Changeset 3544


Ignore:
Timestamp:
Jul 7, 2009, 10:27:37 PM (12 years ago)
Author:
vdigital
Message:

Change: getid3 upgraded to -> 1.7.9

Location:
extensions/charlies_content/getid3/getid3
Files:
20 added
10 deleted
47 edited

Legend:

Unmodified
Added
Removed
  • extensions/charlies_content/getid3/getid3/extension.cache.dbm.php

    r3318 r3544  
    11<?php
    2 // +----------------------------------------------------------------------+
    3 // | PHP version 5                                                        |
    4 // +----------------------------------------------------------------------+
    5 // | Copyright (c) 2002-2006 James Heinrich, Allan Hansen                 |
    6 // +----------------------------------------------------------------------+
    7 // | This source file is subject to version 2 of the GPL license,         |
    8 // | that is bundled with this package in the file license.txt and is     |
    9 // | available through the world-wide-web at the following url:           |
    10 // | http://www.gnu.org/copyleft/gpl.html                                 |
    11 // +----------------------------------------------------------------------+
    12 // | getID3() - http://getid3.sourceforge.net or http://www.getid3.org    |
    13 // +----------------------------------------------------------------------+
    14 // | Authors: James Heinrich <infoØgetid3*org>                            |
    15 // |          Allan Hansen <ahØartemis*dk>                                |
    16 // +----------------------------------------------------------------------+
    17 // | extension.cache.mysql.php                                            |
    18 // | MySQL Cache Extension.                                               |
    19 // | dependencies: getid3.                                                |
    20 // +----------------------------------------------------------------------+
    21 //
    22 // $Id$
     2/////////////////////////////////////////////////////////////////
     3/// getID3() by James Heinrich <info@getid3.org>               //
     4//  available at http://getid3.sourceforge.net                 //
     5//            or http://www.getid3.org                         //
     6/////////////////////////////////////////////////////////////////
     7//                                                             //
     8// extension.cache.dbm.php - part of getID3()                  //
     9// Please see readme.txt for more information                  //
     10//                                                            ///
     11/////////////////////////////////////////////////////////////////
     12//                                                             //
     13// This extension written by Allan Hansen <ahØartemis*dk>      //
     14//                                                            ///
     15/////////////////////////////////////////////////////////////////
    2316
    2417
     
    2720* way as the getID3 class, but return cached information very fast
    2821*
    29 * Example:  (see also demo.cache.dbm.php in /demo/)
     22* Example:
    3023*
    3124*    Normal getID3 usage (example):
    3225*
    3326*       require_once 'getid3/getid3.php';
    34 *       $getid3 = new getid3;
    35 *       $getid3->encoding = 'UTF-8';
    36 *       try {
    37 *           $info1 = $getid3->Analyse('file1.flac');
    38 *           $info2 = $getid3->Analyse('file2.wv');
    39 *           ....
     27*       $getID3 = new getID3;
     28*       $getID3->encoding = 'UTF-8';
     29*       $info1 = $getID3->analyze('file1.flac');
     30*       $info2 = $getID3->analyze('file2.wv');
    4031*
    4132*    getID3_cached usage:
    4233*
    4334*       require_once 'getid3/getid3.php';
    44 *       require_once 'getid3/getid3/extension.cache.mysql.php';
    45 *       $getid3 = new getid3_cached_mysql('localhost', 'database', 'username', 'password');
    46 *       $getid3->encoding = 'UTF-8';
    47 *       try {
    48 *           $info1 = $getid3->analyse('file1.flac');
    49 *           $info2 = $getid3->analyse('file2.wv');
    50 *           ...
     35*       require_once 'getid3/getid3/extension.cache.dbm.php';
     36*       $getID3 = new getID3_cached('db3', '/tmp/getid3_cache.dbm',
     37*                                          '/tmp/getid3_cache.lock');
     38*       $getID3->encoding = 'UTF-8';
     39*       $info1 = $getID3->analyze('file1.flac');
     40*       $info2 = $getID3->analyze('file2.wv');
    5141*
    5242*
     
    8070
    8171
    82 class getid3_cached_dbm extends getid3
     72class getID3_cached_dbm extends getID3
    8373{
    8474
    85     public function __construct($cache_type, $dbm_filename, $lock_filename) {
    86 
    87         // Check for dba extension
    88         if (!extension_loaded('dba')) {
    89             throw new getid3_exception('PHP is not compiled with dba support, required to use DBM style cache.');
    90         }
    91 
    92         if (!in_array($cache_type, dba_handlers())) {
    93             throw new getid3_exception('PHP is not compiled --with '.$cache_type.' support, required to use DBM style cache.');
    94         }
    95 
    96         // Create lock file if needed
    97         if (!file_exists($lock_filename)) {
    98             if (!touch($lock_filename)) {
    99                 die('failed to create lock file: ' . $lock_filename);
    100             }
    101         }
    102 
    103         // Open lock file for writing
    104         if (!is_writeable($lock_filename)) {
    105             die('lock file: ' . $lock_filename . ' is not writable');
    106         }
    107         $this->lock = fopen($lock_filename, 'w');
    108 
    109         // Acquire exclusive write lock to lock file
    110         flock($this->lock, LOCK_EX);
    111 
    112         // Create dbm-file if needed
    113         if (!file_exists($dbm_filename)) {
    114             if (!touch($dbm_filename)) {
    115                 die('failed to create dbm file: ' . $dbm_filename);
    116             }
    117         }
    118 
    119         // Try to open dbm file for writing
    120         $this->dba = @dba_open($dbm_filename, 'w', $cache_type);
    121         if (!$this->dba) {
    122 
    123             // Failed - create new dbm file
    124             $this->dba = dba_open($dbm_filename, 'n', $cache_type);
    125 
    126             if (!$this->dba) {
    127                 die('failed to create dbm file: ' . $dbm_filename);
    128             }
    129 
    130             // Insert getID3 version number
    131             dba_insert(getid3::VERSION, getid3::VERSION, $this->dba);
    132         }
    133 
    134         // Init misc values
    135         $this->cache_type   = $cache_type;
    136         $this->dbm_filename = $dbm_filename;
    137 
    138         // Register destructor
    139         register_shutdown_function(array($this, '__destruct'));
    140 
    141         // Check version number and clear cache if changed
    142         if (dba_fetch(getid3::VERSION, $this->dba) != getid3::VERSION) {
    143             $this->clear_cache();
    144         }
    145 
    146         parent::__construct();
    147     }
    148 
    149 
    150 
    151     public function __destruct() {
    152 
    153         // Close dbm file
    154         @dba_close($this->dba);
    155 
    156         // Release exclusive lock
    157         @flock($this->lock, LOCK_UN);
    158 
    159         // Close lock file
    160         @fclose($this->lock);
    161     }
    162 
    163 
    164 
    165     public function clear_cache() {
    166 
    167         // Close dbm file
    168         dba_close($this->dba);
    169 
    170         // Create new dbm file
    171         $this->dba = dba_open($this->dbm_filename, 'n', $this->cache_type);
    172 
    173         if (!$this->dba) {
    174             die('failed to clear cache/recreate dbm file: ' . $this->dbm_filename);
    175         }
    176 
    177         // Insert getID3 version number
    178         dba_insert(getid3::VERSION, getid3::VERSION, $this->dba);
    179 
    180         // Reregister shutdown function
    181         register_shutdown_function(array($this, '__destruct'));
    182     }
    183 
    184 
    185 
    186     // public: analyze file
    187     public function Analyze($filename) {
    188 
    189         if (file_exists($filename)) {
    190 
    191             // Calc key     filename::mod_time::size    - should be unique
    192             $key = $filename . '::' . filemtime($filename) . '::' . filesize($filename);
    193 
    194             // Loopup key
    195             $result = dba_fetch($key, $this->dba);
    196 
    197             // Hit
    198             if ($result !== false) {
    199                 return unserialize($result);
    200             }
    201         }
    202 
    203         // Miss
    204         $result = parent::Analyze($filename);
    205 
    206         // Save result
    207         if (file_exists($filename)) {
    208             dba_insert($key, serialize($result), $this->dba);
    209         }
    210 
    211         return $result;
    212     }
     75        // public: constructor - see top of this file for cache type and cache_options
     76        function getID3_cached_dbm($cache_type, $dbm_filename, $lock_filename) {
     77
     78                // Check for dba extension
     79                if (!extension_loaded('dba')) {
     80                        die('PHP is not compiled with dba support, required to use DBM style cache.');
     81                }
     82
     83                // 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                        }
     97                }
     98
     99                // Create lock file if needed
     100                if (!file_exists($lock_filename)) {
     101                        if (!touch($lock_filename)) {
     102                                die('failed to create lock file: ' . $lock_filename);
     103                        }
     104                }
     105
     106                // Open lock file for writing
     107                if (!is_writeable($lock_filename)) {
     108                        die('lock file: ' . $lock_filename . ' is not writable');
     109                }
     110                $this->lock = fopen($lock_filename, 'w');
     111
     112                // Acquire exclusive write lock to lock file
     113                flock($this->lock, LOCK_EX);
     114
     115                // Create dbm-file if needed
     116                if (!file_exists($dbm_filename)) {
     117                        if (!touch($dbm_filename)) {
     118                                die('failed to create dbm file: ' . $dbm_filename);
     119                        }
     120                }
     121
     122                // Try to open dbm file for writing
     123                $this->dba = @dba_open($dbm_filename, 'w', $cache_type);
     124                if (!$this->dba) {
     125
     126                        // Failed - create new dbm file
     127                        $this->dba = dba_open($dbm_filename, 'n', $cache_type);
     128
     129                        if (!$this->dba) {
     130                                die('failed to create dbm file: ' . $dbm_filename);
     131                        }
     132
     133                        // Insert getID3 version number
     134                        dba_insert(GETID3_VERSION, GETID3_VERSION, $this->dba);
     135                }
     136
     137                // Init misc values
     138                $this->cache_type   = $cache_type;
     139                $this->dbm_filename = $dbm_filename;
     140
     141                // Register destructor
     142                register_shutdown_function(array($this, '__destruct'));
     143
     144                // Check version number and clear cache if changed
     145                if (dba_fetch(GETID3_VERSION, $this->dba) != GETID3_VERSION) {
     146                        $this->clear_cache();
     147                }
     148
     149                parent::getID3();
     150        }
     151
     152
     153
     154        // public: destuctor
     155        function __destruct() {
     156
     157                // Close dbm file
     158                @dba_close($this->dba);
     159
     160                // Release exclusive lock
     161                @flock($this->lock, LOCK_UN);
     162
     163                // Close lock file
     164                @fclose($this->lock);
     165        }
     166
     167
     168
     169        // public: clear cache
     170        function clear_cache() {
     171
     172                // Close dbm file
     173                dba_close($this->dba);
     174
     175                // Create new dbm file
     176                $this->dba = dba_open($this->dbm_filename, 'n', $this->cache_type);
     177
     178                if (!$this->dba) {
     179                        die('failed to clear cache/recreate dbm file: ' . $this->dbm_filename);
     180                }
     181
     182                // Insert getID3 version number
     183                dba_insert(GETID3_VERSION, GETID3_VERSION, $this->dba);
     184
     185                // Reregister shutdown function
     186                register_shutdown_function(array($this, '__destruct'));
     187        }
     188
     189
     190
     191        // public: analyze file
     192        function analyze($filename) {
     193
     194                if (file_exists($filename)) {
     195
     196                        // Calc key     filename::mod_time::size    - should be unique
     197                        $key = $filename . '::' . filemtime($filename) . '::' . filesize($filename);
     198
     199                        // Loopup key
     200                        $result = dba_fetch($key, $this->dba);
     201
     202                        // Hit
     203                        if ($result !== false) {
     204                                return unserialize($result);
     205                        }
     206                }
     207
     208                // Miss
     209                $result = parent::analyze($filename);
     210
     211                // Save result
     212                if (file_exists($filename)) {
     213                        dba_insert($key, serialize($result), $this->dba);
     214                }
     215
     216                return $result;
     217        }
    213218
    214219}
  • extensions/charlies_content/getid3/getid3/extension.cache.mysql.php

    r3318 r3544  
    11<?php
    2 // +----------------------------------------------------------------------+
    3 // | PHP version 5                                                        |
    4 // +----------------------------------------------------------------------+
    5 // | Copyright (c) 2002-2006 James Heinrich, Allan Hansen                 |
    6 // +----------------------------------------------------------------------+
    7 // | This source file is subject to version 2 of the GPL license,         |
    8 // | that is bundled with this package in the file license.txt and is     |
    9 // | available through the world-wide-web at the following url:           |
    10 // | http://www.gnu.org/copyleft/gpl.html                                 |
    11 // +----------------------------------------------------------------------+
    12 // | getID3() - http://getid3.sourceforge.net or http://www.getid3.org    |
    13 // +----------------------------------------------------------------------+
    14 // | Authors: James Heinrich <infoØgetid3*org>                            |
    15 // |          Allan Hansen <ahØartemis*dk>                                |
    16 // +----------------------------------------------------------------------+
    17 // | extension.cache.mysql.php                                            |
    18 // | MySQL Cache Extension.                                               |
    19 // | dependencies: getid3.                                                |
    20 // +----------------------------------------------------------------------+
    21 //
    22 // $Id$
     2/////////////////////////////////////////////////////////////////
     3/// getID3() by James Heinrich <info@getid3.org>               //
     4//  available at http://getid3.sourceforge.net                 //
     5//            or http://www.getid3.org                         //
     6/////////////////////////////////////////////////////////////////
     7//                                                             //
     8// extension.cache.mysql.php - part of getID3()                //
     9// Please see readme.txt for more information                  //
     10//                                                            ///
     11/////////////////////////////////////////////////////////////////
     12//                                                             //
     13// This extension written by Allan Hansen <ahØartemis*dk>      //
     14//                                                            ///
     15/////////////////////////////////////////////////////////////////
    2316
    2417
     
    3225*
    3326*       require_once 'getid3/getid3.php';
    34 *       $getid3 = new getid3;
    35 *       $getid3->encoding = 'UTF-8';
    36 *       try {
    37 *           $info1 = $getid3->Analyse('file1.flac');
    38 *           $info2 = $getid3->Analyse('file2.wv');
    39 *           ....
     27*       $getID3 = new getID3;
     28*       $getID3->encoding = 'UTF-8';
     29*       $info1 = $getID3->analyze('file1.flac');
     30*       $info2 = $getID3->analyze('file2.wv');
    4031*
    4132*    getID3_cached usage:
     
    4334*       require_once 'getid3/getid3.php';
    4435*       require_once 'getid3/getid3/extension.cache.mysql.php';
    45 *       $getid3 = new getid3_cached_mysql('localhost', 'database', 'username', 'password');
    46 *       $getid3->encoding = 'UTF-8';
    47 *       try {
    48 *           $info1 = $getid3->analyse('file1.flac');
    49 *           $info2 = $getid3->analyse('file2.wv');
    50 *           ...
     36*       $getID3 = new getID3_cached_mysql('localhost', 'database',
     37*                                         'username', 'password');
     38*       $getID3->encoding = 'UTF-8';
     39*       $info1 = $getID3->analyze('file1.flac');
     40*       $info2 = $getID3->analyze('file2.wv');
    5141*
    5242*
     
    8070
    8171
    82 class getid3_cached_mysql extends getID3
     72class getID3_cached_mysql extends getID3
    8373{
    8474
    85     private $cursor;
    86     private $connection;
     75        // private vars
     76        var $cursor;
     77        var $connection;
    8778
    8879
    89     public function __construct($host, $database, $username, $password) {
     80        // public: constructor - see top of this file for cache type and cache_options
     81        function getID3_cached_mysql($host, $database, $username, $password) {
    9082
    91         // Check for mysql support
    92         if (!function_exists('mysql_pconnect')) {
    93             throw new getid3_exception('PHP not compiled with mysql support.');
    94         }
     83                // Check for mysql support
     84                if (!function_exists('mysql_pconnect')) {
     85                        die('PHP not compiled with mysql support.');
     86                }
    9587
    96         // Connect to database
    97         $this->connection = @mysql_pconnect($host, $username, $password);
    98         if (!$this->connection) {
    99             throw new getid3_exception('mysql_pconnect() failed - check permissions and spelling.');
    100         }
     88                // Connect to database
     89                $this->connection = mysql_pconnect($host, $username, $password);
     90                if (!$this->connection) {
     91                        die('mysql_pconnect() failed - check permissions and spelling.');
     92                }
    10193
    102         // Select database
    103         if (!@mysql_select_db($database, $this->connection)) {
    104             throw new getid3_exception('Cannot use database '.$database);
    105         }
     94                // Select database
     95                if (!mysql_select_db($database, $this->connection)) {
     96                        die('Cannot use database '.$database);
     97                }
    10698
    107         // Create cache table if not exists
    108         $this->create_table();
     99                // Create cache table if not exists
     100                $this->create_table();
    109101
    110         // Check version number and clear cache if changed
    111         $this->cursor = mysql_query("SELECT `value` FROM `getid3_cache` WHERE (`filename` = '".getid3::VERSION."') AND (`filesize` = '-1') AND (`filetime` = '-1') AND (`analyzetime` = '-1')", $this->connection);
    112         list($version) = @mysql_fetch_array($this->cursor);
    113         if ($version != getid3::VERSION) {
    114             $this->clear_cache();
    115         }
     102                // 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) {
     106                        $this->clear_cache();
     107                }
    116108
    117         parent::__construct();
    118     }
     109                parent::getID3();
     110        }
    119111
    120112
    121113
    122     public function clear_cache() {
     114        // public: clear cache
     115        function clear_cache() {
    123116
    124         $this->cursor = mysql_query("DELETE FROM `getid3_cache`", $this->connection);
    125         $this->cursor = mysql_query("INSERT INTO `getid3_cache` VALUES ('".getid3::VERSION."', -1, -1, -1, '".getid3::VERSION."')", $this->connection);
    126     }
     117                $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);
     119        }
    127120
    128121
    129122
    130     public function Analyze($filename) {
     123        // public: analyze file
     124        function analyze($filename) {
    131125
    132         if (file_exists($filename)) {
     126                if (file_exists($filename)) {
    133127
    134             // Short-hands
    135             $filetime = filemtime($filename);
    136             $filesize = filesize($filename);
    137             $filenam2 = mysql_escape_string($filename);
     128                        // Short-hands
     129                        $filetime = filemtime($filename);
     130                        $filesize = filesize($filename);
     131                        $filenam2 = mysql_escape_string($filename);
    138132
    139             // Loopup file
    140             $this->cursor = mysql_query("SELECT `value` FROM `getid3_cache` WHERE (`filename`='".$filenam2."') AND (`filesize`='".$filesize."') AND (`filetime`='".$filetime."')", $this->connection);
    141             list($result) = @mysql_fetch_array($this->cursor);
     133                        // 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);
    142136
    143             // Hit
    144             if ($result) {
    145                 return unserialize($result);
    146             }
    147         }
     137                        // Hit
     138                        if ($result) {
     139                                return unserialize($result);
     140                        }
     141                }
    148142
    149         // Miss
    150         $result = parent::Analyze($filename);
     143                // Miss
     144                $result = parent::analyze($filename);
    151145
    152         // Save result
    153         if (file_exists($filename)) {
    154             $res2 = mysql_escape_string(serialize($result));
    155             $this->cursor = mysql_query("INSERT INTO `getid3_cache` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES ('".$filenam2."', '".$filesize."', '".$filetime."', '".time()."', '".$res2."')", $this->connection);
    156         }
    157         return $result;
    158     }
     146                // Save result
     147                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);
     150                }
     151                return $result;
     152        }
    159153
    160154
    161155
    162     // (re)create sql table
    163     private function create_table($drop = false) {
     156        // private: (re)create sql table
     157        function create_table($drop = false) {
    164158
    165         $this->cursor = mysql_query("CREATE TABLE IF NOT EXISTS `getid3_cache` (
    166             `filename` VARCHAR(255) NOT NULL DEFAULT '',
    167             `filesize` INT(11) NOT NULL DEFAULT '0',
    168             `filetime` INT(11) NOT NULL DEFAULT '0',
    169             `analyzetime` INT(11) NOT NULL DEFAULT '0',
    170             `value` TEXT NOT NULL,
    171             PRIMARY KEY (`filename`,`filesize`,`filetime`)) TYPE=MyISAM", $this->connection);
    172         echo mysql_error($this->connection);
    173     }
     159                $this->cursor = mysql_query("CREATE TABLE IF NOT EXISTS `getid3_cache` (
     160                        `filename` VARCHAR(255) NOT NULL DEFAULT '',
     161                        `filesize` INT(11) NOT NULL DEFAULT '0',
     162                        `filetime` INT(11) NOT NULL DEFAULT '0',
     163                        `analyzetime` INT(11) NOT NULL DEFAULT '0',
     164                        `value` TEXT NOT NULL,
     165                        PRIMARY KEY (`filename`,`filesize`,`filetime`)) TYPE=MyISAM", $this->connection);
     166                echo mysql_error($this->connection);
     167        }
    174168}
    175169
  • extensions/charlies_content/getid3/getid3/getid3.php

    r3318 r3544  
    11<?php
    2 // +----------------------------------------------------------------------+
    3 // | PHP version 5                                                        |
    4 // +----------------------------------------------------------------------+
    5 // | Copyright (c) 2002-2006 James Heinrich, Allan Hansen                 |
    6 // +----------------------------------------------------------------------+
    7 // | This source file is subject to version 2 of the GPL license,         |
    8 // | that is bundled with this package in the file license.txt and is     |
    9 // | available through the world-wide-web at the following url:           |
    10 // | http://www.gnu.org/copyleft/gpl.html                                 |
    11 // +----------------------------------------------------------------------+
    12 // | getID3() - http://getid3.sourceforge.net or http://www.getid3.org    |
    13 // +----------------------------------------------------------------------+
    14 // | Authors: James Heinrich <infoØgetid3*org>                            |
    15 // |          Allan Hansen <ahØartemis*dk>                                |
    16 // +----------------------------------------------------------------------+
    17 // | getid3.php                                                           |
    18 // | Main getID3() file.                                                  |
    19 // | dependencies: modules.                                               |
    20 // +----------------------------------------------------------------------+
    21 //
    22 // $Id$
    23 
    24 
    25 class getid3
     2/////////////////////////////////////////////////////////////////
     3/// getID3() by James Heinrich <info@getid3.org>               //
     4//  available at http://getid3.sourceforge.net                 //
     5//            or http://www.getid3.org                         //
     6/////////////////////////////////////////////////////////////////
     7//                                                             //
     8// Please see readme.txt for more information                  //
     9//                                                            ///
     10/////////////////////////////////////////////////////////////////
     11
     12// Defines
     13define('GETID3_VERSION', '1.7.9-20090308');
     14define('GETID3_FREAD_BUFFER_SIZE', 16384); // read buffer size in bytes
     15
     16
     17
     18class getID3
    2619{
    27     //// Settings Section - do NOT modify this file - change setting after newing getid3!
    28 
    29     // Encoding
    30     public $encoding                 = 'ISO-8859-1';      // CASE SENSITIVE! - i.e. (must be supported by iconv() - see http://www.gnu.org/software/libiconv/).  Examples:  ISO-8859-1  UTF-8  UTF-16  UTF-16BE.
    31     public $encoding_id3v1           = 'ISO-8859-1';      // Override SPECIFICATION encoding for broken ID3v1 tags caused by bad tag programs. Examples: 'EUC-CN' for "Chinese MP3s" and 'CP1251' for "Cyrillic".
    32     public $encoding_id3v2           = 'ISO-8859-1';      // Override ISO-8859-1 encoding for broken ID3v2 tags caused by BRAINDEAD tag programs that writes system codepage as 'ISO-8859-1' instead of UTF-8.
    33 
    34     // Tags - disable for speed
    35     public $option_tag_id3v1         = true;              // Read and process ID3v1 tags.
    36     public $option_tag_id3v2         = true;              // Read and process ID3v2 tags.
    37     public $option_tag_lyrics3       = true;              // Read and process Lyrics3 tags.
    38     public $option_tag_apetag        = true;              // Read and process APE tags.
    39 
    40     // Misc calucations - disable for speed
    41     public $option_analyze           = true;              // Analyze file - disable if you only need to detect file format.
    42     public $option_accurate_results  = true;              // Disable to greatly speed up parsing of some file formats at the cost of accuracy.
    43     public $option_tags_process      = true;              // Copy tags to root key 'tags' and 'comments' and encode to $this->encoding.
    44     public $option_tags_images       = false;             // Scan tags for binary image data - ID3v2 and vorbiscomments only.
    45     public $option_extra_info        = true;              // Calculate/return additional info such as bitrate, channelmode etc.
    46     public $option_max_2gb_check     = false;             // Check whether file is larger than 2 Gb and thus not supported by PHP.
    47 
    48     // Misc data hashes - slow - require hash module
    49     public $option_md5_data          = false;             // Get MD5 sum of data part - slow.
    50     public $option_md5_data_source   = false;             // Use MD5 of source file if available - only FLAC, MAC, OptimFROG and Wavpack4.
    51     public $option_sha1_data         = false;             // Get SHA1 sum of data part - slow.
    52 
    53     // Public variables
    54     public $filename;                                     // Filename of file being analysed.
    55     public $fp;                                           // Filepointer to file being analysed.
    56     public $info;                                         // Result array.
    57 
    58     // Protected variables
    59     protected $include_path;                              // getid3 include path.
    60     protected $warnings = array ();
    61     protected $iconv_present;
    62 
    63     // Class constants
    64     const VERSION           = '2.0.0b4';
    65     const FREAD_BUFFER_SIZE = 16384;                      // Read buffer size in bytes.
    66     const ICONV_TEST_STRING = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„
    67 †‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ';
    68 
    69 
    70 
    71     // Constructor - check PHP enviroment and load library.
    72     public function __construct() {
    73 
    74         // Static varibles - no need to recalc every time we new getid3.
    75         static $include_path;
    76         static $iconv_present;
    77 
    78 
    79         static $initialized;
    80         if ($initialized) {
    81 
    82             // Import static variables
    83             $this->include_path  = $include_path;
    84             $this->iconv_present = $iconv_present;
    85 
    86             // Run init checks only on first instance.
    87             return;
    88         }
    89 
    90         // Get include_path
    91         $this->include_path = $include_path = dirname(__FILE__) . '/';
    92 
    93         // Check for presence of iconv() and make sure it works (simpel test only).
    94         if (function_exists('iconv') && @iconv('UTF-16LE', 'ISO-8859-1', @iconv('ISO-8859-1', 'UTF-16LE', getid3::ICONV_TEST_STRING)) == getid3::ICONV_TEST_STRING) {
    95             $this->iconv_present = $iconv_present = true;
    96         }
    97 
    98         // iconv() not present - load replacement module.
    99         else {
    100             $this->include_module('lib.iconv_replacement');
    101             $this->iconv_present = $iconv_present = false;
    102         }
    103 
    104 
    105         // Require magic_quotes_runtime off
    106         if (get_magic_quotes_runtime()) {
    107             throw new getid3_exception('magic_quotes_runtime must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_runtime(0) and set_magic_quotes_runtime(1).');
    108         }
    109 
    110 
    111         // Check memory limit.
    112         $memory_limit = ini_get('memory_limit');
    113         if (eregi('([0-9]+)M', $memory_limit, $matches)) {
    114             // could be stored as "16M" rather than 16777216 for example
    115             $memory_limit = $matches[1] * 1048576;
    116         }
    117         if ($memory_limit <= 0) {
    118             // Should not happen.
    119         } elseif ($memory_limit <= 4194304) {
    120             $this->warning('[SERIOUS] PHP has less than 4 Mb available memory and will very likely run out. Increase memory_limit in php.ini.');
    121         } elseif ($memory_limit <= 12582912) {
    122             $this->warning('PHP has less than 12 Mb available memory and might run out if all modules are loaded. Increase memory_limit in php.ini if needed.');
    123         }
    124 
    125 
    126         // Check safe_mode off
    127         if ((bool)ini_get('safe_mode')) {
    128             $this->warning('Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbis/flac tag writing disabled.');
    129         }
    130 
    131         $initialized = true;
    132     }
    133 
    134 
    135 
    136     // Analyze file by name
    137     public function Analyze($filename) {
    138 
    139         // Init and save values
    140         $this->filename = $filename;
    141         $this->warnings = array ();
    142 
    143         // Init result array and set parameters
    144         $this->info = array ();
    145         $this->info['GETID3_VERSION'] = getid3::VERSION;
    146 
    147         // Remote files not supported
    148         if (preg_match('/^(ht|f)tp:\/\//', $filename)) {
    149             throw new getid3_exception('Remote files are not supported - please copy the file locally first.');
    150         }
    151 
    152         // Open local file
    153         if (!$this->fp = @fopen($filename, 'rb')) {
    154             throw new getid3_exception('Could not open file "'.$filename.'"');
    155         }
    156 
    157         // Set filesize related parameters
    158         $this->info['filesize']     = filesize($filename);
    159         $this->info['avdataoffset'] = 0;
    160         $this->info['avdataend']    = $this->info['filesize'];
    161 
    162         // Option_max_2gb_check
    163         if ($this->option_max_2gb_check) {
    164             // PHP doesn't support integers larger than 31-bit (~2GB)
    165             // filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize
    166             // ftell() returns 0 if seeking to the end is beyond the range of unsigned integer
    167             fseek($this->fp, 0, SEEK_END);
    168             if ((($this->info['filesize'] != 0) && (ftell($this->fp) == 0)) ||
    169                 ($this->info['filesize'] < 0) ||
    170                 (ftell($this->fp) < 0)) {
    171                     unset($this->info['filesize']);
    172                     fclose($this->fp);
    173                     throw new getid3_exception('File is most likely larger than 2GB and is not supported by PHP.');
    174             }
    175         }
    176 
    177 
    178         // ID3v2 detection (NOT parsing) done to make fileformat easier.
    179         if (!$this->option_tag_id3v2) {
    180 
    181             fseek($this->fp, 0, SEEK_SET);
    182             $header = fread($this->fp, 10);
    183             if (substr($header, 0, 3) == 'ID3'  &&  strlen($header) == 10) {
    184                 $this->info['id3v2']['header']        = true;
    185                 $this->info['id3v2']['majorversion']  = ord($header{3});
    186                 $this->info['id3v2']['minorversion']  = ord($header{4});
    187                 $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
    188             }
    189         }
    190 
    191 
    192         // Handle tags
    193         foreach (array ("id3v2", "id3v1", "apetag", "lyrics3") as $tag_name) {
    194 
    195             $option_tag = 'option_tag_' . $tag_name;
    196             if ($this->$option_tag) {
    197                 $this->include_module('tag.'.$tag_name);
    198                 try {
    199                     $tag_class = 'getid3_' . $tag_name;
    200                     $tag = new $tag_class($this);
    201                     $tag->Analyze();
    202                 }
    203                 catch (getid3_exception $e) {
    204                     throw $e;
    205                 }
    206             }
    207         }
    208 
    209 
    210 
    211         //// Determine file format by magic bytes in file header.
    212 
    213         // Read 32 kb file data
    214         fseek($this->fp, $this->info['avdataoffset'], SEEK_SET);
    215         $filedata = fread($this->fp, 32774);
    216 
    217         // Get huge FileFormatArray
    218         $file_format_array = getid3::GetFileFormatArray();
    219 
    220         // Identify file format - loop through $format_info and detect with reg expr
    221         foreach ($file_format_array as $name => $info) {
    222 
    223             if (preg_match('/'.$info['pattern'].'/s', $filedata)) {                         // The /s switch on preg_match() forces preg_match() NOT to treat newline (0x0A) characters as special chars but do a binary match
    224 
    225                 // Format detected but not supported
    226                 if (!@$info['module'] || !@$info['group']) {
    227                     fclose($this->fp);
    228                     $this->info['fileformat'] = $name;
    229                     $this->info['mime_type']  = $info['mime_type'];
    230                     $this->warning('Format only detected. Parsing not available yet.');
    231                     $this->info['warning'] = $this->warnings;
    232                     return $this->info;
    233                 }
    234 
    235                 $determined_format = $info;  // copy $info deleted by foreach()
    236                 continue;
    237             }
    238         }
    239 
    240         // Unable to determine file format
    241         if (!@$determined_format) {
    242 
    243             // Too many mp3 encoders on the market put gabage in front of mpeg files
    244             // use assume format on these if format detection failed
    245             if (preg_match('/\.mp[123a]$/i', $filename)) {
    246                 $determined_format = $file_format_array['mp3'];
    247             }
    248 
    249             else {
    250                 fclose($this->fp);
    251                 throw new getid3_exception('Unable to determine file format');
    252             }
    253         }
    254 
    255         // Free memory
    256         unset($file_format_array);
    257 
    258         // Check for illegal ID3 tags
    259         if (@$determined_format['fail_id3'] && (@$this->info['id3v1'] || @$this->info['id3v2'])) {
    260             if ($determined_format['fail_id3'] === 'ERROR') {
    261                 fclose($this->fp);
    262                 throw new getid3_exception('ID3 tags not allowed on this file type.');
    263             }
    264             elseif ($determined_format['fail_id3'] === 'WARNING') {
    265                 @$this->info['id3v1'] and $this->warning('ID3v1 tags not allowed on this file type.');
    266                 @$this->info['id3v2'] and $this->warning('ID3v2 tags not allowed on this file type.');
    267             }
    268         }
    269 
    270         // Check for illegal APE tags
    271         if (@$determined_format['fail_ape'] && @$this->info['tags']['ape']) {
    272             if ($determined_format['fail_ape'] === 'ERROR') {
    273                 fclose($this->fp);
    274                 throw new getid3_exception('APE tags not allowed on this file type.');
    275             } elseif ($determined_format['fail_ape'] === 'WARNING') {
    276                 $this->warning('APE tags not allowed on this file type.');
    277             }
    278         }
    279 
    280 
    281         // Set mime type
    282         $this->info['mime_type'] = $determined_format['mime_type'];
    283 
    284         // Calc module file name
    285         $determined_format['include'] = 'module.'.$determined_format['group'].'.'.$determined_format['module'].'.php';
    286 
    287         // Supported format signature pattern detected, but module deleted.
    288         if (!file_exists($this->include_path.$determined_format['include'])) {
    289             fclose($this->fp);
    290             throw new getid3_exception('Format not supported, module, '.$determined_format['include'].', was removed.');
    291         }
    292 
    293         // Include module
    294         $this->include_module($determined_format['group'].'.'.$determined_format['module']);
    295 
    296         // Instantiate module class and analyze
    297         $class_name = 'getid3_'.$determined_format['module'];
    298         if (!class_exists($class_name)) {
    299             throw new getid3_exception('Format not supported, module, '.$determined_format['include'].', is corrupt.');
    300         }
    301         $class = new $class_name($this);
    302 
    303         try {
    304              $this->option_analyze and $class->Analyze();
    305             }
    306         catch (getid3_exception $e) {
    307             throw $e;
    308         }
    309         catch (Exception $e) {
    310             throw new getid3_exception('Corrupt file.');
    311         }
    312 
    313         // Close file
    314         fclose($this->fp);
    315 
    316         // Optional - Process all tags - copy to 'tags' and convert charsets
    317         if ($this->option_tags_process) {
    318             $this->HandleAllTags();
    319         }
    320 
    321 
    322         //// Optional - perform more calculations
    323         if ($this->option_extra_info) {
    324 
    325             // Set channelmode on audio
    326             if (@$this->info['audio']['channels'] == '1') {
    327                 $this->info['audio']['channelmode'] = 'mono';
    328             } elseif (@$this->info['audio']['channels'] == '2') {
    329                 $this->info['audio']['channelmode'] = 'stereo';
    330             }
    331 
    332             // Calculate combined bitrate - audio + video
    333             $combined_bitrate  = 0;
    334             $combined_bitrate += (isset($this->info['audio']['bitrate']) ? $this->info['audio']['bitrate'] : 0);
    335             $combined_bitrate += (isset($this->info['video']['bitrate']) ? $this->info['video']['bitrate'] : 0);
    336             if (($combined_bitrate > 0) && empty($this->info['bitrate'])) {
    337                 $this->info['bitrate'] = $combined_bitrate;
    338             }
    339             if (!isset($this->info['playtime_seconds']) && !empty($this->info['bitrate'])) {
    340                 $this->info['playtime_seconds'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['bitrate'];
    341             }
    342 
    343             // Set playtime string
    344             if (!empty($this->info['playtime_seconds']) && empty($this->info['playtime_string'])) {
    345                 $this->info['playtime_string'] =  floor(round($this->info['playtime_seconds']) / 60) . ':' . str_pad(floor(round($this->info['playtime_seconds']) % 60), 2, 0, STR_PAD_LEFT);;
    346             }
    347 
    348 
    349             // CalculateCompressionRatioVideo() {
    350             if (@$this->info['video'] && @$this->info['video']['resolution_x'] && @$this->info['video']['resolution_y'] && @$this->info['video']['bits_per_sample']) {
    351 
    352                 // From static image formats
    353                 if (in_array($this->info['video']['dataformat'], array ('bmp', 'gif', 'jpeg', 'jpg', 'png', 'tiff'))) {
    354                     $frame_rate         = 1;
    355                     $bitrate_compressed = $this->info['filesize'] * 8;
    356                 }
    357 
    358                 // From video formats
    359                 else {
    360                     $frame_rate         = @$this->info['video']['frame_rate'];
    361                     $bitrate_compressed = @$this->info['video']['bitrate'];
    362                 }
    363 
    364                 if ($frame_rate && $bitrate_compressed) {
    365                     $this->info['video']['compression_ratio'] = $bitrate_compressed / ($this->info['video']['resolution_x'] * $this->info['video']['resolution_y'] * $this->info['video']['bits_per_sample'] * $frame_rate);
    366                 }
    367             }
    368 
    369 
    370             // CalculateCompressionRatioAudio() {
    371             if (@$this->info['audio']['bitrate'] && @$this->info['audio']['channels'] && @$this->info['audio']['sample_rate']) {
    372                 $this->info['audio']['compression_ratio'] = $this->info['audio']['bitrate'] / ($this->info['audio']['channels'] * $this->info['audio']['sample_rate'] * (@$this->info['audio']['bits_per_sample'] ? $this->info['audio']['bits_per_sample'] : 16));
    373             }
    374 
    375             if (@$this->info['audio']['streams']) {
    376                 foreach ($this->info['audio']['streams'] as $stream_number => $stream_data) {
    377                     if (@$stream_data['bitrate'] && @$stream_data['channels'] && @$stream_data['sample_rate']) {
    378                         $this->info['audio']['streams'][$stream_number]['compression_ratio'] = $stream_data['bitrate'] / ($stream_data['channels'] * $stream_data['sample_rate'] * (@$stream_data['bits_per_sample'] ? $stream_data['bits_per_sample'] : 16));
    379                     }
    380                 }
    381             }
    382 
    383 
    384             // CalculateReplayGain() {
    385             if (@$this->info['replay_gain']) {
    386                 if (!@$this->info['replay_gain']['reference_volume']) {
    387                      $this->info['replay_gain']['reference_volume'] = 89;
    388                 }
    389                 if (isset($this->info['replay_gain']['track']['adjustment'])) {
    390                     $this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment'];
    391                 }
    392                 if (isset($this->info['replay_gain']['album']['adjustment'])) {
    393                     $this->info['replay_gain']['album']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['album']['adjustment'];
    394                 }
    395 
    396                 if (isset($this->info['replay_gain']['track']['peak'])) {
    397                     $this->info['replay_gain']['track']['max_noclip_gain'] = 0 - 20 * log10($this->info['replay_gain']['track']['peak']);
    398                 }
    399                 if (isset($this->info['replay_gain']['album']['peak'])) {
    400                     $this->info['replay_gain']['album']['max_noclip_gain'] = 0 - 20 * log10($this->info['replay_gain']['album']['peak']);
    401                 }
    402             }
    403 
    404 
    405             // ProcessAudioStreams() {
    406             if (@!$this->info['audio']['streams'] && (@$this->info['audio']['bitrate'] || @$this->info['audio']['channels'] || @$this->info['audio']['sample_rate'])) {
    407                   foreach ($this->info['audio'] as $key => $value) {
    408                     if ($key != 'streams') {
    409                         $this->info['audio']['streams'][0][$key] = $value;
    410                     }
    411                 }
    412             }
    413         }
    414 
    415 
    416         // Get the md5/sha1sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags.
    417         if ($this->option_md5_data || $this->option_sha1_data) {
    418 
    419             // Load data-hash library if needed
    420             $this->include_module('lib.data_hash');
    421 
    422             if ($this->option_sha1_data) {
    423                 new getid3_lib_data_hash($this, 'sha1');
    424             }
    425 
    426             if ($this->option_md5_data) {
    427 
    428                 // no md5_data_source or option disabled -- md5_data_source supported by FLAC, MAC, OptimFROG, Wavpack4
    429                 if (!$this->option_md5_data_source || !@$this->info['md5_data_source']) {
    430                     new getid3_lib_data_hash($this, 'md5');
    431                 }
    432 
    433                 // copy md5_data_source to md5_data if option set to true
    434                 elseif ($this->option_md5_data_source && @$this->info['md5_data_source']) {
    435                     $this->info['md5_data'] = $this->info['md5_data_source'];
    436                 }
    437             }
    438         }
    439 
    440         // Set warnings
    441         if ($this->warnings) {
    442             $this->info['warning'] = $this->warnings;
    443         }
    444 
    445         // Return result
    446         return $this->info;
    447     }
    448 
    449 
    450 
    451     // Return array of warnings
    452     public function warnings() {
    453 
    454         return $this->warnings;
    455     }
    456 
    457 
    458 
    459     // Add warning(s) to $this->warnings[]
    460     public function warning($message) {
    461 
    462         if (is_array($message)) {
    463             $this->warnings = array_merge($this->warnings, $message);
    464         }
    465         else {
    466             $this->warnings[] = $message;
    467         }
    468     }
    469 
    470 
    471 
    472     //  Clear all warnings when cloning
    473     public function __clone() {
    474 
    475         $this->warnings = array ();
    476 
    477         // Copy info array, otherwise it will be a reference.
    478         $temp = $this->info;
    479         unset($this->info);
    480         $this->info = $temp;
    481     }
    482 
    483 
    484 
    485     // Convert string between charsets -- iconv() wrapper
    486     public function iconv($in_charset, $out_charset, $string, $drop01 = false) {
    487 
    488         if ($drop01 && ($string === "\x00" || $string === "\x01")) {
    489             return '';
    490         }
    491 
    492 
    493         if (!$this->iconv_present) {
    494             return getid3_iconv_replacement::iconv($in_charset, $out_charset, $string);
    495         }
    496 
    497 
    498         // iconv() present
    499         if ($result = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) {
    500 
    501             if ($out_charset == 'ISO-8859-1') {
    502                 return rtrim($result, "\x00");
    503             }
    504             return $result;
    505         }
    506 
    507         $this->warning('iconv() was unable to convert the string: "' . $string . '" from ' . $in_charset . ' to ' . $out_charset);
    508         return $string;
    509     }
    510 
    511 
    512 
    513     public function include_module($name) {
    514 
    515         if (!file_exists($this->include_path.'module.'.$name.'.php')) {
    516             throw new getid3_exception('Required module.'.$name.'.php is missing.');
    517         }
    518 
    519         include_once($this->include_path.'module.'.$name.'.php');
    520     }
    521 
    522 
    523 
    524     public function include_module_optional($name) {
    525 
    526         if (!file_exists($this->include_path.'module.'.$name.'.php')) {
    527             return;
    528         }
    529 
    530         include_once($this->include_path.'module.'.$name.'.php');
    531         return true;
    532     }
    533 
    534 
    535     // Return array containing information about all supported formats
    536     public static function GetFileFormatArray() {
    537 
    538         static $format_info = array (
    539 
    540                 // Audio formats
    541 
    542                 // AC-3   - audio      - Dolby AC-3 / Dolby Digital
    543                 'ac3'  => array (
    544                             'pattern'   => '^\x0B\x77',
    545                             'group'     => 'audio',
    546                             'module'    => 'ac3',
    547                             'mime_type' => 'audio/ac3',
    548                           ),
    549 
    550                 // AAC  - audio       - Advanced Audio Coding (AAC) - ADIF format
    551                 'adif' => array (
    552                             'pattern'   => '^ADIF',
    553                             'group'     => 'audio',
    554                             'module'    => 'aac_adif',
    555                             'mime_type' => 'application/octet-stream',
    556                             'fail_ape'  => 'WARNING',
    557                           ),
    558 
    559 
    560                 // AAC  - audio       - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3)
    561                 'adts' => array (
    562                             'pattern'   => '^\xFF[\xF0-\xF1\xF8-\xF9]',
    563                             'group'     => 'audio',
    564                             'module'    => 'aac_adts',
    565                             'mime_type' => 'application/octet-stream',
    566                             'fail_ape'  => 'WARNING',
    567                           ),
    568 
    569 
    570                 // AU   - audio       - NeXT/Sun AUdio (AU)
    571                 'au'   => array (
    572                             'pattern'   => '^\.snd',
    573                             'group'     => 'audio',
    574                             'module'    => 'au',
    575                             'mime_type' => 'audio/basic',
    576                           ),
    577 
    578                 // AVR  - audio       - Audio Visual Research
    579                 'avr'  => array (
    580                             'pattern'   => '^2BIT',
    581                             'group'     => 'audio',
    582                             'module'    => 'avr',
    583                             'mime_type' => 'application/octet-stream',
    584                           ),
    585 
    586                 // BONK - audio       - Bonk v0.9+
    587                 'bonk' => array (
    588                             'pattern'   => '^\x00(BONK|INFO|META| ID3)',
    589                             'group'     => 'audio',
    590                             'module'    => 'bonk',
    591                             'mime_type' => 'audio/xmms-bonk',
    592                           ),
    593 
    594                 // DTS  - audio       - Dolby Theatre System
     20        // 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
     27
     28        // 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
     35
     36        // public: Optional tag/comment calucations
     37        var $option_extra_info        = true;  // Calculate additional info such as bitrate, channelmode etc
     38
     39        // 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
     48
     49        // 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();
     59                }
     60
     61                // Check memory
     62                $memory_limit = ini_get('memory_limit');
     63                if (eregi('([0-9]+)M', $memory_limit, $matches)) {
     64                        // could be stored as "16M" rather than 16777216 for example
     65                        $memory_limit = $matches[1] * 1048576;
     66                }
     67                if ($memory_limit <= 0) {
     68                        // 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';
     73                }
     74
     75                // 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);
     85                        } 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                                }
     97                        }
     98                }
     99
     100                // Load support library
     101                if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) {
     102                        $this->startup_error .= 'getid3.lib.php is missing or corrupt';
     103                }
     104
     105
     106                // Needed for Windows only:
     107                // Define locations of helper applications for Shorten, VorbisComment, MetaFLAC
     108                //   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/"
     111                // IMPORTANT: This path must include the trailing slash
     112                if (GETID3_OS_ISWINDOWS && !defined('GETID3_HELPERAPPSDIR')) {
     113
     114                        $helperappsdir = GETID3_INCLUDEPATH.'..'.DIRECTORY_SEPARATOR.'helperapps'; // must not have any space in this path
     115
     116                        if (!is_dir($helperappsdir)) {
     117                                $this->startup_error .= '"'.$helperappsdir.'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist';
     118                        } elseif (strpos(realpath($helperappsdir), ' ') !== false) {
     119                                $DirPieces = explode(DIRECTORY_SEPARATOR, realpath($helperappsdir));
     120                                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';
     124                                                }
     125                                        } elseif ((strpos($value, ' ') !== false) || strlen($value) > 8) {
     126                                                $value = substr($value, 0, 6).'~1';
     127                                        }
     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
     135        }
     136
     137
     138        // public: setOption
     139        function setOption($optArray) {
     140                if (!is_array($optArray) || empty($optArray)) {
     141                        return false;
     142                }
     143                foreach ($optArray as $opt => $val) {
     144                        //if (isset($this, $opt) === false) {
     145                        if (isset($this->$opt) === false) {
     146                                continue;
     147                        }
     148                        $this->$opt = $val;
     149                }
     150                return true;
     151        }
     152
     153
     154        // public: analyze file - replaces GetAllFileInfo() and GetTagOnly()
     155        function analyze($filename) {
     156
     157                if (!empty($this->startup_error)) {
     158                        return $this->error($this->startup_error);
     159                }
     160                if (!empty($this->startup_warning)) {
     161                        $this->warning($this->startup_warning);
     162                }
     163
     164                // init result array and set parameters
     165                $this->info = array();
     166                $this->info['GETID3_VERSION'] = GETID3_VERSION;
     167
     168                // Check encoding/iconv support
     169                if (!function_exists('iconv') && !in_array($this->encoding, array('ISO-8859-1', 'UTF-8', 'UTF-16LE', 'UTF-16BE', 'UTF-16'))) {
     170                        $errormessage = 'iconv() support is needed for encodings other than ISO-8859-1, UTF-8, UTF-16LE, UTF16-BE, UTF-16. ';
     171                        if (GETID3_OS_ISWINDOWS) {
     172                                $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';
     173                        } else {
     174                                $errormessage .= 'PHP is not compiled with iconv() support. Please recompile with the --with-iconv switch';
     175                        }
     176                return $this->error($errormessage);
     177                }
     178
     179                // Disable magic_quotes_runtime, if neccesary
     180                $old_magic_quotes_runtime = get_magic_quotes_runtime(); // store current setting of magic_quotes_runtime
     181                if ($old_magic_quotes_runtime) {
     182                        set_magic_quotes_runtime(0);                        // turn off magic_quotes_runtime
     183                        if (get_magic_quotes_runtime()) {
     184                                return $this->error('Could not disable magic_quotes_runtime - getID3() cannot work properly with this setting enabled');
     185                        }
     186                }
     187
     188                // remote files not supported
     189                if (preg_match('/^(ht|f)tp:\/\//', $filename)) {
     190                        return $this->error('Remote files are not supported in this version of getID3() - please copy the file locally first');
     191                }
     192
     193                $filename = str_replace('/', DIRECTORY_SEPARATOR, $filename);
     194                $filename = preg_replace('#'.preg_quote(DIRECTORY_SEPARATOR).'{2,}#', DIRECTORY_SEPARATOR, $filename);
     195
     196                // open local file
     197                if (file_exists($filename) && ($fp = @fopen($filename, 'rb'))) {
     198                        // great
     199                } else {
     200                        return $this->error('Could not open file "'.$filename.'"');
     201                }
     202
     203                // set parameters
     204                $this->info['filesize'] = filesize($filename);
     205
     206                // option_max_2gb_check
     207                if ($this->option_max_2gb_check) {
     208                        // PHP doesn't support integers larger than 31-bit (~2GB)
     209                        // filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize
     210                        // ftell() returns 0 if seeking to the end is beyond the range of unsigned integer
     211                        fseek($fp, 0, SEEK_END);
     212                        if ((($this->info['filesize'] != 0) && (ftell($fp) == 0)) ||
     213                                ($this->info['filesize'] < 0) ||
     214                                (ftell($fp) < 0)) {
     215                                        $real_filesize = false;
     216                                        if (GETID3_OS_ISWINDOWS) {
     217                                                $commandline = 'dir /-C "'.str_replace('/', DIRECTORY_SEPARATOR, $filename).'"';
     218                                                $dir_output = `$commandline`;
     219                                                if (eregi('1 File\(s\)[ ]+([0-9]+) bytes', $dir_output, $matches)) {
     220                                                        $real_filesize = (float) $matches[1];
     221                                                }
     222                                        } else {
     223                                                $commandline = 'ls -o -g -G --time-style=long-iso '.escapeshellarg($filename);
     224                                                $dir_output = `$commandline`;
     225                                                if (eregi('([0-9]+) ([0-9]{4}-[0-9]{2}\-[0-9]{2} [0-9]{2}:[0-9]{2}) '.preg_quote($filename).'$', $dir_output, $matches)) {
     226                                                        $real_filesize = (float) $matches[1];
     227                                                }
     228                                        }
     229                                        if ($real_filesize === false) {
     230                                                unset($this->info['filesize']);
     231                                                fclose($fp);
     232                                                return $this->error('File is most likely larger than 2GB and is not supported by PHP');
     233                                        } elseif ($real_filesize < pow(2, 31)) {
     234                                                unset($this->info['filesize']);
     235                                                fclose($fp);
     236                                                return $this->error('PHP seems to think the file is larger than 2GB, but filesystem reports it as '.number_format($real_filesize, 3).'GB, please report to info@getid3.org');
     237                                        }
     238                                        $this->info['filesize'] = $real_filesize;
     239                                        $this->error('File is larger than 2GB (filesystem reports it as '.number_format($real_filesize, 3).'GB) and is not properly supported by PHP.');
     240                        }
     241                }
     242
     243                // set more parameters
     244                $this->info['avdataoffset']        = 0;
     245                $this->info['avdataend']           = $this->info['filesize'];
     246                $this->info['fileformat']          = '';                // filled in later
     247                $this->info['audio']['dataformat'] = '';                // filled in later, unset if not used
     248                $this->info['video']['dataformat'] = '';                // filled in later, unset if not used
     249                $this->info['tags']                = array();           // filled in later, unset if not used
     250                $this->info['error']               = array();           // filled in later, unset if not used
     251                $this->info['warning']             = array();           // filled in later, unset if not used
     252                $this->info['comments']            = array();           // filled in later, unset if not used
     253                $this->info['encoding']            = $this->encoding;   // required by id3v2 and iso modules - can be unset at the end if desired
     254
     255                // set redundant parameters - might be needed in some include file
     256                $this->info['filename']            = basename($filename);
     257                $this->info['filepath']            = str_replace('\\', '/', realpath(dirname($filename)));
     258                $this->info['filenamepath']        = $this->info['filepath'].'/'.$this->info['filename'];
     259
     260
     261                // handle ID3v2 tag - done first - already at beginning of file
     262                // ID3v2 detection (even if not parsing) is always done otherwise fileformat is much harder to detect
     263                if ($this->option_tag_id3v2) {
     264
     265                        $GETID3_ERRORARRAY = &$this->info['warning'];
     266                        if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, false)) {
     267                                $tag = new getid3_id3v2($fp, $this->info);
     268                                unset($tag);
     269                        }
     270
     271                } else {
     272
     273                        fseek($fp, 0, SEEK_SET);
     274                        $header = fread($fp, 10);
     275                        if (substr($header, 0, 3) == 'ID3'  &&  strlen($header) == 10) {
     276                                $this->info['id3v2']['header']           = true;
     277                                $this->info['id3v2']['majorversion']     = ord($header{3});
     278                                $this->info['id3v2']['minorversion']     = ord($header{4});
     279                                $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
     280
     281                                $this->info['id3v2']['tag_offset_start'] = 0;
     282                                $this->info['id3v2']['tag_offset_end']   = $this->info['id3v2']['tag_offset_start'] + $this->info['id3v2']['headerlength'];
     283                                $this->info['avdataoffset']              = $this->info['id3v2']['tag_offset_end'];
     284                        }
     285
     286                }
     287
     288
     289                // handle ID3v1 tag
     290                if ($this->option_tag_id3v1) {
     291                        if (!@include_once(GETID3_INCLUDEPATH.'module.tag.id3v1.php')) {
     292                                return $this->error('module.tag.id3v1.php is missing - you may disable option_tag_id3v1.');
     293                        }
     294                        $tag = new getid3_id3v1($fp, $this->info);
     295                        unset($tag);
     296                }
     297
     298                // handle APE tag
     299                if ($this->option_tag_apetag) {
     300                        if (!@include_once(GETID3_INCLUDEPATH.'module.tag.apetag.php')) {
     301                                return $this->error('module.tag.apetag.php is missing - you may disable option_tag_apetag.');
     302                        }
     303                        $tag = new getid3_apetag($fp, $this->info);
     304                        unset($tag);
     305                }
     306
     307                // handle lyrics3 tag
     308                if ($this->option_tag_lyrics3) {
     309                        if (!@include_once(GETID3_INCLUDEPATH.'module.tag.lyrics3.php')) {
     310                                return $this->error('module.tag.lyrics3.php is missing - you may disable option_tag_lyrics3.');
     311                        }
     312                        $tag = new getid3_lyrics3($fp, $this->info);
     313                        unset($tag);
     314                }
     315
     316                // read 32 kb file data
     317                fseek($fp, $this->info['avdataoffset'], SEEK_SET);
     318                $formattest = fread($fp, 32774);
     319
     320                // determine format
     321                $determined_format = $this->GetFileFormat($formattest, $filename);
     322
     323                // unable to determine file format
     324                if (!$determined_format) {
     325                        fclose($fp);
     326                        return $this->error('unable to determine file format');
     327                }
     328
     329                // check for illegal ID3 tags
     330                if (isset($determined_format['fail_id3']) && (in_array('id3v1', $this->info['tags']) || in_array('id3v2', $this->info['tags']))) {
     331                        if ($determined_format['fail_id3'] === 'ERROR') {
     332                                fclose($fp);
     333                                return $this->error('ID3 tags not allowed on this file type.');
     334                        } elseif ($determined_format['fail_id3'] === 'WARNING') {
     335                                $this->info['warning'][] = 'ID3 tags not allowed on this file type.';
     336                        }
     337                }
     338
     339                // check for illegal APE tags
     340                if (isset($determined_format['fail_ape']) && in_array('ape', $this->info['tags'])) {
     341                        if ($determined_format['fail_ape'] === 'ERROR') {
     342                                fclose($fp);
     343                                return $this->error('APE tags not allowed on this file type.');
     344                        } elseif ($determined_format['fail_ape'] === 'WARNING') {
     345                                $this->info['warning'][] = 'APE tags not allowed on this file type.';
     346                        }
     347                }
     348
     349                // set mime type
     350                $this->info['mime_type'] = $determined_format['mime_type'];
     351
     352                // supported format signature pattern detected, but module deleted
     353                if (!file_exists(GETID3_INCLUDEPATH.$determined_format['include'])) {
     354                        fclose($fp);
     355                        return $this->error('Format not supported, module "'.$determined_format['include'].'" was removed.');
     356                }
     357
     358                // module requires iconv support
     359        if (!function_exists('iconv') && @$determined_format['iconv_req']) {
     360                    return $this->error('iconv support is required for this module ('.$determined_format['include'].').');
     361                }
     362
     363                // include module
     364                include_once(GETID3_INCLUDEPATH.$determined_format['include']);
     365
     366                // instantiate module class
     367                $class_name = 'getid3_'.$determined_format['module'];
     368                if (!class_exists($class_name)) {
     369                        return $this->error('Format not supported, module "'.$determined_format['include'].'" is corrupt.');
     370                }
     371                if (isset($determined_format['option'])) {
     372                        $class = new $class_name($fp, $this->info, $determined_format['option']);
     373                } else {
     374                        $class = new $class_name($fp, $this->info);
     375                }
     376                unset($class);
     377
     378                // close file
     379                fclose($fp);
     380
     381                // process all tags - copy to 'tags' and convert charsets
     382                if ($this->option_tags_process) {
     383                        $this->HandleAllTags();
     384                }
     385
     386                // perform more calculations
     387                if ($this->option_extra_info) {
     388                        $this->ChannelsBitratePlaytimeCalculations();
     389                        $this->CalculateCompressionRatioVideo();
     390                        $this->CalculateCompressionRatioAudio();
     391                        $this->CalculateReplayGain();
     392                        $this->ProcessAudioStreams();
     393                }
     394
     395                // get the MD5 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags
     396                if ($this->option_md5_data) {
     397                        // do not cald md5_data if md5_data_source is present - set by flac only - future MPC/SV8 too
     398                        if (!$this->option_md5_data_source || empty($this->info['md5_data_source'])) {
     399                                $this->getHashdata('md5');
     400                        }
     401                }
     402
     403                // get the SHA1 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags
     404                if ($this->option_sha1_data) {
     405                        $this->getHashdata('sha1');
     406                }
     407
     408                // remove undesired keys
     409                $this->CleanUp();
     410
     411                // restore magic_quotes_runtime setting
     412                set_magic_quotes_runtime($old_magic_quotes_runtime);
     413
     414                // return info array
     415                return $this->info;
     416        }
     417
     418
     419        // private: error handling
     420        function error($message) {
     421
     422                $this->CleanUp();
     423
     424                $this->info['error'][] = $message;
     425                return $this->info;
     426        }
     427
     428
     429        // private: warning handling
     430        function warning($message) {
     431                $this->info['warning'][] = $message;
     432                return true;
     433        }
     434
     435
     436        // private: CleanUp
     437        function CleanUp() {
     438
     439                // remove possible empty keys
     440                $AVpossibleEmptyKeys = array('dataformat', 'bits_per_sample', 'encoder_options', 'streams', 'bitrate');
     441                foreach ($AVpossibleEmptyKeys as $dummy => $key) {
     442                        if (empty($this->info['audio'][$key]) && isset($this->info['audio'][$key])) {
     443                                unset($this->info['audio'][$key]);
     444                        }
     445                        if (empty($this->info['video'][$key]) && isset($this->info['video'][$key])) {
     446                                unset($this->info['video'][$key]);
     447                        }
     448                }
     449
     450                // remove empty root keys
     451                if (!empty($this->info)) {
     452                        foreach ($this->info as $key => $value) {
     453                                if (empty($this->info[$key]) && ($this->info[$key] !== 0) && ($this->info[$key] !== '0')) {
     454                                        unset($this->info[$key]);
     455                                }
     456                        }
     457                }
     458
     459                // remove meaningless entries from unknown-format files
     460                if (empty($this->info['fileformat'])) {
     461                        if (isset($this->info['avdataoffset'])) {
     462                                unset($this->info['avdataoffset']);
     463                        }
     464                        if (isset($this->info['avdataend'])) {
     465                                unset($this->info['avdataend']);
     466                        }
     467                }
     468        }
     469
     470
     471        // return array containing information about all supported formats
     472        function GetFileFormatArray() {
     473                static $format_info = array();
     474                if (empty($format_info)) {
     475                        $format_info = array(
     476
     477                                // Audio formats
     478
     479                                // AC-3   - audio      - Dolby AC-3 / Dolby Digital
     480                                'ac3'  => array(
     481                                                        'pattern'   => '^\x0B\x77',
     482                                                        'group'     => 'audio',
     483                                                        'module'    => 'ac3',
     484                                                        'mime_type' => 'audio/ac3',
     485                                                ),
     486
     487                                // AAC  - audio       - Advanced Audio Coding (AAC) - ADIF format
     488                                'adif' => array(
     489                                                        'pattern'   => '^ADIF',
     490                                                        'group'     => 'audio',
     491                                                        'module'    => 'aac',
     492                                                        'option'    => 'adif',
     493                                                        'mime_type' => 'application/octet-stream',
     494                                                        'fail_ape'  => 'WARNING',
     495                                                ),
     496
     497
     498                                // AAC  - audio       - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3)
     499                                'adts' => array(
     500                                                        'pattern'   => '^\xFF[\xF0-\xF1\xF8-\xF9]',
     501                                                        'group'     => 'audio',
     502                                                        'module'    => 'aac',
     503                                                        'option'    => 'adts',
     504                                                        'mime_type' => 'application/octet-stream',
     505                                                        'fail_ape'  => 'WARNING',
     506                                                ),
     507
     508
     509                                // AU   - audio       - NeXT/Sun AUdio (AU)
     510                                'au'   => array(
     511                                                        'pattern'   => '^\.snd',
     512                                                        'group'     => 'audio',
     513                                                        'module'    => 'au',
     514                                                        'mime_type' => 'audio/basic',
     515                                                ),
     516
     517                                // AVR  - audio       - Audio Visual Research
     518                                'avr'  => array(
     519                                                        'pattern'   => '^2BIT',
     520                                                        'group'     => 'audio',
     521                                                        'module'    => 'avr',
     522                                                        'mime_type' => 'application/octet-stream',
     523                                                ),
     524
     525                                // BONK - audio       - Bonk v0.9+
     526                                'bonk' => array(
     527                                                        'pattern'   => '^\x00(BONK|INFO|META| ID3)',
     528                                                        'group'     => 'audio',
     529                                                        'module'    => 'bonk',
     530                                                        'mime_type' => 'audio/xmms-bonk',
     531                                                ),
     532
     533                                // DSS  - audio       - Digital Speech Standard
     534                                'dss'  => array(
     535                                                        'pattern'   => '^[\x02]dss',
     536                                                        'group'     => 'audio',
     537                                                        'module'    => 'dss',
     538                                                        'mime_type' => 'application/octet-stream',
     539                                                ),
     540
     541                                // DTS  - audio       - Dolby Theatre System
    595542                                'dts'  => array(
    596543                                                        'pattern'   => '^\x7F\xFE\x80\x01',
     
    600547                                                ),
    601548
    602                 // FLAC - audio       - Free Lossless Audio Codec
    603                 'flac' => array (
    604                             'pattern'   => '^fLaC',
    605                             'group'     => 'audio',
    606                             'module'    => 'xiph',
    607                             'mime_type' => 'audio/x-flac',
    608                           ),
    609 
    610                 // LA   - audio       - Lossless Audio (LA)
    611                 'la'   => array (
    612                             'pattern'   => '^LA0[2-4]',
    613                             'group'     => 'audio',
    614                             'module'    => 'la',
    615                             'mime_type' => 'application/octet-stream',
    616                           ),
    617 
    618                 // LPAC - audio       - Lossless Predictive Audio Compression (LPAC)
    619                 'lpac' => array (
    620                             'pattern'   => '^LPAC',
    621                             'group'     => 'audio',
    622                             'module'    => 'lpac',
    623                             'mime_type' => 'application/octet-stream',
    624                           ),
    625 
    626                 // MIDI - audio       - MIDI (Musical Instrument Digital Interface)
    627                 'midi' => array (
    628                             'pattern'   => '^MThd',
    629                             'group'     => 'audio',
    630                             'module'    => 'midi',
    631                             'mime_type' => 'audio/midi',
    632                           ),
    633 
    634                 // MAC  - audio       - Monkey's Audio Compressor
    635                 'mac'  => array (
    636                             'pattern'   => '^MAC ',
    637                             'group'     => 'audio',
    638                             'module'    => 'monkey',
    639                             'mime_type' => 'application/octet-stream',
    640                           ),
    641 
    642                 // MOD  - audio       - MODule (assorted sub-formats)
    643                 'mod'  => array (
    644                             'pattern'   => '^.{1080}(M.K.|[5-9]CHN|[1-3][0-9]CH)',
    645                             'mime_type' => 'audio/mod',
    646                           ),
    647 
    648                 // MOD  - audio       - MODule (Impulse Tracker)
    649                 'it'   => array (
    650                             'pattern'   => '^IMPM',
    651                             'mime_type' => 'audio/it',
    652                           ),
    653 
    654                 // MOD  - audio       - MODule (eXtended Module, various sub-formats)
    655                 'xm'   => array (
    656                             'pattern'   => '^Extended Module',
    657                             'mime_type' => 'audio/xm',
    658                           ),
    659 
    660                 // MOD  - audio       - MODule (ScreamTracker)
    661                 's3m'  => array (
    662                             'pattern'   => '^.{44}SCRM',
    663                             'mime_type' => 'audio/s3m',
    664                           ),
    665 
    666                 // MPC  - audio       - Musepack / MPEGplus SV7+
    667                 'mpc'  => array (
    668                             'pattern'   => '^(MP\+)',
    669                             'group'     => 'audio',
    670                             'module'    => 'mpc',
    671                             'mime_type' => 'audio/x-musepack',
    672                           ),
    673 
    674                 // MPC  - audio       - Musepack / MPEGplus SV4-6
    675                 'mpc_old' => array (
    676                             'pattern'   => '^([\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])',
    677                             'group'     => 'audio',
    678                             'module'    => 'mpc_old',
    679                             'mime_type' => 'application/octet-stream',
    680                           ),
    681 
    682 
    683                 // MP3  - audio       - MPEG-audio Layer 3 (very similar to AAC-ADTS)
    684                 'mp3'  => array (
    685                             'pattern'   => '^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]',
    686                             'group'     => 'audio',
    687                             'module'    => 'mp3',
    688                             'mime_type' => 'audio/mpeg',
    689                           ),
    690 
    691                 // OFR  - audio       - OptimFROG
    692                 'ofr'  => array (
    693                             'pattern'   => '^(\*RIFF|OFR)',
    694                             'group'     => 'audio',
    695                             'module'    => 'optimfrog',
    696                             'mime_type' => 'application/octet-stream',
    697                           ),
    698 
    699                 // RKAU - audio       - RKive AUdio compressor
    700                 'rkau' => array (
    701                             'pattern'   => '^RKA',
    702                             'group'     => 'audio',
    703                             'module'    => 'rkau',
    704                             'mime_type' => 'application/octet-stream',
    705                           ),
    706 
    707                 // SHN  - audio       - Shorten
    708                 'shn'  => array (
    709                             'pattern'   => '^ajkg',
    710                             'group'     => 'audio',
    711                             'module'    => 'shorten',
    712                             'mime_type' => 'audio/xmms-shn',
    713                             'fail_id3'  => 'ERROR',
    714                             'fail_ape'  => 'ERROR',
    715                           ),
    716 
    717                 // TTA  - audio       - TTA Lossless Audio Compressor (http://tta.corecodec.org)
    718                 'tta'  => array (
    719                             'pattern'   => '^TTA',  // could also be '^TTA(\x01|\x02|\x03|2|1)'
    720                             'group'     => 'audio',
    721                             'module'    => 'tta',
    722                             'mime_type' => 'application/octet-stream',
    723                           ),
    724 
    725                 // VOC  - audio       - Creative Voice (VOC)
    726                 'voc'  => array (
    727                             'pattern'   => '^Creative Voice File',
    728                             'group'     => 'audio',
    729                             'module'    => 'voc',
    730                             'mime_type' => 'audio/voc',
    731                           ),
    732 
    733                 // VQF  - audio       - transform-domain weighted interleave Vector Quantization Format (VQF)
    734                 'vqf'  => array (
    735                             'pattern'   => '^TWIN',
    736                             'group'     => 'audio',
    737                             'module'    => 'vqf',
    738                             'mime_type' => 'application/octet-stream',
    739                           ),
    740 
    741                 // WV  - audio        - WavPack (v4.0+)
    742                 'vw'  => array(
    743                             'pattern'   => '^wvpk',
    744                             'group'     => 'audio',
    745                             'module'    => 'wavpack',
    746                             'mime_type' => 'application/octet-stream',
    747                           ),
    748 
    749 
    750                 // Audio-Video formats
    751 
    752                 // ASF  - audio/video - Advanced Streaming Format, Windows Media Video, Windows Media Audio
    753                 'asf'  => array (
    754                             'pattern'   => '^\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C',
    755                             'group'     => 'audio-video',
    756                             'module'    => 'asf',
    757                             'mime_type' => 'video/x-ms-asf',
    758                           ),
    759 
    760                 // BINK  - audio/video - Bink / Smacker
    761                 'bink' => array(
    762                             'pattern'   => '^(BIK|SMK)',
    763                             'mime_type' => 'application/octet-stream',
    764                           ),
    765 
    766                 // FLV  - audio/video - FLash Video
    767                 'flv' => array(
    768                             'pattern'   => '^FLV\x01',
    769                             'group'     => 'audio-video',
    770                             'module'    => 'flv',
    771                             'mime_type' => 'video/x-flv',
    772                           ),
    773 
    774                 // MKAV - audio/video - Mastroka
    775                 'matroska' => array (
    776                             'pattern'   => '^\x1A\x45\xDF\xA3',
    777                             'mime_type' => 'application/octet-stream',
    778                           ),
    779 
    780                 // MPEG - audio/video - MPEG (Moving Pictures Experts Group)
    781                 'mpeg' => array (
    782                             'pattern'   => '^\x00\x00\x01(\xBA|\xB3)',
    783                             'group'     => 'audio-video',
    784                             'module'    => 'mpeg',
    785                             'mime_type' => 'video/mpeg',
    786                           ),
    787 
    788                 // NSV  - audio/video - Nullsoft Streaming Video (NSV)
    789                 'nsv'  => array (
    790                             'pattern'   => '^NSV[sf]',
    791                             'group'     => 'audio-video',
    792                             'module'    => 'nsv',
    793                             'mime_type' => 'application/octet-stream',
    794                           ),
    795 
    796                 // Ogg  - audio/video - Ogg (Ogg Vorbis, OggFLAC, Speex, Ogg Theora(*), Ogg Tarkin(*))
    797                 'ogg'  => array (
    798                             'pattern'   => '^OggS',
    799                             'group'     => 'audio',
    800                             'module'    => 'xiph',
    801                             'mime_type' => 'application/ogg',
    802                             'fail_id3'  => 'WARNING',
    803                             'fail_ape'  => 'WARNING',
    804                           ),
    805 
    806                 // QT   - audio/video - Quicktime
    807                 'quicktime' => array (
    808                             'pattern'   => '^.{4}(cmov|free|ftyp|mdat|moov|pnot|skip|wide)',
    809                             'group'     => 'audio-video',
    810                             'module'    => 'quicktime',
    811                             'mime_type' => 'video/quicktime',
    812                           ),
    813 
    814                 // RIFF - audio/video - Resource Interchange File Format (RIFF) / WAV / AVI / CD-audio / SDSS = renamed variant used by SmartSound QuickTracks (www.smartsound.com) / FORM = Audio Interchange File Format (AIFF)
    815                 'riff' => array (
    816                             'pattern'   => '^(RIFF|SDSS|FORM)',
    817                             'group'     => 'audio-video',
    818                             'module'    => 'riff',
    819                             'mime_type' => 'audio/x-wave',
    820                             'fail_ape'  => 'WARNING',
    821                           ),
    822 
    823                 // Real - audio/video - RealAudio, RealVideo
    824                 'real' => array (
    825                             'pattern'   => '^(\.RMF|.ra)',
    826                             'group'     => 'audio-video',
    827                             'module'    => 'real',
    828                             'mime_type' => 'audio/x-realaudio',
    829                           ),
    830 
    831                 // SWF - audio/video - ShockWave Flash
    832                 'swf' => array (
    833                             'pattern'   => '^(F|C)WS',
    834                             'group'     => 'audio-video',
    835                             'module'    => 'swf',
    836                             'mime_type' => 'application/x-shockwave-flash',
    837                           ),
    838 
    839 
    840                 // Still-Image formats
    841 
    842                 // BMP  - still image - Bitmap (Windows, OS/2; uncompressed, RLE8, RLE4)
    843                 'bmp'  => array (
    844                             'pattern'   => '^BM',
    845                             'group'     => 'graphic',
    846                             'module'    => 'bmp',
    847                             'mime_type' => 'image/bmp',
    848                             'fail_id3'  => 'ERROR',
    849                             'fail_ape'  => 'ERROR',
    850                           ),
    851 
    852                 // GIF  - still image - Graphics Interchange Format
    853                 'gif'  => array (
    854                             'pattern'   => '^GIF',
    855                             'group'     => 'graphic',
    856                             'module'    => 'gif',
    857                             'mime_type' => 'image/gif',
    858                             'fail_id3'  => 'ERROR',
    859                             'fail_ape'  => 'ERROR',
    860                           ),
    861 
    862                 // JPEG - still image - Joint Photographic Experts Group (JPEG)
    863                 'jpeg'  => array (
    864                             'pattern'   => '^\xFF\xD8\xFF',
    865                             'group'     => 'graphic',
    866                             'module'    => 'jpeg',
    867                             'mime_type' => 'image/jpeg',
    868                             'fail_id3'  => 'ERROR',
    869                             'fail_ape'  => 'ERROR',
    870                           ),
    871 
    872                 // PCD  - still image - Kodak Photo CD
    873                 'pcd'  => array (
    874                             'pattern'   => '^.{2048}PCD_IPI\x00',
    875                             'group'     => 'graphic',
    876                             'module'    => 'pcd',
    877                             'mime_type' => 'image/x-photo-cd',
    878                             'fail_id3'  => 'ERROR',
    879                             'fail_ape'  => 'ERROR',
    880                           ),
    881 
    882 
    883                 // PNG  - still image - Portable Network Graphics (PNG)
    884                 'png'  => array (
    885                             'pattern'   => '^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A',
    886                             'group'     => 'graphic',
    887                             'module'    => 'png',
    888                             'mime_type' => 'image/png',
    889                             'fail_id3'  => 'ERROR',
    890                             'fail_ape'  => 'ERROR',
    891                           ),
     549                                // FLAC - audio       - Free Lossless Audio Codec
     550                                'flac' => array(
     551                                                        'pattern'   => '^fLaC',
     552                                                        'group'     => 'audio',
     553                                                        'module'    => 'flac',
     554                                                        'mime_type' => 'audio/x-flac',
     555                                                ),
     556
     557                                // LA   - audio       - Lossless Audio (LA)
     558                                'la'   => array(
     559                                                        'pattern'   => '^LA0[2-4]',
     560                                                        'group'     => 'audio',
     561                                                        'module'    => 'la',
     562                                                        'mime_type' => 'application/octet-stream',
     563                                                ),
     564
     565                                // LPAC - audio       - Lossless Predictive Audio Compression (LPAC)
     566                                'lpac' => array(
     567                                                        'pattern'   => '^LPAC',
     568                                                        'group'     => 'audio',
     569                                                        'module'    => 'lpac',
     570                                                        'mime_type' => 'application/octet-stream',
     571                                                ),
     572
     573                                // MIDI - audio       - MIDI (Musical Instrument Digital Interface)
     574                                'midi' => array(
     575                                                        'pattern'   => '^MThd',
     576                                                        'group'     => 'audio',
     577                                                        'module'    => 'midi',
     578                                                        'mime_type' => 'audio/midi',
     579                                                ),
     580
     581                                // MAC  - audio       - Monkey's Audio Compressor
     582                                'mac'  => array(
     583                                                        'pattern'   => '^MAC ',
     584                                                        'group'     => 'audio',
     585                                                        'module'    => 'monkey',
     586                                                        'mime_type' => 'application/octet-stream',
     587                                                ),
     588
     589// has been known to produce false matches in random files (e.g. JPEGs), leave out until more precise matching available
     590//                              // MOD  - audio       - MODule (assorted sub-formats)
     591//                              'mod'  => array(
     592//                                                      'pattern'   => '^.{1080}(M\\.K\\.|M!K!|FLT4|FLT8|[5-9]CHN|[1-3][0-9]CH)',
     593//                                                      'group'     => 'audio',
     594//                                                      'module'    => 'mod',
     595//                                                      'option'    => 'mod',
     596//                                                      'mime_type' => 'audio/mod',
     597//                                              ),
     598
     599                                // MOD  - audio       - MODule (Impulse Tracker)
     600                                'it'   => array(
     601                                                        'pattern'   => '^IMPM',
     602                                                        'group'     => 'audio',
     603                                                        'module'    => 'mod',
     604                                                        'option'    => 'it',
     605                                                        'mime_type' => 'audio/it',
     606                                                ),
     607
     608                                // MOD  - audio       - MODule (eXtended Module, various sub-formats)
     609                                'xm'   => array(
     610                                                        'pattern'   => '^Extended Module',
     611                                                        'group'     => 'audio',
     612                                                        'module'    => 'mod',
     613                                                        'option'    => 'xm',
     614                                                        'mime_type' => 'audio/xm',
     615                                                ),
     616
     617                                // MOD  - audio       - MODule (ScreamTracker)
     618                                's3m'  => array(
     619                                                        'pattern'   => '^.{44}SCRM',
     620                                                        'group'     => 'audio',
     621                                                        'module'    => 'mod',
     622                                                        'option'    => 's3m',
     623                                                        'mime_type' => 'audio/s3m',
     624                                                ),
     625
     626                                // MPC  - audio       - Musepack / MPEGplus
     627                                'mpc'  => array(
     628                                                        '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])',
     629                                                        'group'     => 'audio',
     630                                                        'module'    => 'mpc',
     631                                                        'mime_type' => 'audio/x-musepack',
     632                                                ),
     633
     634                                // MP3  - audio       - MPEG-audio Layer 3 (very similar to AAC-ADTS)
     635                                'mp3'  => array(
     636                                                        'pattern'   => '^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]',
     637                                                        'group'     => 'audio',
     638                                                        'module'    => 'mp3',
     639                                                        'mime_type' => 'audio/mpeg',
     640                                                ),
     641
     642                                // OFR  - audio       - OptimFROG
     643                                'ofr'  => array(
     644                                                        'pattern'   => '^(\*RIFF|OFR)',
     645                                                        'group'     => 'audio',
     646                                                        'module'    => 'optimfrog',
     647                                                        'mime_type' => 'application/octet-stream',
     648                                                ),
     649
     650                                // RKAU - audio       - RKive AUdio compressor
     651                                'rkau' => array(
     652                                                        'pattern'   => '^RKA',
     653                                                        'group'     => 'audio',
     654                                                        'module'    => 'rkau',
     655                                                        'mime_type' => 'application/octet-stream',
     656                                                ),
     657
     658                                // SHN  - audio       - Shorten
     659                                'shn'  => array(
     660                                                        'pattern'   => '^ajkg',
     661                                                        'group'     => 'audio',
     662                                                        'module'    => 'shorten',
     663                                                        'mime_type' => 'audio/xmms-shn',
     664                                                        'fail_id3'  => 'ERROR',
     665                                                        'fail_ape'  => 'ERROR',
     666                                                ),
     667
     668                                // TTA  - audio       - TTA Lossless Audio Compressor (http://tta.corecodec.org)
     669                                'tta'  => array(
     670                                                        'pattern'   => '^TTA',  // could also be '^TTA(\x01|\x02|\x03|2|1)'
     671                                                        'group'     => 'audio',
     672                                                        'module'    => 'tta',
     673                                                        'mime_type' => 'application/octet-stream',
     674                                                ),
     675
     676                                // VOC  - audio       - Creative Voice (VOC)
     677                                'voc'  => array(
     678                                                        'pattern'   => '^Creative Voice File',
     679                                                        'group'     => 'audio',
     680                                                        'module'    => 'voc',
     681                                                        'mime_type' => 'audio/voc',
     682                                                ),
     683
     684                                // VQF  - audio       - transform-domain weighted interleave Vector Quantization Format (VQF)
     685                                'vqf'  => array(
     686                                                        'pattern'   => '^TWIN',
     687                                                        'group'     => 'audio',
     688                                                        'module'    => 'vqf',
     689                                                        'mime_type' => 'application/octet-stream',
     690                                                ),
     691
     692                                // WV  - audio        - WavPack (v4.0+)
     693                                'wv'   => array(
     694                                                        'pattern'   => '^wvpk',
     695                                                        'group'     => 'audio',
     696                                                        'module'    => 'wavpack',
     697                                                        'mime_type' => 'application/octet-stream',
     698                                                ),
     699
     700
     701                                // Audio-Video formats
     702
     703                                // ASF  - audio/video - Advanced Streaming Format, Windows Media Video, Windows Media Audio
     704                                'asf'  => array(
     705                                                        'pattern'   => '^\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C',
     706                                                        'group'     => 'audio-video',
     707                                                        'module'    => 'asf',
     708                                                        'mime_type' => 'video/x-ms-asf',
     709                                                        'iconv_req' => false,
     710                                                ),
     711
     712                                // BINK - audio/video - Bink / Smacker
     713                                'bink' => array(
     714                                                        'pattern'   => '^(BIK|SMK)',
     715                                                        'group'     => 'audio-video',
     716                                                        'module'    => 'bink',
     717                                                        'mime_type' => 'application/octet-stream',
     718                                                ),
     719
     720                                // FLV  - audio/video - FLash Video
     721                                'flv' => array(
     722                                                        'pattern'   => '^FLV\x01',
     723                                                        'group'     => 'audio-video',
     724                                                        'module'    => 'flv',
     725                                                        'mime_type' => 'video/x-flv',
     726                                                ),
     727
     728                                // MKAV - audio/video - Mastroka
     729                                'matroska' => array(
     730                                                        'pattern'   => '^\x1A\x45\xDF\xA3',
     731                                                        'group'     => 'audio-video',
     732                                                        'module'    => 'matroska',
     733                                                        'mime_type' => 'video/x-matroska', // may also be audio/x-matroska
     734                                                ),
     735
     736                                // MPEG - audio/video - MPEG (Moving Pictures Experts Group)
     737                                'mpeg' => array(
     738                                                        'pattern'   => '^\x00\x00\x01(\xBA|\xB3)',
     739                                                        'group'     => 'audio-video',
     740                                                        'module'    => 'mpeg',
     741                                                        'mime_type' => 'video/mpeg',
     742                                                ),
     743
     744                                // NSV  - audio/video - Nullsoft Streaming Video (NSV)
     745                                'nsv'  => array(
     746                                                        'pattern'   => '^NSV[sf]',
     747                                                        'group'     => 'audio-video',
     748                                                        'module'    => 'nsv',
     749                                                        'mime_type' => 'application/octet-stream',
     750                                                ),
     751
     752                                // Ogg  - audio/video - Ogg (Ogg-Vorbis, Ogg-FLAC, Speex, Ogg-Theora(*), Ogg-Tarkin(*))
     753                                'ogg'  => array(
     754                                                        'pattern'   => '^OggS',
     755                                                        'group'     => 'audio',
     756                                                        'module'    => 'ogg',
     757                                                        'mime_type' => 'application/ogg',
     758                                                        'fail_id3'  => 'WARNING',
     759                                                        'fail_ape'  => 'WARNING',
     760                                                ),
     761
     762                                // QT   - audio/video - Quicktime
     763                                'quicktime' => array(
     764                                                        'pattern'   => '^.{4}(cmov|free|ftyp|mdat|moov|pnot|skip|wide)',
     765                                                        'group'     => 'audio-video',
     766                                                        'module'    => 'quicktime',
     767                                                        'mime_type' => 'video/quicktime',
     768                                                ),
     769
     770                                // RIFF - audio/video - Resource Interchange File Format (RIFF) / WAV / AVI / CD-audio / SDSS = renamed variant used by SmartSound QuickTracks (www.smartsound.com) / FORM = Audio Interchange File Format (AIFF)
     771                                'riff' => array(
     772                                                        'pattern'   => '^(RIFF|SDSS|FORM)',
     773                                                        'group'     => 'audio-video',
     774                                                        'module'    => 'riff',
     775                                                        'mime_type' => 'audio/x-wave',
     776                                                        'fail_ape'  => 'WARNING',
     777                                                ),
     778
     779                                // Real - audio/video - RealAudio, RealVideo
     780                                'real' => array(
     781                                                        'pattern'   => '^(\\.RMF|\\.ra)',
     782                                                        'group'     => 'audio-video',
     783                                                        'module'    => 'real',
     784                                                        'mime_type' => 'audio/x-realaudio',
     785                                                ),
     786
     787                                // SWF - audio/video - ShockWave Flash
     788                                'swf' => array(
     789                                                        'pattern'   => '^(F|C)WS',
     790                                                        'group'     => 'audio-video',
     791                                                        'module'    => 'swf',
     792                                                        'mime_type' => 'application/x-shockwave-flash',
     793                                                ),
     794
     795
     796                                // Still-Image formats
     797
     798                                // BMP  - still image - Bitmap (Windows, OS/2; uncompressed, RLE8, RLE4)
     799                                'bmp'  => array(
     800                                                        'pattern'   => '^BM',
     801                                                        'group'     => 'graphic',
     802                                                        'module'    => 'bmp',
     803                                                        'mime_type' => 'image/bmp',
     804                                                        'fail_id3'  => 'ERROR',
     805                                                        'fail_ape'  => 'ERROR',
     806                                                ),
     807
     808                                // GIF  - still image - Graphics Interchange Format
     809                                'gif'  => array(
     810                                                        'pattern'   => '^GIF',
     811                                                        'group'     => 'graphic',
     812                                                        'module'    => 'gif',
     813                                                        'mime_type' => 'image/gif',
     814                                                        'fail_id3'  => 'ERROR',
     815                                                        'fail_ape'  => 'ERROR',
     816                                                ),
     817
     818                                // JPEG - still image - Joint Photographic Experts Group (JPEG)
     819                                'jpg'  => array(
     820                                                        'pattern'   => '^\xFF\xD8\xFF',
     821                                                        'group'     => 'graphic',
     822                                                        'module'    => 'jpg',
     823                                                        'mime_type' => 'image/jpeg',
     824                                                        'fail_id3'  => 'ERROR',
     825                                                        'fail_ape'  => 'ERROR',
     826                                                ),
     827
     828                                // PCD  - still image - Kodak Photo CD
     829                                'pcd'  => array(
     830                                                        'pattern'   => '^.{2048}PCD_IPI\x00',
     831                                                        'group'     => 'graphic',
     832                                                        'module'    => 'pcd',
     833                                                        'mime_type' => 'image/x-photo-cd',
     834                                                        'fail_id3'  => 'ERROR',
     835                                                        'fail_ape'  => 'ERROR',
     836                                                ),
     837
     838
     839                                // PNG  - still image - Portable Network Graphics (PNG)
     840                                'png'  => array(
     841                                                        'pattern'   => '^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A',
     842                                                        'group'     => 'graphic',
     843                                                        'module'    => 'png',
     844                                                        'mime_type' => 'image/png',
     845                                                        'fail_id3'  => 'ERROR',
     846                                                        'fail_ape'  => 'ERROR',
     847                                                ),
    892848
    893849
     
    895851                                'svg'  => array(
    896852                                                        'pattern'   => '<!DOCTYPE svg PUBLIC ',
     853                                                        'group'     => 'graphic',
     854                                                        'module'    => 'svg',
    897855                                                        'mime_type' => 'image/svg+xml',
    898856                                                        'fail_id3'  => 'ERROR',
     
    901859
    902860
    903                 // TIFF  - still image - Tagged Information File Format (TIFF)
    904                 'tiff' => array (
    905                             'pattern'   => '^(II\x2A\x00|MM\x00\x2A)',
    906                             'group'     => 'graphic',
    907                             'module'    => 'tiff',
    908                             'mime_type' => 'image/tiff',
    909                             'fail_id3'  => 'ERROR',
    910                             'fail_ape'  => 'ERROR',
    911                           ),
    912 
    913 
    914                 // Data formats
    915 
    916                 'exe'  => array(
    917                             'pattern'   => '^MZ',
    918                             'mime_type' => 'application/octet-stream',
    919                             'fail_id3'  => 'ERROR',
    920                             'fail_ape'  => 'ERROR',
    921                           ),
    922 
    923                 // ISO  - data        - International Standards Organization (ISO) CD-ROM Image
    924                 'iso'  => array (
    925                             'pattern'   => '^.{32769}CD001',
    926                             'group'     => 'misc',
    927                             'module'    => 'iso',
    928                             'mime_type' => 'application/octet-stream',
    929                             'fail_id3'  => 'ERROR',
    930                             'fail_ape'  => 'ERROR',
    931                           ),
    932 
    933                 // RAR  - data        - RAR compressed data
    934                 'rar'  => array(
    935                             'pattern'   => '^Rar\!',
    936                             'mime_type' => 'application/octet-stream',
    937                             'fail_id3'  => 'ERROR',
    938                             'fail_ape'  => 'ERROR',
    939                           ),
    940 
    941                 // SZIP - audio       - SZIP compressed data
    942                 'szip' => array (
    943                             'pattern'   => '^SZ\x0A\x04',
    944                             'group'     => 'archive',
    945                             'module'    => 'szip',
    946                             'mime_type' => 'application/octet-stream',
    947                             'fail_id3'  => 'ERROR',
    948                             'fail_ape'  => 'ERROR',
    949                           ),
    950 
    951                 // TAR  - data        - TAR compressed data
    952                 'tar'  => array(
    953                             'pattern'   => '^.{100}[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20\x00]{12}[0-9\x20\x00]{12}',
    954                             'group'     => 'archive',
    955                             'module'    => 'tar',
    956                             'mime_type' => 'application/x-tar',
    957                             'fail_id3'  => 'ERROR',
    958                             'fail_ape'  => 'ERROR',
    959                           ),
    960 
    961                 // GZIP  - data        - GZIP compressed data
    962                 'gz'  => array(
    963                             'pattern'   => '^\x1F\x8B\x08',
    964                             'group'     => 'archive',
    965                             'module'    => 'gzip',
    966                             'mime_type' => 'application/x-gzip',
    967                             'fail_id3'  => 'ERROR',
    968                             'fail_ape'  => 'ERROR',
    969                           ),
    970 
    971 
    972                 // ZIP  - data        - ZIP compressed data
    973                 'zip'  => array (
    974                             'pattern'   => '^PK\x03\x04',
    975                             'group'     => 'archive',
    976                             'module'    => 'zip',
    977                             'mime_type' => 'application/zip',
    978                             'fail_id3'  => 'ERROR',
    979                             'fail_ape'  => 'ERROR',
    980                           ),
    981 
     861                                // TIFF  - still image - Tagged Information File Format (TIFF)
     862                                'tiff' => array(
     863                                                        'pattern'   => '^(II\x2A\x00|MM\x00\x2A)',
     864                                                        'group'     => 'graphic',
     865                                                        'module'    => 'tiff',
     866                                                        'mime_type' => 'image/tiff',
     867                                                        'fail_id3'  => 'ERROR',
     868                                                        'fail_ape'  => 'ERROR',
     869                                                ),
     870
     871
     872                                // Data formats
     873
     874                                // ISO  - data        - International Standards Organization (ISO) CD-ROM Image
     875                                'iso'  => array(
     876                                                        'pattern'   => '^.{32769}CD001',
     877                                                        'group'     => 'misc',
     878                                                        'module'    => 'iso',
     879                                                        'mime_type' => 'application/octet-stream',
     880                                                        'fail_id3'  => 'ERROR',
     881                                                        'fail_ape'  => 'ERROR',
     882                                                        'iconv_req' => false,
     883                                                ),
     884
     885                                // RAR  - data        - RAR compressed data
     886                                'rar'  => array(
     887                                                        'pattern'   => '^Rar\!',
     888                                                        'group'     => 'archive',
     889                                                        'module'    => 'rar',
     890                                                        'mime_type' => 'application/octet-stream',
     891                                                        'fail_id3'  => 'ERROR',
     892                                                        'fail_ape'  => 'ERROR',
     893                                                ),
     894
     895                                // SZIP - audio/data  - SZIP compressed data
     896                                'szip' => array(
     897                                                        'pattern'   => '^SZ\x0A\x04',
     898                                                        'group'     => 'archive',
     899                                                        'module'    => 'szip',
     900                                                        'mime_type' => 'application/octet-stream',
     901                                                        'fail_id3'  => 'ERROR',
     902                                                        'fail_ape'  => 'ERROR',
     903                                                ),
     904
     905                                // TAR  - data        - TAR compressed data
     906                                'tar'  => array(
     907                                                        'pattern'   => '^.{100}[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20\x00]{12}[0-9\x20\x00]{12}',
     908                                                        'group'     => 'archive',
     909                                                        'module'    => 'tar',
     910                                                        'mime_type' => 'application/x-tar',
     911                                                        'fail_id3'  => 'ERROR',
     912                                                        'fail_ape'  => 'ERROR',
     913                                                ),
     914
     915                                // GZIP  - data        - GZIP compressed data
     916                                'gz'  => array(
     917                                                        'pattern'   => '^\x1F\x8B\x08',
     918                                                        'group'     => 'archive',
     919                                                        'module'    => 'gzip',
     920                                                        'mime_type' => 'application/x-gzip',
     921                                                        'fail_id3'  => 'ERROR',
     922                                                        'fail_ape'  => 'ERROR',
     923                                                ),
     924
     925                                // ZIP  - data         - ZIP compressed data
     926                                'zip'  => array(
     927                                                        'pattern'   => '^PK\x03\x04',
     928                                                        'group'     => 'archive',
     929                                                        'module'    => 'zip',
     930                                                        'mime_type' => 'application/zip',
     931                                                        'fail_id3'  => 'ERROR',
     932                                                        'fail_ape'  => 'ERROR',
     933                                                ),
     934
     935
     936                                // Misc other formats
    982937
    983938                // PAR2 - data        - Parity Volume Set Specification 2.0
    984939                'par2' => array (
    985940                                        'pattern'   => '^PAR2\x00PKT',
    986                                                         'mime_type' => 'application/octet-stream',
    987                                                         'fail_id3'  => 'ERROR',
    988                                                         'fail_ape'  => 'ERROR',
    989                                                 ),
    990 
    991 
    992                  // PDF  - data       - Portable Document Format
    993                  'pdf' => array(
    994                             'pattern'   => '^\x25PDF',
    995                             'mime_type' => 'application/pdf',
    996                             'fail_id3'  => 'ERROR',
    997                             'fail_ape'  => 'ERROR',
    998                            ),
    999 
    1000                  // DOC  - data       - Microsoft Word
    1001                  'msoffice' => array(
    1002                             'pattern'   => '^\xD0\xCF\x11\xE0', // D0CF11E == DOCFILE == Microsoft Office Document
    1003                             'mime_type' => 'application/octet-stream',
    1004                             'fail_id3'  => 'ERROR',
    1005                             'fail_ape'  => 'ERROR',
    1006                           ),
    1007             );
    1008 
    1009         return $format_info;
    1010     }
    1011 
    1012 
    1013 
    1014     // Recursive over array - converts array to $encoding charset from $this->encoding
    1015     function CharConvert(&$array, $encoding) {
    1016 
    1017         // Identical encoding - end here
    1018         if ($encoding == $this->encoding) {
    1019             return;
    1020         }
    1021 
    1022         // Loop thru array
    1023         foreach ($array as $key => $value) {
    1024 
    1025             // Go recursive
    1026             if (is_array($value)) {
    1027                 $this->CharConvert($array[$key], $encoding);
    1028             }
    1029 
    1030             // Convert string
    1031             elseif (is_string($value)) {
    1032                 $array[$key] = $this->iconv($encoding, $this->encoding, $value);
    1033             }
    1034         }
    1035     }
    1036 
    1037 
    1038 
    1039     // Convert and copy tags
    1040     protected function HandleAllTags() {
    1041 
    1042         // Key name => array (tag name, character encoding)
    1043         static $tags = array (
    1044             'asf'       => array ('asf',           'UTF-16LE'),
    1045             'midi'      => array ('midi',          'ISO-8859-1'),
    1046             'nsv'       => array ('nsv',           'ISO-8859-1'),
    1047             'ogg'       => array ('vorbiscomment', 'UTF-8'),
    1048             'png'       => array ('png',           'UTF-8'),
    1049             'tiff'      => array ('tiff',          'ISO-8859-1'),
    1050             'quicktime' => array ('quicktime',     'ISO-8859-1'),
    1051             'real'      => array ('real',          'ISO-8859-1'),
    1052             'vqf'       => array ('vqf',           'ISO-8859-1'),
    1053             'zip'       => array ('zip',           'ISO-8859-1'),
    1054             'riff'      => array ('riff',          'ISO-8859-1'),
    1055             'lyrics3'   => array ('lyrics3',       'ISO-8859-1'),
    1056             'id3v1'     => array ('id3v1',         ''),            // change below - cannot assign variable to static array
    1057             'id3v2'     => array ('id3v2',         'UTF-8'),       // module converts all frames to UTF-8
    1058             'ape'       => array ('ape',           'UTF-8')
    1059         );
    1060         $tags['id3v1'][1] = $this->encoding_id3v1;
    1061 
    1062         // Loop thru tags array
    1063         foreach ($tags as $comment_name => $tag_name_encoding_array) {
    1064             list($tag_name, $encoding) = $tag_name_encoding_array;
    1065 
    1066             // Fill in default encoding type if not already present
    1067             @$this->info[$comment_name]  and  $this->info[$comment_name]['encoding'] = $encoding;
    1068 
    1069             // Copy comments if key name set
    1070             if (@$this->info[$comment_name]['comments']) {
    1071 
    1072                 foreach ($this->info[$comment_name]['comments'] as $tag_key => $value_array) {
    1073                     foreach ($value_array as $key => $value) {
    1074                         if (strlen(trim($value)) > 0) {
    1075                             $this->info['tags'][$tag_name][trim($tag_key)][] = $value; // do not trim!! Unicode characters will get mangled if trailing nulls are removed!
    1076                         }
    1077                     }
    1078 
    1079                 }
    1080 
    1081                 if (!@$this->info['tags'][$tag_name]) {
    1082                     // comments are set but contain nothing but empty strings, so skip
    1083                     continue;
    1084                 }
    1085 
    1086                 $this->CharConvert($this->info['tags'][$tag_name], $encoding);
    1087             }
    1088         }
    1089 
    1090 
    1091         // Merge comments from ['tags'] into common ['comments']
    1092         if (@$this->info['tags']) {
    1093 
    1094             foreach ($this->info['tags'] as $tag_type => $tag_array) {
    1095 
    1096                 foreach ($tag_array as $tag_name => $tagdata) {
    1097 
    1098                     foreach ($tagdata as $key => $value) {
    1099 
    1100                         if (!empty($value)) {
    1101 
    1102                             if (empty($this->info['comments'][$tag_name])) {
    1103 
    1104                                 // fall through and append value
    1105                             }
    1106                             elseif ($tag_type == 'id3v1') {
    1107 
    1108                                 $new_value_length = strlen(trim($value));
    1109                                 foreach ($this->info['comments'][$tag_name] as $existing_key => $existing_value) {
    1110                                     $old_value_length = strlen(trim($existing_value));
    1111                                     if (($new_value_length <= $old_value_length) && (substr($existing_value, 0, $new_value_length) == trim($value))) {
    1112                                         // new value is identical but shorter-than (or equal-length to) one already in comments - skip
    1113                                         break 2;
    1114                                     }
    1115                                 }
    1116                             }
    1117                             else {
    1118 
    1119                                 $new_value_length = strlen(trim($value));
    1120                                 foreach ($this->info['comments'][$tag_name] as $existing_key => $existing_value) {
    1121                                     $old_value_length = strlen(trim($existing_value));
    1122                                     if (($new_value_length > $old_value_length) && (substr(trim($value), 0, strlen($existing_value)) == $existing_value)) {
    1123                                         $this->info['comments'][$tag_name][$existing_key] = trim($value);
    1124                                         break 2;
    1125                                     }
    1126                                 }
    1127                             }
    1128 
    1129                             if (empty($this->info['comments'][$tag_name]) || !in_array(trim($value), $this->info['comments'][$tag_name])) {
    1130                                 $this->info['comments'][$tag_name][] = trim($value);
    1131                             }
    1132                         }
    1133                     }
    1134                 }
    1135             }
    1136         }
    1137 
    1138         return true;
    1139     }
     941                                        'group'     => 'misc',
     942                                                        'module'    => 'par2',
     943                                                        'mime_type' => 'application/octet-stream',
     944                                                        'fail_id3'  => 'ERROR',
     945                                                        'fail_ape'  => 'ERROR',
     946                                                ),
     947
     948                                // PDF  - data        - Portable Document Format
     949                                'pdf'  => array(
     950                                                        'pattern'   => '^\x25PDF',
     951                                                        'group'     => 'misc',
     952                                                        'module'    => 'pdf',
     953                                                        'mime_type' => 'application/pdf',
     954                                                        'fail_id3'  => 'ERROR',
     955                                                        'fail_ape'  => 'ERROR',
     956                                                ),
     957
     958                                // MSOFFICE  - data   - ZIP compressed data
     959                                'msoffice' => array(
     960                                                        'pattern'   => '^\xD0\xCF\x11\xE0', // D0CF11E == DOCFILE == Microsoft Office Document
     961                                                        'group'     => 'misc',
     962                                                        'module'    => 'msoffice',
     963                                                        'mime_type' => 'application/octet-stream',
     964                                                        'fail_id3'  => 'ERROR',
     965                                                        'fail_ape'  => 'ERROR',
     966                                                ),
     967                        );
     968                }
     969
     970                return $format_info;
     971        }
     972
     973
     974
     975        function GetFileFormat(&$filedata, $filename='') {
     976                // this function will determine the format of a file based on usually
     977                // the first 2-4 bytes of the file (8 bytes for PNG, 16 bytes for JPG,
     978                // and in the case of ISO CD image, 6 bytes offset 32kb from the start
     979                // of the file).
     980
     981                // Identify file format - loop through $format_info and detect with reg expr
     982                foreach ($this->GetFileFormatArray() as $format_name => $info) {
     983                        // Using preg_match() instead of ereg() - much faster
     984                        // The /s switch on preg_match() forces preg_match() NOT to treat
     985                        // newline (0x0A) characters as special chars but do a binary match
     986                        if (preg_match('/'.$info['pattern'].'/s', $filedata)) {
     987                                $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
     988                                return $info;
     989                        }
     990                }
     991
     992
     993                if (preg_match('/\.mp[123a]$/i', $filename)) {
     994                        // Too many mp3 encoders on the market put gabage in front of mpeg files
     995                        // use assume format on these if format detection failed
     996                        $GetFileFormatArray = $this->GetFileFormatArray();
     997                        $info = $GetFileFormatArray['mp3'];
     998                        $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
     999                        return $info;
     1000                }
     1001
     1002                return false;
     1003        }
     1004
     1005
     1006        // converts array to $encoding charset from $this->encoding
     1007        function CharConvert(&$array, $encoding) {
     1008
     1009                // identical encoding - end here
     1010                if ($encoding == $this->encoding) {
     1011                        return;
     1012                }
     1013
     1014                // loop thru array
     1015                foreach ($array as $key => $value) {
     1016
     1017                        // go recursive
     1018                        if (is_array($value)) {
     1019                                $this->CharConvert($array[$key], $encoding);
     1020                        }
     1021
     1022                        // convert string
     1023                        elseif (is_string($value)) {
     1024                                $array[$key] = trim(getid3_lib::iconv_fallback($encoding, $this->encoding, $value));
     1025                        }
     1026                }
     1027        }
     1028
     1029
     1030        function HandleAllTags() {
     1031
     1032                // key name => array (tag name, character encoding)
     1033                static $tags;
     1034                if (empty($tags)) {
     1035                        $tags = array(
     1036                                'asf'       => array('asf'           , 'UTF-16LE'),
     1037                                'midi'      => array('midi'          , 'ISO-8859-1'),
     1038                                'nsv'       => array('nsv'           , 'ISO-8859-1'),
     1039                                'ogg'       => array('vorbiscomment' , 'UTF-8'),
     1040                                'png'       => array('png'           , 'UTF-8'),
     1041                                'tiff'      => array('tiff'          , 'ISO-8859-1'),
     1042                                'quicktime' => array('quicktime'     , 'ISO-8859-1'),
     1043                                'real'      => array('real'          , 'ISO-8859-1'),
     1044                                'vqf'       => array('vqf'           , 'ISO-8859-1'),
     1045                                'zip'       => array('zip'           , 'ISO-8859-1'),
     1046                                'riff'      => array('riff'          , 'ISO-8859-1'),
     1047                                'lyrics3'   => array('lyrics3'       , 'ISO-8859-1'),
     1048                                'id3v1'     => array('id3v1'         , $this->encoding_id3v1),
     1049                                '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
     1050                                'ape'       => array('ape'           , 'UTF-8')
     1051                        );
     1052                }
     1053
     1054                // loop thru comments array
     1055                foreach ($tags as $comment_name => $tagname_encoding_array) {
     1056                        list($tag_name, $encoding) = $tagname_encoding_array;
     1057
     1058                        // fill in default encoding type if not already present
     1059                        if (isset($this->info[$comment_name]) && !isset($this->info[$comment_name]['encoding'])) {
     1060                                $this->info[$comment_name]['encoding'] = $encoding;
     1061                        }
     1062
     1063                        // copy comments if key name set
     1064                        if (!empty($this->info[$comment_name]['comments'])) {
     1065
     1066                                foreach ($this->info[$comment_name]['comments'] as $tag_key => $valuearray) {
     1067                                        foreach ($valuearray as $key => $value) {
     1068                                                if (strlen(trim($value)) > 0) {
     1069                                                        $this->info['tags'][trim($tag_name)][trim($tag_key)][] = $value; // do not trim!! Unicode characters will get mangled if trailing nulls are removed!
     1070                                                }
     1071                                        }
     1072                                }
     1073
     1074                                if (!isset($this->info['tags'][$tag_name])) {
     1075                                        // comments are set but contain nothing but empty strings, so skip
     1076                                        continue;
     1077                                }
     1078
     1079                                if ($this->option_tags_html) {
     1080                                        foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) {
     1081                                                foreach ($valuearray as $key => $value) {
     1082                                                        if (is_string($value)) {
     1083                                                                //$this->info['tags_html'][$tag_name][$tag_key][$key] = getid3_lib::MultiByteCharString2HTML($value, $encoding);
     1084                                                                $this->info['tags_html'][$tag_name][$tag_key][$key] = str_replace('&#0;', '', getid3_lib::MultiByteCharString2HTML($value, $encoding));
     1085                                                        } else {
     1086                                                                $this->info['tags_html'][$tag_name][$tag_key][$key] = $value;
     1087                                                        }
     1088                                                }
     1089                                        }
     1090                                }
     1091
     1092                                $this->CharConvert($this->info['tags'][$tag_name], $encoding);           // only copy gets converted!
     1093                        }
     1094
     1095                }
     1096                return true;
     1097        }
     1098
     1099
     1100        function getHashdata($algorithm) {
     1101                switch ($algorithm) {
     1102                        case 'md5':
     1103                        case 'sha1':
     1104                                break;
     1105
     1106                        default:
     1107                                return $this->error('bad algorithm "'.$algorithm.'" in getHashdata()');
     1108                                break;
     1109                }
     1110
     1111                if ((@$this->info['fileformat'] == 'ogg') && (@$this->info['audio']['dataformat'] == 'vorbis')) {
     1112
     1113                        // We cannot get an identical md5_data value for Ogg files where the comments
     1114                        // span more than 1 Ogg page (compared to the same audio data with smaller
     1115                        // comments) using the normal getID3() method of MD5'ing the data between the
     1116                        // end of the comments and the end of the file (minus any trailing tags),
     1117                        // because the page sequence numbers of the pages that the audio data is on
     1118                        // do not match. Under normal circumstances, where comments are smaller than
     1119                        // the nominal 4-8kB page size, then this is not a problem, but if there are
     1120                        // very large comments, the only way around it is to strip off the comment
     1121                        // tags with vorbiscomment and MD5 that file.
     1122                        // This procedure must be applied to ALL Ogg files, not just the ones with
     1123                        // comments larger than 1 page, because the below method simply MD5's the
     1124                        // whole file with the comments stripped, not just the portion after the
     1125                        // comments block (which is the standard getID3() method.
     1126
     1127                        // The above-mentioned problem of comments spanning multiple pages and changing
     1128                        // page sequence numbers likely happens for OggSpeex and OggFLAC as well, but
     1129                        // currently vorbiscomment only works on OggVorbis files.
     1130
     1131                        if ((bool) ini_get('safe_mode')) {
     1132
     1133                                $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)';
     1134                                $this->info[$algorithm.'_data']  = false;
     1135
     1136                        } else {
     1137
     1138                                // Prevent user from aborting script
     1139                                $old_abort = ignore_user_abort(true);
     1140
     1141                                // Create empty file
     1142                                $empty = tempnam('*', 'getID3');
     1143                                touch($empty);
     1144
     1145
     1146                                // Use vorbiscomment to make temp file without comments
     1147                                $temp = tempnam('*', 'getID3');
     1148                                $file = $this->info['filenamepath'];
     1149
     1150                                if (GETID3_OS_ISWINDOWS) {
     1151
     1152                                        if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) {
     1153
     1154                                                $commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w -c "'.$empty.'" "'.$file.'" "'.$temp.'"';
     1155                                                $VorbisCommentError = `$commandline`;
     1156
     1157                                        } else {
     1158
     1159                                                $VorbisCommentError = 'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR;
     1160
     1161                                        }
     1162
     1163                                } else {
     1164
     1165                                        $commandline = 'vorbiscomment -w -c "'.$empty.'" "'.$file.'" "'.$temp.'" 2>&1';
     1166                                        $commandline = 'vorbiscomment -w -c '.escapeshellarg($empty).' '.escapeshellarg($file).' '.escapeshellarg($temp).' 2>&1';
     1167                                        $VorbisCommentError = `$commandline`;
     1168
     1169                                }
     1170
     1171                                if (!empty($VorbisCommentError)) {
     1172
     1173                                        $this->info['warning'][]         = 'Failed making system call to vorbiscomment(.exe) - '.$algorithm.'_data will be incorrect. If vorbiscomment is unavailable, please download from http://www.vorbis.com/download.psp and put in the getID3() directory. Error returned: '.$VorbisCommentError;
     1174                                        $this->info[$algorithm.'_data']  = false;
     1175
     1176                                } else {
     1177
     1178                                        // Get hash of newly created file
     1179                                        switch ($algorithm) {
     1180                                                case 'md5':
     1181                                                        $this->info[$algorithm.'_data'] = getid3_lib::md5_file($temp);
     1182                                                        break;
     1183
     1184                                                case 'sha1':
     1185                                                        $this->info[$algorithm.'_data'] = getid3_lib::sha1_file($temp);
     1186                                                        break;
     1187                                        }
     1188                                }
     1189
     1190                                // Clean up
     1191                                unlink($empty);
     1192                                unlink($temp);
     1193
     1194                                // Reset abort setting
     1195                                ignore_user_abort($old_abort);
     1196
     1197                        }
     1198
     1199                } else {
     1200
     1201                        if (!empty($this->info['avdataoffset']) || (isset($this->info['avdataend']) && ($this->info['avdataend'] < $this->info['filesize']))) {
     1202
     1203                                // get hash from part of file
     1204                                $this->info[$algorithm.'_data'] = getid3_lib::hash_data($this->info['filenamepath'], $this->info['avdataoffset'], $this->info['avdataend'], $algorithm);
     1205
     1206                        } else {
     1207
     1208                                // get hash from whole file
     1209                                switch ($algorithm) {
     1210                                        case 'md5':
     1211                                                $this->info[$algorithm.'_data'] = getid3_lib::md5_file($this->info['filenamepath']);
     1212                                                break;
     1213
     1214                                        case 'sha1':
     1215                                                $this->info[$algorithm.'_data'] = getid3_lib::sha1_file($this->info['filenamepath']);
     1216                                                break;
     1217                                }
     1218                        }
     1219
     1220                }
     1221                return true;
     1222        }
     1223
     1224
     1225        function ChannelsBitratePlaytimeCalculations() {
     1226
     1227                // set channelmode on audio
     1228                if (@$this->info['audio']['channels'] == '1') {
     1229                        $this->info['audio']['channelmode'] = 'mono';
     1230                } elseif (@$this->info['audio']['channels'] == '2') {
     1231                        $this->info['audio']['channelmode'] = 'stereo';
     1232                }
     1233
     1234                // Calculate combined bitrate - audio + video
     1235                $CombinedBitrate  = 0;
     1236                $CombinedBitrate += (isset($this->info['audio']['bitrate']) ? $this->info['audio']['bitrate'] : 0);
     1237                $CombinedBitrate += (isset($this->info['video']['bitrate']) ? $this->info['video']['bitrate'] : 0);
     1238                if (($CombinedBitrate > 0) && empty($this->info['bitrate'])) {
     1239                        $this->info['bitrate'] = $CombinedBitrate;
     1240                }
     1241                //if ((isset($this->info['video']) && !isset($this->info['video']['bitrate'])) || (isset($this->info['audio']) && !isset($this->info['audio']['bitrate']))) {
     1242                //      // for example, VBR MPEG video files cannot determine video bitrate:
     1243                //      // should not set overall bitrate and playtime from audio bitrate only
     1244                //      unset($this->info['bitrate']);
     1245                //}
     1246
     1247                // video bitrate undetermined, but calculable
     1248                if (isset($this->info['video']['dataformat']) && $this->info['video']['dataformat'] && (!isset($this->info['video']['bitrate']) || ($this->info['video']['bitrate'] == 0))) {
     1249                        // if video bitrate not set
     1250                        if (isset($this->info['audio']['bitrate']) && ($this->info['audio']['bitrate'] > 0) && ($this->info['audio']['bitrate'] == $this->info['bitrate'])) {
     1251                                // AND if audio bitrate is set to same as overall bitrate
     1252                                if (isset($this->info['playtime_seconds']) && ($this->info['playtime_seconds'] > 0)) {
     1253                                        // AND if playtime is set
     1254                                        if (isset($this->info['avdataend']) && isset($this->info['avdataoffset'])) {
     1255                                                // AND if AV data offset start/end is known
     1256                                                // THEN we can calculate the video bitrate
     1257                                                $this->info['bitrate'] = round((($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['playtime_seconds']);
     1258                                                $this->info['video']['bitrate'] = $this->info['bitrate'] - $this->info['audio']['bitrate'];
     1259                                        }
     1260                                }
     1261                        }
     1262                }
     1263
     1264                if ((!isset($this->info['playtime_seconds']) || ($this->info['playtime_seconds'] <= 0)) && !empty($this->info['bitrate'])) {
     1265                        $this->info['playtime_seconds'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['bitrate'];
     1266                }
     1267
     1268                if (!isset($this->info['bitrate']) && !empty($this->info['playtime_seconds'])) {
     1269                        $this->info['bitrate'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['playtime_seconds'];
     1270                }
     1271//echo '<pre>';
     1272//var_dump($this->info['bitrate']);
     1273//var_dump($this->info['audio']['bitrate']);
     1274//var_dump($this->info['video']['bitrate']);
     1275//echo '</pre>';
     1276                if (isset($this->info['bitrate']) && empty($this->info['audio']['bitrate']) && empty($this->info['video']['bitrate'])) {
     1277                        if (isset($this->info['audio']['dataformat']) && empty($this->info['video']['resolution_x'])) {
     1278                                // audio only
     1279                                $this->info['audio']['bitrate'] = $this->info['bitrate'];
     1280                        } elseif (isset($this->info['video']['resolution_x']) && empty($this->info['audio']['dataformat'])) {
     1281                                // video only
     1282                                $this->info['video']['bitrate'] = $this->info['bitrate'];
     1283                        }
     1284                }
     1285
     1286                // Set playtime string
     1287                if (!empty($this->info['playtime_seconds']) && empty($this->info['playtime_string'])) {
     1288                        $this->info['playtime_string'] = getid3_lib::PlaytimeString($this->info['playtime_seconds']);
     1289                }
     1290        }
     1291
     1292
     1293        function CalculateCompressionRatioVideo() {
     1294                if (empty($this->info['video'])) {
     1295                        return false;
     1296                }
     1297                if (empty($this->info['video']['resolution_x']) || empty($this->info['video']['resolution_y'])) {
     1298                        return false;
     1299                }
     1300                if (empty($this->info['video']['bits_per_sample'])) {
     1301                        return false;
     1302                }
     1303
     1304                switch ($this->info['video']['dataformat']) {
     1305                        case 'bmp':
     1306                        case 'gif':
     1307                        case 'jpeg':
     1308                        case 'jpg':
     1309                        case 'png':
     1310                        case 'tiff':
     1311                                $FrameRate = 1;
     1312                                $PlaytimeSeconds = 1;
     1313                                $BitrateCompressed = $this->info['filesize'] * 8;
     1314                                break;
     1315
     1316                        default:
     1317                                if (!empty($this->info['video']['frame_rate'])) {
     1318                                        $FrameRate = $this->info['video']['frame_rate'];
     1319                                } else {
     1320                                        return false;
     1321                                }
     1322                                if (!empty($this->info['playtime_seconds'])) {
     1323                                        $PlaytimeSeconds = $this->info['playtime_seconds'];
     1324                                } else {
     1325                                        return false;
     1326                                }
     1327                                if (!empty($this->info['video']['bitrate'])) {
     1328                                        $BitrateCompressed = $this->info['video']['bitrate'];
     1329                                } else {
     1330                                        return false;
     1331                                }
     1332                                break;
     1333                }
     1334                $BitrateUncompressed = $this->info['video']['resolution_x'] * $this->info['video']['resolution_y'] * $this->info['video']['bits_per_sample'] * $FrameRate;
     1335
     1336                $this->info['video']['compression_ratio'] = $BitrateCompressed / $BitrateUncompressed;
     1337                return true;
     1338        }
     1339
     1340
     1341        function CalculateCompressionRatioAudio() {
     1342                if (empty($this->info['audio']['bitrate']) || empty($this->info['audio']['channels']) || empty($this->info['audio']['sample_rate'])) {
     1343                        return false;
     1344                }
     1345                $this->info['audio']['compression_ratio'] = $this->info['audio']['bitrate'] / ($this->info['audio']['channels'] * $this->info['audio']['sample_rate'] * (!empty($this->info['audio']['bits_per_sample']) ? $this->info['audio']['bits_per_sample'] : 16));
     1346
     1347                if (!empty($this->info['audio']['streams'])) {
     1348                        foreach ($this->info['audio']['streams'] as $streamnumber => $streamdata) {
     1349                                if (!empty($streamdata['bitrate']) && !empty($streamdata['channels']) && !empty($streamdata['sample_rate'])) {
     1350                                        $this->info['audio']['streams'][$streamnumber]['compression_ratio'] = $streamdata['bitrate'] / ($streamdata['channels'] * $streamdata['sample_rate'] * (!empty($streamdata['bits_per_sample']) ? $streamdata['bits_per_sample'] : 16));
     1351                                }
     1352                        }
     1353                }
     1354                return true;
     1355        }
     1356
     1357
     1358        function CalculateReplayGain() {
     1359                if (isset($this->info['replay_gain'])) {
     1360                        $this->info['replay_gain']['reference_volume'] = 89;
     1361                        if (isset($this->info['replay_gain']['track']['adjustment'])) {
     1362                                $this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment'];
     1363                        }
     1364                        if (isset($this->info['replay_gain']['album']['adjustment'])) {
     1365                                $this->info['replay_gain']['album']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['album']['adjustment'];
     1366                        }
     1367
     1368                        if (isset($this->info['replay_gain']['track']['peak'])) {
     1369                                $this->info['replay_gain']['track']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['track']['peak']);
     1370                        }
     1371                        if (isset($this->info['replay_gain']['album']['peak'])) {
     1372                                $this->info['replay_gain']['album']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['album']['peak']);
     1373                        }
     1374                }
     1375                return true;
     1376        }
     1377
     1378        function ProcessAudioStreams() {
     1379                if (!empty($this->info['audio']['bitrate']) || !empty($this->info['audio']['channels']) || !empty($this->info['audio']['sample_rate'])) {
     1380                        if (!isset($this->info['audio']['streams'])) {
     1381                                foreach ($this->info['audio'] as $key => $value) {
     1382                                        if ($key != 'streams') {
     1383                                                $this->info['audio']['streams'][0][$key] = $value;
     1384                                        }
     1385                                }
     1386                        }
     1387                }
     1388                return true;
     1389        }
     1390
     1391        function getid3_tempnam() {
     1392                return tempnam($this->tempdir, 'gI3');
     1393        }
     1394
    11401395}
    11411396
    1142 
    1143 abstract class getid3_handler
    1144 {
    1145 
    1146     protected $getid3;                          // pointer
    1147 
    1148     protected $data_string_flag = false;        // analyzing filepointer or string
    1149     protected $data_string;                     // string to analyze
    1150     protected $data_string_position = 0;        // seek position in string
    1151 
    1152 
    1153     public function __construct(getID3 $getid3) {
    1154 
    1155         $this->getid3 = $getid3;
    1156     }
    1157 
    1158 
    1159     // Analyze from file pointer
    1160     abstract public function Analyze();
    1161 
    1162 
    1163 
    1164     // Analyze from string instead
    1165     public function AnalyzeString(&$string) {
    1166 
    1167         // Enter string mode
    1168         $this->data_string_flag = true;
    1169         $this->data_string      = $string;
    1170 
    1171         // Save info
    1172         $saved_avdataoffset = $this->getid3->info['avdataoffset'];
    1173         $saved_avdataend    = $this->getid3->info['avdataend'];
    1174         $saved_filesize     = $this->getid3->info['filesize'];
    1175 
    1176         // Reset some info
    1177         $this->getid3->info['avdataoffset'] = 0;
    1178         $this->getid3->info['avdataend']    = $this->getid3->info['filesize'] = strlen($string);
    1179 
    1180         // Analyze
    1181         $this->Analyze();
    1182 
    1183         // Restore some info
    1184         $this->getid3->info['avdataoffset'] = $saved_avdataoffset;
    1185         $this->getid3->info['avdataend']    = $saved_avdataend;
    1186         $this->getid3->info['filesize']     = $saved_filesize;
    1187 
    1188         // Exit string mode
    1189         $this->data_string_flag = false;
    1190     }
    1191 
    1192 
    1193     protected function ftell() {
    1194 
    1195         if ($this->data_string_flag) {
    1196             return $this->data_string_position;
    1197         }
    1198         return ftell($this->getid3->fp);
    1199     }
    1200 
    1201 
    1202     protected function fread($bytes) {
    1203 
    1204         if ($this->data_string_flag) {
    1205             $this->data_string_position += $bytes;
    1206             return substr($this->data_string, $this->data_string_position - $bytes, $bytes);
    1207         }
    1208         return fread($this->getid3->fp, $bytes);
    1209     }
    1210 
    1211 
    1212     protected function fseek($bytes, $whence = SEEK_SET) {
    1213 
    1214         if ($this->data_string_flag) {
    1215             switch ($whence) {
    1216                 case SEEK_SET:
    1217                     $this->data_string_position = $bytes;
    1218                     return;
    1219 
    1220                 case SEEK_CUR:
    1221                     $this->data_string_position += $bytes;
    1222                     return;
    1223 
    1224                 case SEEK_END:
    1225                     $this->data_string_position = strlen($this->data_string) + $bytes;
    1226                     return;
    1227             }
    1228         }
    1229         return fseek($this->getid3->fp, $bytes, $whence);
    1230     }
    1231 
    1232 }
    1233 
    1234 
    1235 
    1236 
    1237 abstract class getid3_handler_write
    1238 {
    1239     protected $filename;
    1240     protected $user_abort;
    1241 
    1242     private $fp_lock;
    1243     private $owner;
    1244     private $group;
    1245     private $perms;
    1246 
    1247 
    1248     public function __construct($filename) {
    1249 
    1250         if (!file_exists($filename)) {
    1251             throw new getid3_exception('File does not exist: "' . $filename . '"');
    1252         }
    1253 
    1254         if (!is_writeable($filename)) {
    1255             throw new getid3_exception('File is not writeable: "' . $filename . '"');
    1256         }
    1257 
    1258         if (!is_writeable(dirname($filename))) {
    1259             throw new getid3_exception('Directory is not writeable: ' . dirname($filename) . ' (need to write lock file).');
    1260         }
    1261 
    1262         $this->user_abort = ignore_user_abort(true);
    1263 
    1264         $this->fp_lock = fopen($filename . '.getid3.lock', 'w');
    1265         flock($this->fp_lock, LOCK_EX);
    1266 
    1267         $this->filename = $filename;
    1268     }
    1269 
    1270 
    1271     public function __destruct() {
    1272 
    1273         flock($this->fp_lock, LOCK_UN);
    1274         fclose($this->fp_lock);
    1275         unlink($this->filename . '.getid3.lock');
    1276 
    1277         ignore_user_abort($this->user_abort);
    1278     }
    1279    
    1280    
    1281     protected function save_permissions() {
    1282        
    1283         $this->owner = fileowner($this->filename);
    1284         $this->group = filegroup($this->filename);
    1285         $this->perms = fileperms($this->filename);
    1286     }
    1287    
    1288    
    1289     protected function restore_permissions() {
    1290        
    1291         @chown($this->filename, $this->owner);
    1292         @chgrp($this->filename, $this->group);
    1293         @chmod($this->filename, $this->perms);
    1294     }
    1295 
    1296 
    1297     abstract public function read();
    1298 
    1299     abstract public function write();
    1300 
    1301     abstract public function remove();
    1302 
    1303 }
    1304 
    1305 
    1306 
    1307 
    1308 class getid3_exception extends Exception
    1309 {
    1310     public $message;
    1311 
    1312 }
    1313 
    1314 
    1315 
    1316 
    1317 class getid3_lib
    1318 {
    1319 
    1320     // Convert Little Endian byte string to int - max 32 bits
    1321     public static function LittleEndian2Int($byte_word, $signed = false) {
    1322 
    1323         return getid3_lib::BigEndian2Int(strrev($byte_word), $signed);
    1324     }
    1325 
    1326 
    1327 
    1328     // Convert number to Little Endian byte string
    1329     public static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) {
    1330         $intstring = '';
    1331         while ($number > 0) {
    1332             if ($synchsafe) {
    1333                 $intstring = $intstring.chr($number & 127);
    1334                 $number >>= 7;
    1335             } else {
    1336                 $intstring = $intstring.chr($number & 255);
    1337                 $number >>= 8;
    1338             }
    1339         }
    1340         return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
    1341     }
    1342 
    1343 
    1344 
    1345     // Convert Big Endian byte string to int - max 32 bits
    1346     public static function BigEndian2Int($byte_word, $signed = false) {
    1347 
    1348         $int_value = 0;
    1349         $byte_wordlen = strlen($byte_word);
    1350 
    1351         for ($i = 0; $i < $byte_wordlen; $i++) {
    1352             $int_value += ord($byte_word{$i}) * pow(256, ($byte_wordlen - 1 - $i));
    1353         }
    1354 
    1355         if ($signed) {
    1356             $sign_mask_bit = 0x80 << (8 * ($byte_wordlen - 1));
    1357             if ($int_value & $sign_mask_bit) {
    1358                 $int_value = 0 - ($int_value & ($sign_mask_bit - 1));
    1359             }
    1360         }
    1361 
    1362         return $int_value;
    1363     }
    1364 
    1365 
    1366 
    1367     // Convert Big Endian byte sybc safe string to int - max 32 bits
    1368     public static function BigEndianSyncSafe2Int($byte_word) {
    1369 
    1370         $int_value = 0;
    1371         $byte_wordlen = strlen($byte_word);
    1372 
    1373         // disregard MSB, effectively 7-bit bytes
    1374         for ($i = 0; $i < $byte_wordlen; $i++) {
    1375             $int_value = $int_value | (ord($byte_word{$i}) & 0x7F) << (($byte_wordlen - 1 - $i) * 7);
    1376         }
    1377         return $int_value;
    1378     }
    1379 
    1380 
    1381 
    1382     // Convert Big Endian byte string to bit string
    1383     public static function BigEndian2Bin($byte_word) {
    1384 
    1385         $bin_value = '';
    1386         $byte_wordlen = strlen($byte_word);
    1387         for ($i = 0; $i < $byte_wordlen; $i++) {
    1388             $bin_value .= str_pad(decbin(ord($byte_word{$i})), 8, '0', STR_PAD_LEFT);
    1389         }
    1390         return $bin_value;
    1391     }
    1392 
    1393 
    1394 
    1395     public static function BigEndian2Float($byte_word) {
    1396 
    1397                 // ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic
    1398                 // http://www.psc.edu/general/software/packages/ieee/ieee.html
    1399                 // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html
    1400 
    1401                 $bit_word = getid3_lib::BigEndian2Bin($byte_word);
    1402                 if (!$bit_word) {
    1403             return 0;
    1404         }
    1405                 $sign_bit = $bit_word{0};
    1406 
    1407                 switch (strlen($byte_word) * 8) {
    1408                         case 32:
    1409                                 $exponent_bits = 8;
    1410                                 $fraction_bits = 23;
    1411                                 break;
    1412 
    1413                         case 64:
    1414                                 $exponent_bits = 11;
    1415                                 $fraction_bits = 52;
    1416                                 break;
    1417 
    1418                         case 80:
    1419                                 // 80-bit Apple SANE format
    1420                                 // http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/
    1421                                 $exponent_string = substr($bit_word, 1, 15);
    1422                                 $is_normalized = intval($bit_word{16});
    1423                                 $fraction_string = substr($bit_word, 17, 63);
    1424                                 $exponent = pow(2, getid3_lib::Bin2Dec($exponent_string) - 16383);
    1425                                 $fraction = $is_normalized + getid3_lib::DecimalBinary2Float($fraction_string);
    1426                                 $float_value = $exponent * $fraction;
    1427                                 if ($sign_bit == '1') {
    1428                                         $float_value *= -1;
    1429                                 }
    1430                                 return $float_value;
    1431                                 break;
    1432 
    1433                         default:
    1434                                 return false;
    1435                                 break;
    1436                 }
    1437                 $exponent_string = substr($bit_word, 1, $exponent_bits);
    1438                 $fraction_string = substr($bit_word, $exponent_bits + 1, $fraction_bits);
    1439                 $exponent = bindec($exponent_string);
    1440                 $fraction = bindec($fraction_string);
    1441 
    1442                 if (($exponent == (pow(2, $exponent_bits) - 1)) && ($fraction != 0)) {
    1443                         // Not a Number
    1444                         $float_value = false;
    1445                 } elseif (($exponent == (pow(2, $exponent_bits) - 1)) && ($fraction == 0)) {
    1446                         if ($sign_bit == '1') {
    1447                                 $float_value = '-infinity';
    1448                         } else {
    1449                                 $float_value = '+infinity';
    1450                         }
    1451                 } elseif (($exponent == 0) && ($fraction == 0)) {
    1452                         if ($sign_bit == '1') {
    1453                                 $float_value = -0;
    1454                         } else {
    1455                                 $float_value = 0;
    1456                         }
    1457                         $float_value = ($sign_bit ? 0 : -0);
    1458                 } elseif (($exponent == 0) && ($fraction != 0)) {
    1459                         // These are 'unnormalized' values
    1460                         $float_value = pow(2, (-1 * (pow(2, $exponent_bits - 1) - 2))) * getid3_lib::DecimalBinary2Float($fraction_string);
    1461                         if ($sign_bit == '1') {
    1462                                 $float_value *= -1;
    1463                         }
    1464                 } elseif ($exponent != 0) {
    1465                         $float_value = pow(2, ($exponent - (pow(2, $exponent_bits - 1) - 1))) * (1 + getid3_lib::DecimalBinary2Float($fraction_string));
    1466                         if ($sign_bit == '1') {
    1467                                 $float_value *= -1;
    1468                         }
    1469                 }
    1470                 return (float) $float_value;
    1471         }
    1472 
    1473 
    1474 
    1475         public static function LittleEndian2Float($byte_word) {
    1476 
    1477                 return getid3_lib::BigEndian2Float(strrev($byte_word));
    1478         }
    1479 
    1480 
    1481 
    1482         public static function DecimalBinary2Float($binary_numerator) {
    1483                 $numerator   = bindec($binary_numerator);
    1484                 $denominator = bindec('1'.str_repeat('0', strlen($binary_numerator)));
    1485                 return ($numerator / $denominator);
    1486         }
    1487 
    1488 
    1489         public static function PrintHexBytes($string, $hex=true, $spaces=true, $html_safe=true) {
    1490 
    1491         $return_string = '';
    1492         for ($i = 0; $i < strlen($string); $i++) {
    1493             if ($hex) {
    1494                 $return_string .= str_pad(dechex(ord($string{$i})), 2, '0', STR_PAD_LEFT);
    1495             } else {
    1496                 $return_string .= ' '.(ereg("[\x20-\x7E]", $string{$i}) ? $string{$i} : '¤');
    1497             }
    1498             if ($spaces) {
    1499                 $return_string .= ' ';
    1500             }
    1501         }
    1502         if ($html_safe) {
    1503             $return_string = htmlentities($return_string);
    1504         }
    1505         return $return_string;
    1506     }
    1507 
    1508 
    1509 
    1510     // Process header data string - read several values with algorithm and add to target
    1511     //   algorithm is one one the getid3_lib::Something2Something() function names
    1512     //   parts_array is  index => length    -  $target[index] = algorithm(substring(data))
    1513     //   - OR just substring(data) if length is negative!
    1514     //  indexes == 'IGNORE**' are ignored
    1515 
    1516     public static function ReadSequence($algorithm, &$target, &$data, $offset, $parts_array) {
    1517 
    1518         // Loop thru $parts_array
    1519         foreach ($parts_array as $target_string => $length) {
    1520 
    1521             // Add to target
    1522             if (!strstr($target_string, 'IGNORE')) {
    1523 
    1524                 // substr(....length)
    1525                 if ($length < 0) {
    1526                     $target[$target_string] = substr($data, $offset, -$length);
    1527                 }
    1528 
    1529                 // algorithm(substr(...length))
    1530                 else {
    1531                     $target[$target_string] = getid3_lib::$algorithm(substr($data, $offset, $length));
    1532                 }
    1533             }
    1534 
    1535             // Move pointer
    1536             $offset += abs($length);
    1537         }
    1538     }
    1539 
    1540 }
    1541 
    1542 
    1543 
    1544 class getid3_lib_replaygain
    1545 {
    1546 
    1547     public static function NameLookup($name_code) {
    1548 
    1549         static $lookup = array (
    1550             0 => 'not set',
    1551             1 => 'Track Gain Adjustment',
    1552             2 => 'Album Gain Adjustment'
    1553         );
    1554 
    1555         return @$lookup[$name_code];
    1556     }
    1557 
    1558 
    1559 
    1560     public static function OriginatorLookup($originator_code) {
    1561 
    1562         static $lookup = array (
    1563             0 => 'unspecified',
    1564             1 => 'pre-set by artist/producer/mastering engineer',
    1565             2 => 'set by user',
    1566             3 => 'determined automatically'
    1567         );
    1568 
    1569         return @$lookup[$originator_code];
    1570     }
    1571 
    1572 
    1573 
    1574     public static function AdjustmentLookup($raw_adjustment, $sign_bit) {
    1575 
    1576         return (float)$raw_adjustment / 10 * ($sign_bit == 1 ? -1 : 1);
    1577     }
    1578 
    1579 
    1580 
    1581     public static function GainString($name_code, $originator_code, $replaygain) {
    1582 
    1583         $sign_bit = $replaygain < 0 ? 1 : 0;
    1584 
    1585         $stored_replaygain = intval(round($replaygain * 10));
    1586         $gain_string  = str_pad(decbin($name_code), 3, '0', STR_PAD_LEFT);
    1587         $gain_string .= str_pad(decbin($originator_code), 3, '0', STR_PAD_LEFT);
    1588         $gain_string .= $sign_bit;
    1589         $gain_string .= str_pad(decbin($stored_replaygain), 9, '0', STR_PAD_LEFT);
    1590 
    1591         return $gain_string;
    1592     }
    1593 
    1594 }
    1595 
    1596 
    1597 
    1598 
    15991397?>
  • extensions/charlies_content/getid3/getid3/module.archive.gzip.php

    r3318 r3544  
    11<?php
    2 // +----------------------------------------------------------------------+
    3 // | PHP version 5                                                        |
    4 // +----------------------------------------------------------------------+
    5 // | Copyright (c) 2002-2006 James Heinrich, Allan Hansen                 |
    6 // +----------------------------------------------------------------------+
    7 // | This source file is subject to version 2 of the GPL license,         |
    8 // | that is bundled with this package in the file license.txt and is     |
    9 // | available through the world-wide-web at the following url:           |
    10 // | http://www.gnu.org/copyleft/gpl.html                                 |
    11 // +----------------------------------------------------------------------+
    12 // | getID3() - http://getid3.sourceforge.net or http://www.getid3.org    |
    13 // +----------------------------------------------------------------------+
    14 // | Authors: James Heinrich <infoØgetid3*org>                            |
    15 // |          Allan Hansen <ahØartemis*dk>                                |
    16 // +----------------------------------------------------------------------+
    17 // | module.archive.gzip.php                                              |
    18 // | module for analyzing GZIP files                                      |
    19 // | dependencies: PHP compiled with zlib support (optional)              |
    20 // +----------------------------------------------------------------------+
    21 // | Module originally written by Mike Mozolin <teddybearØmail*ru>        |
    22 // +----------------------------------------------------------------------+
    23 //
    24 // $Id$
    25 
    26        
    27        
    28 class getid3_gzip extends getid3_handler
    29 {
    30 
    31     // public: Optional file list - disable for speed.
    32     public $option_gzip_parse_contents = true; // decode gzipped files, if possible, and parse recursively (.tar.gz for example)
    33 
    34    
    35     // Reads the gzip-file
    36     function Analyze() {
    37 
    38         $info = &$this->getid3->info;
    39 
    40         $info['fileformat'] = 'gzip';
    41 
    42         $start_length = 10;
    43         $unpack_header = 'a1id1/a1id2/a1cmethod/a1flags/a4mtime/a1xflags/a1os';
    44        
    45         //+---+---+---+---+---+---+---+---+---+---+
    46         //|ID1|ID2|CM |FLG|     MTIME     |XFL|OS |
    47         //+---+---+---+---+---+---+---+---+---+---+
    48        
    49         @fseek($this->getid3->fp, 0);
    50         $buffer = @fread($this->getid3->fp, $info['filesize']);
    51 
    52         $arr_members = explode("\x1F\x8B\x08", $buffer);
    53        
    54         while (true) {
    55             $is_wrong_members = false;
    56             $num_members = intval(count($arr_members));
    57             for ($i = 0; $i < $num_members; $i++) {
    58                 if (strlen($arr_members[$i]) == 0) {
    59                     continue;
    60                 }
    61                 $buf = "\x1F\x8B\x08".$arr_members[$i];
    62 
    63                 $attr = unpack($unpack_header, substr($buf, 0, $start_length));
    64                 if (!$this->get_os_type(ord($attr['os']))) {
    65        
    66                     // Merge member with previous if wrong OS type
    67                     $arr_members[$i - 1] .= $buf;
    68                     $arr_members[$i] = '';
    69                     $is_wrong_members = true;
    70                     continue;
    71                 }
    72             }
    73             if (!$is_wrong_members) {
    74                 break;
    75             }
    76         }
    77 
    78         $fpointer = 0;
    79         $idx = 0;
    80         for ($i = 0; $i < $num_members; $i++) {
    81             if (strlen($arr_members[$i]) == 0) {
    82                 continue;
    83             }
    84             $info_gzip_member_header_idx = &$info['gzip']['member_header'][++$idx];
    85 
    86             $buff = "\x1F\x8B\x08".$arr_members[$i];
    87 
    88             $attr = unpack($unpack_header, substr($buff, 0, $start_length));
    89             $info_gzip_member_header_idx['filemtime']      = getid3_lib::LittleEndian2Int($attr['mtime']);
    90             $info_gzip_member_header_idx['raw']['id1']     = ord($attr['cmethod']);
    91             $info_gzip_member_header_idx['raw']['id2']     = ord($attr['cmethod']);
    92             $info_gzip_member_header_idx['raw']['cmethod'] = ord($attr['cmethod']);
    93             $info_gzip_member_header_idx['raw']['os']      = ord($attr['os']);
    94             $info_gzip_member_header_idx['raw']['xflags']  = ord($attr['xflags']);
    95             $info_gzip_member_header_idx['raw']['flags']   = ord($attr['flags']);
    96 
    97             $info_gzip_member_header_idx['flags']['crc16']    = (bool) ($info_gzip_member_header_idx['raw']['flags'] & 0x02);
    98             $info_gzip_member_header_idx['flags']['extra']    = (bool) ($info_gzip_member_header_idx['raw']['flags'] & 0x04);
    99             $info_gzip_member_header_idx['flags']['filename'] = (bool) ($info_gzip_member_header_idx['raw']['flags'] & 0x08);
    100             $info_gzip_member_header_idx['flags']['comment']  = (bool) ($info_gzip_member_header_idx['raw']['flags'] & 0x10);
    101 
    102             $info_gzip_member_header_idx['compression'] = $this->get_xflag_type($info_gzip_member_header_idx['raw']['xflags']);
    103 
    104             $info_gzip_member_header_idx['os'] = $this->get_os_type($info_gzip_member_header_idx['raw']['os']);
    105             if (!$info_gzip_member_header_idx['os']) {
    106                 $info['error'][] = 'Read error on gzip file';
    107                 return false;
    108             }
    109 
    110             $fpointer = 10;
    111             $arr_xsubfield = array ();
    112            
    113             // bit 2 - FLG.FEXTRA
    114             //+---+---+=================================+
    115             //| XLEN  |...XLEN bytes of "extra field"...|
    116             //+---+---+=================================+
    117            
    118             if ($info_gzip_member_header_idx['flags']['extra']) {
    119                 $w_xlen = substr($buff, $fpointer, 2);
    120                 $xlen = getid3_lib::LittleEndian2Int($w_xlen);
    121                 $fpointer += 2;
    122 
    123                 $info_gzip_member_header_idx['raw']['xfield'] = substr($buff, $fpointer, $xlen);
    124            
    125                 // Extra SubFields
    126                 //+---+---+---+---+==================================+
    127                 //|SI1|SI2|  LEN  |... LEN bytes of subfield data ...|
    128                 //+---+---+---+---+==================================+
    129            
    130                 $idx = 0;
    131                 while (true) {
    132                     if ($idx >= $xlen) {
    133                         break;
    134                     }
    135                     $si1 = ord(substr($buff, $fpointer + $idx++, 1));
    136                     $si2 = ord(substr($buff, $fpointer + $idx++, 1));
    137                     if (($si1 == 0x41) && ($si2 == 0x70)) {
    138                         $w_xsublen = substr($buff, $fpointer+$idx, 2);
    139                         $xsublen = getid3_lib::LittleEndian2Int($w_xsublen);
    140                         $idx += 2;
    141                         $arr_xsubfield[] = substr($buff, $fpointer+$idx, $xsublen);
    142                         $idx += $xsublen;
    143                     } else {
    144                         break;
    145                     }
    146                 }
    147                 $fpointer += $xlen;
    148             }
    149            
    150             // bit 3 - FLG.FNAME
    151             //+=========================================+
    152             //|...original file name, zero-terminated...|
    153             //+=========================================+
    154             // GZIP files may have only one file, with no filename, so assume original filename is current filename without .gz
    155            
    156             $info_gzip_member_header_idx['filename'] = eregi_replace('.gz$', '', @$info['filename']);
    157             if ($info_gzip_member_header_idx['flags']['filename']) {
    158                 while (true) {
    159                     if (ord($buff[$fpointer]) == 0) {
    160                         $fpointer++;
    161                         break;
    162                     }
    163                     $info_gzip_member_header_idx['filename'] .= $buff[$fpointer];
    164                     $fpointer++;
    165                 }
    166             }
    167            
    168             // bit 4 - FLG.FCOMMENT
    169             //+===================================+
    170             //|...file comment, zero-terminated...|
    171             //+===================================+
    172            
    173             if ($info_gzip_member_header_idx['flags']['comment']) {
    174                 while (true) {
    175                     if (ord($buff[$fpointer]) == 0) {
    176                         $fpointer++;
    177                         break;
    178                     }
    179                     $info_gzip_member_header_idx['comment'] .= $buff[$fpointer];
    180                     $fpointer++;
    181                 }
    182             }
    183            
    184             // bit 1 - FLG.FHCRC
    185             //+---+---+
    186             //| CRC16 |
    187             //+---+---+
    188            
    189             if ($info_gzip_member_header_idx['flags']['crc16']) {
    190                 $w_crc = substr($buff, $fpointer, 2);
    191                 $info_gzip_member_header_idx['crc16'] = getid3_lib::LittleEndian2Int($w_crc);
    192                 $fpointer += 2;
    193             }
    194            
    195             // bit 0 - FLG.FTEXT
    196             //if ($info_gzip_member_header_idx['raw']['flags'] & 0x01) {
    197             //  Ignored...
    198             //}
    199             // bits 5, 6, 7 - reserved
    200 
    201             $info_gzip_member_header_idx['crc32']    = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 8, 4));
    202             $info_gzip_member_header_idx['filesize'] = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 4));
    203 
    204             if ($this->option_gzip_parse_contents) {
    205 
    206                 // Try to inflate GZip
    207                
    208                 if (!function_exists('gzinflate')) {
    209                     $this->getid3->warning('PHP does not have zlib support - contents not parsed.');
    210                     return true;
    211                 }
    212 
    213                 $csize = 0;
    214                 $inflated = '';
    215                 $chkcrc32 = '';
    216 
    217                 $cdata = substr($buff, $fpointer);
    218                 $cdata = substr($cdata, 0, strlen($cdata) - 8);
    219                 $csize = strlen($cdata);
    220                 $inflated = gzinflate($cdata);
    221 
    222                 // Calculate CRC32 for inflated content
    223                 $info_gzip_member_header_idx['crc32_valid'] = (bool) (sprintf('%u', crc32($inflated)) == $info_gzip_member_header_idx['crc32']);
    224 
    225                
    226                 //// Analyse contents
    227                
    228                 // write content to temp file
    229                 if (($temp_file_name = tempnam('*', 'getID3'))  === false) {
    230                     throw new getid3_exception('Unable to create temporary file.');
    231                 }
    232 
    233                 if ($tmp = fopen($temp_file_name, 'wb')) {
    234                     fwrite($tmp, $inflated);
    235                     fclose($tmp);
    236                    
    237                     // clone getid3 - we want same settings
    238                     $clone = clone $this->getid3;
    239                     unset($clone->info);
    240                     try {
    241                         $clone->Analyze($temp_file_name);
    242                         $info_gzip_member_header_idx['parsed_content'] = $clone->info;
    243                     }
    244                     catch (getid3_exception $e) {
    245                         // unable to parse contents
    246                     }
    247                    
    248                     unlink($temp_file_name);
    249                 }
    250            
    251                 // Unknown/unhandled format
    252                 else {
    253                                        
    254                 }
    255             }
    256         }
    257         return true;
    258     }
    259 
    260 
    261     // Converts the OS type
    262     public static function get_os_type($key) {
    263         static $os_type = array (
    264             '0'   => 'FAT filesystem (MS-DOS, OS/2, NT/Win32)',
    265             '1'   => 'Amiga',
    266             '2'   => 'VMS (or OpenVMS)',
    267             '3'   => 'Unix',
    268             '4'   => 'VM/CMS',
    269             '5'   => 'Atari TOS',
    270             '6'   => 'HPFS filesystem (OS/2, NT)',
    271             '7'   => 'Macintosh',
    272             '8'   => 'Z-System',
    273             '9'   => 'CP/M',
    274             '10'  => 'TOPS-20',
    275             '11'  => 'NTFS filesystem (NT)',
    276             '12'  => 'QDOS',
    277             '13'  => 'Acorn RISCOS',
    278             '255' => 'unknown'
    279         );
    280         return @$os_type[$key];
    281     }
    282 
    283 
    284     // Converts the eXtra FLags
    285     public static function get_xflag_type($key) {
    286         static $xflag_type = array (
    287             '0' => 'unknown',
    288             '2' => 'maximum compression',
    289             '4' => 'fastest algorithm'
    290         );
    291         return @$xflag_type[$key];
    292     }
    293    
     2/////////////////////////////////////////////////////////////////
     3/// getID3() by James Heinrich <info@getid3.org>               //
     4//  available at http://getid3.sourceforge.net                 //
     5//            or http://www.getid3.org                         //
     6/////////////////////////////////////////////////////////////////
     7// See readme.txt for more details                             //
     8/////////////////////////////////////////////////////////////////
     9//                                                             //
     10// module.archive.gzip.php                                     //
     11// module for analyzing GZIP files                             //
     12// dependencies: NONE                                          //
     13//                                                            ///
     14/////////////////////////////////////////////////////////////////
     15//                                                             //
     16// Module originally written by                                //
     17//      Mike Mozolin <teddybearØmail*ru>                       //
     18//                                                             //
     19/////////////////////////////////////////////////////////////////
     20
     21
     22class getid3_gzip {
     23
     24        // public: Optional file list - disable for speed.
     25        var $option_gzip_parse_contents = false; // decode gzipped files, if possible, and parse recursively (.tar.gz for example)
     26
     27        function getid3_gzip(&$fd, &$ThisFileInfo) {
     28                $ThisFileInfo['fileformat'] = 'gzip';
     29
     30                $start_length = 10;
     31                $unpack_header = 'a1id1/a1id2/a1cmethod/a1flags/a4mtime/a1xflags/a1os';
     32                //+---+---+---+---+---+---+---+---+---+---+
     33                //|ID1|ID2|CM |FLG|     MTIME     |XFL|OS |
     34                //+---+---+---+---+---+---+---+---+---+---+
     35                @fseek($fd, 0);
     36                $buffer = @fread($fd, $ThisFileInfo['filesize']);
     37
     38                $arr_members = explode("\x1F\x8B\x08", $buffer);
     39                while (true) {
     40                        $is_wrong_members = false;
     41                        $num_members = intval(count($arr_members));
     42                        for ($i = 0; $i < $num_members; $i++) {
     43                                if (strlen($arr_members[$i]) == 0) {
     44                                        continue;
     45                                }
     46                                $buf = "\x1F\x8B\x08".$arr_members[$i];
     47
     48                                $attr = unpack($unpack_header, substr($buf, 0, $start_length));
     49                                if (!$this->get_os_type(ord($attr['os']))) {
     50                                        // Merge member with previous if wrong OS type
     51                                        $arr_members[$i - 1] .= $buf;
     52                                        $arr_members[$i] = '';
     53                                        $is_wrong_members = true;
     54                                        continue;
     55                                }
     56                        }
     57                        if (!$is_wrong_members) {
     58                                break;
     59                        }
     60                }
     61
     62                $ThisFileInfo['gzip']['files'] = array();
     63
     64                $fpointer = 0;
     65                $idx = 0;
     66                for ($i = 0; $i < $num_members; $i++) {
     67                        if (strlen($arr_members[$i]) == 0) {
     68                                continue;
     69                        }
     70                        $thisThisFileInfo = &$ThisFileInfo['gzip']['member_header'][++$idx];
     71
     72                        $buff = "\x1F\x8B\x08".$arr_members[$i];
     73
     74                        $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';
     93                                return false;
     94                        }
     95
     96                        $fpointer = 10;
     97                        $arr_xsubfield = array();
     98                        // bit 2 - FLG.FEXTRA
     99                        //+---+---+=================================+
     100                        //| XLEN  |...XLEN bytes of "extra field"...|
     101                        //+---+---+=================================+
     102                        if ($thisThisFileInfo['flags']['extra']) {
     103                                $w_xlen = substr($buff, $fpointer, 2);
     104                                $xlen = getid3_lib::LittleEndian2Int($w_xlen);
     105                                $fpointer += 2;
     106
     107                                $thisThisFileInfo['raw']['xfield'] = substr($buff, $fpointer, $xlen);
     108                                // Extra SubFields
     109                                //+---+---+---+---+==================================+
     110                                //|SI1|SI2|  LEN  |... LEN bytes of subfield data ...|
     111                                //+---+---+---+---+==================================+
     112                                $idx = 0;
     113                                while (true) {
     114                                        if ($idx >= $xlen) {
     115                                                break;
     116                                        }
     117                                        $si1 = ord(substr($buff, $fpointer + $idx++, 1));
     118                                        $si2 = ord(substr($buff, $fpointer + $idx++, 1));
     119                                        if (($si1 == 0x41) && ($si2 == 0x70)) {
     120                                                $w_xsublen = substr($buff, $fpointer + $idx, 2);
     121                                                $xsublen = getid3_lib::LittleEndian2Int($w_xsublen);
     122                                                $idx += 2;
     123                                                $arr_xsubfield[] = substr($buff, $fpointer + $idx, $xsublen);
     124                                                $idx += $xsublen;
     125                                        } else {
     126                                                break;
     127                                        }
     128                                }
     129                                $fpointer += $xlen;
     130                        }
     131                        // bit 3 - FLG.FNAME
     132                        //+=========================================+
     133                        //|...original file name, zero-terminated...|
     134                        //+=========================================+
     135                        // GZIP files may have only one file, with no filename, so assume original filename is current filename without .gz
     136                        $thisThisFileInfo['filename'] = eregi_replace('.gz$', '', $ThisFileInfo['filename']);
     137                        if ($thisThisFileInfo['flags']['filename']) {
     138                                while (true) {
     139                                        if (ord($buff[$fpointer]) == 0) {
     140                                                $fpointer++;
     141                                                break;
     142                                        }
     143                                        $thisThisFileInfo['filename'] .= $buff[$fpointer];
     144                                        $fpointer++;
     145                                }
     146                        }
     147                        // bit 4 - FLG.FCOMMENT
     148                        //+===================================+
     149                        //|...file comment, zero-terminated...|
     150                        //+===================================+
     151                        if ($thisThisFileInfo['flags']['comment']) {
     152                                while (true) {
     153                                        if (ord($buff[$fpointer]) == 0) {
     154                                                $fpointer++;
     155                                                break;
     156                                        }
     157                                        $thisThisFileInfo['comment'] .= $buff[$fpointer];
     158                                        $fpointer++;
     159                                }
     160                        }
     161                        // bit 1 - FLG.FHCRC
     162                        //+---+---+
     163                        //| CRC16 |
     164                        //+---+---+
     165                        if ($thisThisFileInfo['flags']['crc16']) {
     166                                $w_crc = substr($buff, $fpointer, 2);
     167                                $thisThisFileInfo['crc16'] = getid3_lib::LittleEndian2Int($w_crc);
     168                                $fpointer += 2;
     169                        }
     170                        // bit 0 - FLG.FTEXT
     171                        //if ($thisThisFileInfo['raw']['flags'] & 0x01) {
     172                        //      Ignored...
     173                        //}
     174                        // bits 5, 6, 7 - reserved
     175
     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']));
     180
     181                        if ($this->option_gzip_parse_contents) {
     182                                // Try to inflate GZip
     183                                $csize = 0;
     184                                $inflated = '';
     185                                $chkcrc32 = '';
     186                                if (function_exists('gzinflate')) {
     187                                        $cdata = substr($buff, $fpointer);
     188                                        $cdata = substr($cdata, 0, strlen($cdata) - 8);
     189                                        $csize = strlen($cdata);
     190                                        $inflated = gzinflate($cdata);
     191
     192                                        // Calculate CRC32 for inflated content
     193                                        $thisThisFileInfo['crc32_valid'] = (bool) (sprintf('%u', crc32($inflated)) == $thisThisFileInfo['crc32']);
     194
     195                                        // determine format
     196                                        $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                                                        // 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) {
     207                                                                        // can't find anywhere to create a temp file, abort
     208                                                                        $ThisFileInfo['error'][] = 'Unable to create temp file to parse TAR inside GZIP file';
     209                                                                        break;
     210                                                                }
     211                                                                if ($fp_temp_tar = fopen($temp_tar_filename, 'w+b')) {
     212                                                                        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);
     218                                                                        fclose($fp_temp_tar);
     219                                                                        unlink($temp_tar_filename);
     220                                                                } else {
     221                                                                        $ThisFileInfo['error'][] = 'Unable to fopen() temp file to parse TAR inside GZIP file';
     222                                                                        break;
     223                                                                }
     224                                                        }
     225                                                        break;
     226
     227                                        case '':
     228                                        default:
     229                                                // unknown or unhandled format
     230                                                break;
     231                                        }
     232                                }
     233                        }
     234                }
     235                return true;
     236        }
     237
     238        // Converts the OS type
     239        function get_os_type($key) {
     240                static $os_type = array(
     241                        '0'   => 'FAT filesystem (MS-DOS, OS/2, NT/Win32)',
     242                        '1'   => 'Amiga',
     243                        '2'   => 'VMS (or OpenVMS)',
     244                        '3'   => 'Unix',
     245                        '4'   => 'VM/CMS',
     246                        '5'   => 'Atari TOS',
     247                        '6'   => 'HPFS filesystem (OS/2, NT)',
     248                        '7'   => 'Macintosh',
     249                        '8'   => 'Z-System',
     250                        '9'   => 'CP/M',
     251                        '10'  => 'TOPS-20',
     252                        '11'  => 'NTFS filesystem (NT)',
     253                        '12'  => 'QDOS',
     254                        '13'  => 'Acorn RISCOS',
     255                        '255' => 'unknown'
     256                );
     257                return @$os_type[$key];
     258        }
     259
     260        // Converts the eXtra FLags
     261        function get_xflag_type($key) {
     262                static $xflag_type = array(
     263                        '0' => 'unknown',
     264                        '2' => 'maximum compression',
     265                        '4' => 'fastest algorithm'
     266                );
     267                return @$xflag_type[$key];
     268        }
    294269}
    295270
  • extensions/charlies_content/getid3/getid3/module.archive.szip.php

    r3318 r3544  
    11<?php
    2 // +----------------------------------------------------------------------+
    3 // | PHP version 5                                                        |
    4 // +----------------------------------------------------------------------+
    5 // | Copyright (c) 2002-2006 James Heinrich, Allan Hansen                 |
    6 // +----------------------------------------------------------------------+
    7 // | This source file is subject to version 2 of the GPL license,         |
    8 // | that is bundled with this package in the file license.txt and is     |
    9 // | available through the world-wide-web at the following url:           |
    10 // | http://www.gnu.org/copyleft/gpl.html                                 |
    11 // +----------------------------------------------------------------------+
    12 // | getID3() - http://getid3.sourceforge.net or http://www.getid3.org    |
    13 // +----------------------------------------------------------------------+
    14 // | Authors: James Heinrich <infoØgetid3*org>                            |
    15 // |          Allan Hansen <ahØartemis*dk>                                |
    16 // +----------------------------------------------------------------------+
    17 // | module.archive.szip.php                                              |
    18 // | module for analyzing SZIP compressed files                           |
    19 // | dependencies: NONE                                                   |
    20 // +----------------------------------------------------------------------+
    21 //
    22 // $Id$
     2/////////////////////////////////////////////////////////////////
     3/// getID3() by James Heinrich <info@getid3.org>               //
     4//  available at http://getid3.sourceforge.net                 //
     5//            or http://www.getid3.org                         //
     6/////////////////////////////////////////////////////////////////
     7// See readme.txt for more details                             //
     8/////////////////////////////////////////////////////////////////
     9//                                                             //
     10// module.archive.szip.php                                     //
     11// module for analyzing SZIP compressed files                  //
     12// dependencies: NONE                                          //
     13//                                                            ///
     14/////////////////////////////////////////////////////////////////
    2315
    24        
    25        
    26 class getid3_szip extends getid3_handler
     16
     17class getid3_szip
    2718{
    2819
    29     public function Analyze() {
    30        
    31         $getid3 = $this->getid3;
     20        function getid3_szip(&$fd, &$ThisFileInfo) {
    3221
    33         fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET);
    34         $szip_rkau = fread($getid3->fp, 6);
    35        
    36         // Magic bytes:  'SZ'."\x0A\x04"
    37            
    38         $getid3->info['fileformat']            = 'szip';
     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).'"';
     26                        return false;
     27                }
    3928
    40         $getid3->info['szip']['major_version'] = getid3_lib::BigEndian2Int(substr($szip_rkau, 4, 1));
    41         $getid3->info['szip']['minor_version'] = getid3_lib::BigEndian2Int(substr($szip_rkau, 5, 1));
     29                $ThisFileInfo['fileformat']            = 'szip';
    4230
    43         while (!feof($getid3->fp)) {
    44             $next_block_id = fread($getid3->fp, 2);
    45             switch ($next_block_id) {
    46                 case 'SZ':
    47                     // Note that szip files can be concatenated, this has the same effect as
    48                     // concatenating the files. this also means that global header blocks
    49                     // might be present between directory/data blocks.
    50                     fseek($getid3->fp, 4, SEEK_CUR);
    51                     break;
     31                $ThisFileInfo['szip']['major_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 4, 1));
     32                $ThisFileInfo['szip']['minor_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 5, 1));
    5233
    53                 case 'BH':
    54                     $bh_header_bytes  = getid3_lib::BigEndian2Int(fread($getid3->fp, 3));
    55                     $bh_header_data   = fread($getid3->fp, $bh_header_bytes);
    56                     $bh_header_offset = 0;
    57                     while (strpos($bh_header_data, "\x00", $bh_header_offset) > 0) {
    58                         //filename as \0 terminated string  (empty string indicates end)
    59                         //owner as \0 terminated string (empty is same as last file)
    60                         //group as \0 terminated string (empty is same as last file)
    61                         //3 byte filelength in this block
    62                         //2 byte access flags
    63                         //4 byte creation time (like in unix)
    64                         //4 byte modification time (like in unix)
    65                         //4 byte access time (like in unix)
     34                while (!feof($fd)) {
     35                        $NextBlockID = fread($fd, 2);
     36                        switch ($NextBlockID) {
     37                                case 'SZ':
     38                                        // Note that szip files can be concatenated, this has the same effect as
     39                                        // concatenating the files. this also means that global header blocks
     40                                        // might be present between directory/data blocks.
     41                                        fseek($fd, 4, SEEK_CUR);
     42                                        break;
    6643
    67                         $bh_data_array['filename'] = substr($bh_header_data, $bh_header_offset, strcspn($bh_header_data, "\x00"));
    68                         $bh_header_offset += (strlen($bh_data_array['filename']) + 1);
     44                                case 'BH':
     45                                        $BHheaderbytes  = getid3_lib::BigEndian2Int(fread($fd, 3));
     46                                        $BHheaderdata   = fread($fd, $BHheaderbytes);
     47                                        $BHheaderoffset = 0;
     48                                        while (strpos($BHheaderdata, "\x00", $BHheaderoffset) > 0) {
     49                                                //filename as \0 terminated string  (empty string indicates end)
     50                                                //owner as \0 terminated string (empty is same as last file)
     51                                                //group as \0 terminated string (empty is same as last file)
     52                                                //3 byte filelength in this block
     53                                                //2 byte access flags
     54                                                //4 byte creation time (like in unix)
     55                                                //4 byte modification time (like in unix)
     56                                                //4 byte access time (like in unix)
    6957
    70                         $bh_data_array['owner'] = substr($bh_header_data, $bh_header_offset, strcspn($bh_header_data, "\x00"));
    71                         $bh_header_offset += (strlen($bh_data_array['owner']) + 1);
     58                                                $BHdataArray['filename'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00"));
     59                                                $BHheaderoffset += (strlen($BHdataArray['filename']) + 1);
    7260
    73                         $bh_data_array['group'] = substr($bh_header_data, $bh_header_offset, strcspn($bh_header_data, "\x00"));
    74                         $bh_header_offset += (strlen($bh_data_array['group']) + 1);
     61                                                $BHdataArray['owner'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00"));
     62                                                $BHheaderoffset += (strlen($BHdataArray['owner']) + 1);
    7563
    76                         $bh_data_array['filelength'] = getid3_lib::BigEndian2Int(substr($bh_header_data, $bh_header_offset, 3));
    77                         $bh_header_offset += 3;
     64                                                $BHdataArray['group'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00"));
     65                                                $BHheaderoffset += (strlen($BHdataArray['group']) + 1);
    7866
    79                         $bh_data_array['access_flags'] = getid3_lib::BigEndian2Int(substr($bh_header_data, $bh_header_offset, 2));
    80                         $bh_header_offset += 2;
     67                                                $BHdataArray['filelength'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 3));
     68                                                $BHheaderoffset += 3;
    8169
    82                         $bh_data_array['creation_time'] = getid3_lib::BigEndian2Int(substr($bh_header_data, $bh_header_offset, 4));
    83                         $bh_header_offset += 4;
     70                                                $BHdataArray['access_flags'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 2));
     71                                                $BHheaderoffset += 2;
    8472
    85                         $bh_data_array['modification_time'] = getid3_lib::BigEndian2Int(substr($bh_header_data, $bh_header_offset, 4));
    86                         $bh_header_offset += 4;
     73                                                $BHdataArray['creation_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4));
     74                                                $BHheaderoffset += 4;
    8775
    88                         $bh_data_array['access_time'] = getid3_lib::BigEndian2Int(substr($bh_header_data, $bh_header_offset, 4));
    89                         $bh_header_offset += 4;
     76                                                $BHdataArray['modification_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4));
     77                                                $BHheaderoffset += 4;
    9078
    91                         $getid3->info['szip']['BH'][] = $bh_data_array;
    92                     }
    93                     break;
     79                                                $BHdataArray['access_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4));
     80                                                $BHheaderoffset += 4;
    9481
    95                 default:
    96                     break 2;
    97             }
    98         }
     82                                                $ThisFileInfo['szip']['BH'][] = $BHdataArray;
     83                                        }
     84                                        break;
    9985
    100         return true;
    101     }
     86                                default:
     87                                        break 2;
     88                        }
     89                }
     90
     91                return true;
     92
     93        }
    10294
    10395}
  • extensions/charlies_content/getid3/getid3/module.archive.tar.php

    r3318 r3544  
    11<?php
    2 // +----------------------------------------------------------------------+
    3 // | PHP version 5                                                        |
    4 // +----------------------------------------------------------------------+
    5 // | Copyright (c) 2002-2006 James Heinrich, Allan Hansen                 |
    6 // +----------------------------------------------------------------------+
    7 // | This source file is subject to version 2 of the GPL license,         |
    8 // | that is bundled with this package in the file license.txt and is     |
    9 // | available through the world-wide-web at the following url:           |
    10 // | http://www.gnu.org/copyleft/gpl.html                                 |
    11 // +----------------------------------------------------------------------+
    12 // | getID3() - http://getid3.sourceforge.net or http://www.getid3.org    |
    13 // +----------------------------------------------------------------------+
    14 // | Authors: James Heinrich <infoØgetid3*org>                            |
    15 // |          Allan Hansen <ahØartemis*dk>                                |
    16 // +----------------------------------------------------------------------+
    17 // | module.archive.tar.php                                               |
    18 // | module for analyzing TAR files                                       |
    19 // | dependencies: NONE                                                   |
    20 // +----------------------------------------------------------------------+
    21 // | Module originally written by Mike Mozolin <teddybearØmail*ru>        |
    22 // +----------------------------------------------------------------------+
    23 //
    24 // $Id$
    25 
    26        
    27        
    28 class getid3_tar extends getid3_handler
    29 {
    30 
    31     function Analyze() {
    32 
    33         $info = &$this->getid3->info;
    34 
    35         $info['fileformat'] = 'tar';
    36 
    37         $fp = $this->getid3->fp;
    38        
    39         fseek($fp, 0);
    40        
    41         $unpack_header = 'a100fname/a8mode/a8uid/a8gid/a12size/a12mtime/a8chksum/a1typflag/a100lnkname/a6magic/a2ver/a32uname/a32gname/a8devmaj/a8devmin/a155/prefix';
    42 
    43         $null_512k = str_repeat("\0", 512); // end-of-file marker
    44 
    45         $already_warned = false;
    46 
    47         while (!feof($fp)) {
    48            
    49             $buffer = fread($fp, 512);
    50            
    51             // check the block
    52             $checksum = 0;
    53             for ($i = 0; $i < 148; $i++) {
    54                 $checksum += ord(substr($buffer, $i, 1));
    55             }
    56             for ($i = 148; $i < 156; $i++) {
    57                 $checksum += ord(' ');
    58             }
    59             for ($i = 156; $i < 512; $i++) {
    60                 $checksum += ord(substr($buffer, $i, 1));
    61             }
    62             $attr    = unpack($unpack_header, $buffer);
    63             $name    =        trim(@$attr['fname']);
    64             $mode    = octdec(trim(@$attr['mode']));
    65             $uid     = octdec(trim(@$attr['uid']));
    66             $gid     = octdec(trim(@$attr['gid']));
    67             $size    = octdec(trim(@$attr['size']));
    68             $mtime   = octdec(trim(@$attr['mtime']));
    69             $chksum  = octdec(trim(@$attr['chksum']));
    70             $typflag =        trim(@$attr['typflag']);
    71             $lnkname =        trim(@$attr['lnkname']);
    72             $magic   =        trim(@$attr['magic']);
    73             $ver     =        trim(@$attr['ver']);
    74             $uname   =        trim(@$attr['uname']);
    75             $gname   =        trim(@$attr['gname']);
    76             $devmaj  = octdec(trim(@$attr['devmaj']));
    77             $devmin  = octdec(trim(@$attr['devmin']));
    78             $prefix  =        trim(@$attr['prefix']);
    79 
    80             // EOF Found
    81             if (($checksum == 256) && ($chksum == 0)) {
    82                 break;
    83             }
    84 
    85             // Check if filename if 7bit as spec requires
    86             if (!$already_warned) {
    87                 for ($i = 0; $i < strlen($name); $i++) {
    88                     if ($name{$i} < chr(32) || $name{$i} > chr(127)) {
    89                         $this->getid3->warning('Some filenames contains extended characters, which breaks the tar specifation. This is not uncommon, but you will have to handle the character encoding for filenames yourself.');
    90                         $already_warned = true;
    91                         break;
    92                     }
    93                 }
    94             }
    95            
    96             if ($prefix) {
    97                 $name = $prefix.'/'.$name;
    98             }
    99             if ((preg_match('#/$#', $name)) && !$name) {
    100                 $typeflag = 5;
    101             }
    102            
    103             // If it's the end of the tar-file...
    104             if ($buffer == $null_512k) {
    105                 break;
    106             }
    107            
    108             // Protect against tar-files with garbage at the end
    109             if ($name == '') {
    110                 break;
    111             }
    112            
    113             $info['tar']['file_details'][$name] = array (
    114                 'name'     => $name,
    115                 'mode_raw' => $mode,
    116                 'mode'     => getid3_tar::display_perms($mode),
    117                 'uid'      => $uid,
    118                 'gid'      => $gid,
    119                 'size'     => $size,
    120                 'mtime'    => $mtime,
    121                 'chksum'   => $chksum,
    122                 'typeflag' => getid3_tar::get_flag_type($typflag),
    123                 'linkname' => $lnkname,
    124                 'magic'    => $magic,
    125                 'version'  => $ver,
    126                 'uname'    => $uname,
    127                 'gname'    => $gname,
    128                 'devmajor' => $devmaj,
    129                 'devminor' => $devmin
    130             );
    131            
    132             // Skip the next chunk
    133             fseek($fp, $size, SEEK_CUR);
    134 
    135             // Throw away padding
    136             if ($size % 512) {
    137                 fseek($fp, 512 - $diff, SEEK_CUR);
    138             }
    139            
    140         }
    141         return true;
    142     }
     2/////////////////////////////////////////////////////////////////
     3/// getID3() by James Heinrich <info@getid3.org>               //
     4//  available at http://getid3.sourceforge.net                 //
     5//            or http://www.getid3.org                         //
     6/////////////////////////////////////////////////////////////////
     7// See readme.txt for more details                             //
     8/////////////////////////////////////////////////////////////////
     9//                                                             //
     10// module.archive.tar.php                                      //
     11// module for analyzing TAR files                              //
     12// dependencies: NONE                                          //
     13//                                                            ///
     14/////////////////////////////////////////////////////////////////
     15//                                                             //
     16// Module originally written by                                //
     17//      Mike Mozolin <teddybearØmail*ru>                       //
     18//                                                             //
     19/////////////////////////////////////////////////////////////////
    14320
    14421
    145     // Parses the file mode to file permissions
    146     public static function display_perms($mode) {
     22class getid3_tar {
    14723
    148         // Determine Type
    149         if ($mode & 0x1000) {
    150             $type='p'; // FIFO pipe
    151         }
    152         elseif ($mode & 0x2000) {
    153             $type='c'; // Character special
    154         }
    155         elseif ($mode & 0x4000) {
    156             $type='d'; // Directory
    157         }
    158         elseif ($mode & 0x6000) {
    159             $type='b'; // Block special
    160         }
    161         elseif ($mode & 0x8000) {
    162             $type='-'; // Regular
    163         }
    164         elseif ($mode & 0xA000) {
    165             $type='l'; // Symbolic Link
    166         }
    167         elseif ($mode & 0xC000) {
    168             $type='s'; // Socket
    169         }
    170         else {
    171             $type='u'; // UNKNOWN
    172         }
     24        function getid3_tar(&$fd, &$ThisFileInfo) {
     25                $ThisFileInfo['fileformat'] = 'tar';
     26                $ThisFileInfo['tar']['files'] = array();
    17327
    174         // Determine permissions
    175         $owner['read']    = (($mode & 00400) ? 'r' : '-');
    176         $owner['write']   = (($mode & 00200) ? 'w' : '-');
    177         $owner['execute'] = (($mode & 00100) ? 'x' : '-');
    178         $group['read']    = (($mode & 00040) ? 'r' : '-');
    179         $group['write']   = (($mode & 00020) ? 'w' : '-');
    180         $group['execute'] = (($mode & 00010) ? 'x' : '-');
    181         $world['read']    = (($mode & 00004) ? 'r' : '-');
    182         $world['write']   = (($mode & 00002) ? 'w' : '-');
    183         $world['execute'] = (($mode & 00001) ? 'x' : '-');
     28                $unpack_header = 'a100fname/a8mode/a8uid/a8gid/a12size/a12mtime/a8chksum/a1typflag/a100lnkname/a6magic/a2ver/a32uname/a32gname/a8devmaj/a8devmin/a155prefix';
     29                $null_512k = str_repeat("\x00", 512); // end-of-file marker
    18430
    185         // Adjust for SUID, SGID and sticky bit
    186         if ($mode & 0x800) {
    187             $owner['execute'] = ($owner['execute'] == 'x') ? 's' : 'S';
    188         }
    189         if ($mode & 0x400) {
    190             $group['execute'] = ($group['execute'] == 'x') ? 's' : 'S';
    191         }
    192         if ($mode & 0x200) {
    193             $world['execute'] = ($world['execute'] == 'x') ? 't' : 'T';
    194         }
     31                @fseek($fd, 0);
     32                while (!feof($fd)) {
     33                        $buffer = fread($fd, 512);
     34                        if (strlen($buffer) < 512) {
     35                                break;
     36                        }
    19537
    196         $s  = sprintf('%1s', $type);
    197         $s .= sprintf('%1s%1s%1s',      $owner['read'], $owner['write'], $owner['execute']);
    198         $s .= sprintf('%1s%1s%1s',      $group['read'], $group['write'], $group['execute']);
    199         $s .= sprintf('%1s%1s%1s'."\n", $world['read'], $world['write'], $world['execute']);
     38                        // check the block
     39                        $checksum = 0;
     40                        for ($i = 0; $i < 148; $i++) {
     41                                $checksum += ord($buffer{$i});
     42                        }
     43                        for ($i = 148; $i < 156; $i++) {
     44                                $checksum += ord(' ');
     45                        }
     46                        for ($i = 156; $i < 512; $i++) {
     47                                $checksum += ord($buffer{$i});
     48                        }
     49                        $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']);
     66                        if (($checksum == 256) && ($chksum == 0)) {
     67                                // EOF Found
     68                                break;
     69                        }
     70                        if ($prefix) {
     71                                $name = $prefix.'/'.$name;
     72                        }
     73                        if ((preg_match('#/$#', $name)) && !$name) {
     74                                $typeflag = 5;
     75                        }
     76                        if ($buffer == $null_512k) {
     77                                // it's the end of the tar-file...
     78                                break;
     79                        }
    20080
    201         return $s;
    202     }
     81                        // Read to the next chunk
     82                        fseek($fd, $size, SEEK_CUR);
    20383
     84                        $diff = $size % 512;
     85                        if ($diff != 0) {
     86                                // Padding, throw away
     87                                fseek($fd, (512 - $diff), SEEK_CUR);
     88                        }
     89                        // Protect against tar-files with garbage at the end
     90                        if ($name == '') {
     91                                break;
     92                        }
     93                        $ThisFileInfo['tar']['file_details'][$name] = array (
     94                                'name'     => $name,
     95                                'mode_raw' => $mode,
     96                                'mode'     => getid3_tar::display_perms($mode),
     97                                'uid'      => $uid,
     98                                'gid'      => $gid,
     99                                'size'     => $size,
     100                                'mtime'    => $mtime,
     101                                'chksum'   => $chksum,
     102                                'typeflag' => getid3_tar::get_flag_type($typflag),
     103                                'linkname' => $lnkname,
     104                                'magic'    => $magic,
     105                                'version'  => $ver,
     106                                'uname'    => $uname,
     107                                'gname'    => $gname,
     108                                'devmajor' => $devmaj,
     109                                'devminor' => $devmin
     110                        );
     111                        $ThisFileInfo['tar']['files'] = getid3_lib::array_merge_clobber($ThisFileInfo['tar']['files'], getid3_lib::CreateDeepArray($ThisFileInfo['tar']['file_details'][$name]['name'], '/', $size));
     112                }
     113                return true;
     114        }
    204115
    205     // Converts the file type
    206     public static function get_flag_type($typflag) {
     116        // Parses the file mode to file permissions
     117        function display_perms($mode) {
     118                // Determine Type
     119                if     ($mode & 0x1000) $type='p'; // FIFO pipe
     120                elseif ($mode & 0x2000) $type='c'; // Character special
     121                elseif ($mode & 0x4000) $type='d'; // Directory
     122                elseif ($mode & 0x6000) $type='b'; // Block special
     123                elseif ($mode & 0x8000) $type='-'; // Regular
     124                elseif ($mode & 0xA000) $type='l'; // Symbolic Link
     125                elseif ($mode & 0xC000) $type='s'; // Socket
     126                else                    $type='u'; // UNKNOWN
    207127
    208         static $flag_types = array (
    209             '0' => 'LF_NORMAL',
    210             '1' => 'LF_LINK',
    211             '2' => 'LF_SYNLINK',
    212             '3' => 'LF_CHR',
    213             '4' => 'LF_BLK',
    214             '5' => 'LF_DIR',
    215             '6' => 'LF_FIFO',
    216             '7' => 'LF_CONFIG',
    217             'D' => 'LF_DUMPDIR',
    218             'K' => 'LF_LONGLINK',
    219             'L' => 'LF_LONGNAME',
    220             'M' => 'LF_MULTIVOL',
    221             'N' => 'LF_NAMES',
    222             'S' => 'LF_SPARSE',
    223             'V' => 'LF_VOLHDR'
    224         );
     128                // Determine permissions
     129                $owner['read']    = (($mode & 00400) ? 'r' : '-');
     130                $owner['write']   = (($mode & 00200) ? 'w' : '-');
     131                $owner['execute'] = (($mode & 00100) ? 'x' : '-');
     132                $group['read']    = (($mode & 00040) ? 'r' : '-');
     133                $group['write']   = (($mode & 00020) ? 'w' : '-');
     134                $group['execute'] = (($mode & 00010) ? 'x' : '-');
     135                $world['read']    = (($mode & 00004) ? 'r' : '-');
     136                $world['write']   = (($mode & 00002) ? 'w' : '-');
     137                $world['execute'] = (($mode & 00001) ? 'x' : '-');
    225138
    226         return @$flag_types[$typflag];
    227     }
    228    
     139                // Adjust for SUID, SGID and sticky bit
     140                if ($mode & 0x800) $owner['execute'] = ($owner['execute'] == 'x') ? 's' : 'S';
     141                if ($mode & 0x400) $group['execute'] = ($group['execute'] == 'x') ? 's' : 'S';
     142                if ($mode & 0x200) $world['execute'] = ($world['execute'] == 'x') ? 't' : 'T';
     143
     144                $s  = sprintf('%1s', $type);
     145                $s .= sprintf('%1s%1s%1s',      $owner['read'], $owner['write'], $owner['execute']);
     146                $s .= sprintf('%1s%1s%1s',      $group['read'], $group['write'], $group['execute']);
     147                $s .= sprintf('%1s%1s%1s'."\n", $world['read'], $world['write'], $world['execute']);
     148                return $s;
     149        }
     150
     151        // Converts the file type
     152        function get_flag_type($typflag) {
     153                static $flag_types = array(
     154                        '0' => 'LF_NORMAL',
     155                        '1' => 'LF_LINK',
     156                        '2' => 'LF_SYNLINK',
     157                        '3' => 'LF_CHR',
     158                        '4' => 'LF_BLK',
     159                        '5' => 'LF_DIR',
     160                        '6' => 'LF_FIFO',
     161                        '7' => 'LF_CONFIG',
     162                        'D' => 'LF_DUMPDIR',
     163                        'K' => 'LF_LONGLINK',
     164                        'L' => 'LF_LONGNAME',
     165                        'M' => 'LF_MULTIVOL',
     166                        'N' => 'LF_NAMES',
     167                        'S' => 'LF_SPARSE',
     168                        'V' => 'LF_VOLHDR'
     169                );
     170                return @$flag_types[$typflag];
     171        }
     172
    229173}
    230174
  • extensions/charlies_content/getid3/getid3/module.archive.zip.php

    r3318 r3544  
    11<?php
    2 // +----------------------------------------------------------------------+
    3 // | PHP version 5                                                        |
    4 // +----------------------------------------------------------------------+
    5 // | Copyright (c) 2002-2006 James Heinrich, Allan Hansen                 |
    6 // +----------------------------------------------------------------------+
    7 // | This source file is subject to version 2 of the GPL license,         |
    8 // | that is bundled with this package in the file license.txt and is     |
    9 // | available through the world-wide-web at the following url:           |
    10 // | http://www.gnu.org/copyleft/gpl.html                                 |
    11 // +----------------------------------------------------------------------+
    12 // | getID3() - http://getid3.sourceforge.net or http://www.getid3.org    |
    13 // +----------------------------------------------------------------------+
    14 // | Authors: James Heinrich <infoØgetid3*org>                            |
    15 // |          Allan Hansen <ahØartemis*dk>                                |
    16 // +----------------------------------------------------------------------+
    17 // | module.archive.zip.php                                               |
    18 // | Module for analyzing pkZip files                                     |
    19 // | dependencies: NONE                                                   |
    20 // +----------------------------------------------------------------------+
    21 //
    22 // $Id$
    23 
    24 
    25 
    26 class getid3_zip extends getid3_handler
     2/////////////////////////////////////////////////////////////////
     3/// getID3() by James Heinrich <info@getid3.org>               //
     4//  available at http://getid3.sourceforge.net                 //
     5//            or http://www.getid3.org                         //
     6/////////////////////////////////////////////////////////////////
     7// See readme.txt for more details                             //
     8/////////////////////////////////////////////////////////////////
     9//                                                             //
     10// module.archive.zip.php                                      //
     11// module for analyzing pkZip files                            //
     12// dependencies: NONE                                          //
     13//                                                            ///
     14/////////////////////////////////////////////////////////////////
     15
     16
     17class getid3_zip
    2718{
    2819
    29     public function Analyze() {
    30 
    31         $getid3 = $this->getid3;
    32        
    33         $getid3->info['zip'] = array ();
    34         $info_zip = &$getid3->info['zip'];
    35        
    36         $getid3->info['fileformat'] = 'zip';
    37        
    38         $info_zip['encoding'] = 'ISO-8859-1';
    39         $info_zip['files']    = array ();
    40         $info_zip['compressed_size'] = $info_zip['uncompressed_size'] = $info_zip['entries_count'] = 0;
    41 
    42         $eocd_search_data    = '';
    43         $eocd_search_counter = 0;
    44         while ($eocd_search_counter++ < 512) {
    45 
    46             fseek($getid3->fp, -128 * $eocd_search_counter, SEEK_END);
    47             $eocd_search_data = fread($getid3->fp, 128).$eocd_search_data;
    48 
    49             if (strstr($eocd_search_data, 'PK'."\x05\x06")) {
    50 
    51                 $eocd_position = strpos($eocd_search_data, 'PK'."\x05\x06");
    52                 fseek($getid3->fp, (-128 * $eocd_search_counter) + $eocd_position, SEEK_END);
    53                 $info_zip['end_central_directory'] = $this->ZIPparseEndOfCentralDirectory();
    54 
    55                 fseek($getid3->fp, $info_zip['end_central_directory']['directory_offset'], SEEK_SET);
    56                 $info_zip['entries_count'] = 0;
    57                 while ($central_directoryentry = $this->ZIPparseCentralDirectory($getid3->fp)) {
    58                     $info_zip['central_directory'][] = $central_directoryentry;
    59                     $info_zip['entries_count']++;
    60                     $info_zip['compressed_size']   += $central_directoryentry['compressed_size'];
    61                     $info_zip['uncompressed_size'] += $central_directoryentry['uncompressed_size'];
    62 
    63                     if ($central_directoryentry['uncompressed_size'] > 0) {
    64                         $info_zip['files'] = getid3_zip::array_merge_clobber($info_zip['files'], getid3_zip::CreateDeepArray($central_directoryentry['filename'], '/', $central_directoryentry['uncompressed_size']));
    65                     }
    66                 }
    67 
    68                 if ($info_zip['entries_count'] == 0) {
    69                     throw new getid3_exception('No Central Directory entries found (truncated file?)');
    70                 }
    71 
    72                 if (!empty($info_zip['end_central_directory']['comment'])) {
    73                     $info_zip['comments']['comment'][] = $info_zip['end_central_directory']['comment'];
    74                 }
    75 
    76                 if (isset($