File indexing completed on 2024-05-12 05:58:10

0001 <?php
0002 /////////////////////////////////////////////////////////////////////////////////
0003 /// getID3() by James Heinrich <info@getid3.org>                               //
0004 //  available at http://getid3.sourceforge.net                                 //
0005 //            or http://www.getid3.org                                         //
0006 //          also https://github.com/JamesHeinrich/getID3                       //
0007 /////////////////////////////////////////////////////////////////////////////////
0008 ///                                                                            //
0009 // extension.cache.sqlite3.php - part of getID3()                              //
0010 // Please see readme.txt for more information                                  //
0011 //                                                                            ///
0012 /////////////////////////////////////////////////////////////////////////////////
0013 ///                                                                            //
0014 // MySQL extension written by Allan Hansen <ahØartemis*dk>                     //
0015 // Table name mod by Carlo Capocasa <calroØcarlocapocasa*com>                  //
0016 // MySQL extension was reworked for SQLite3 by Karl G. Holz <newaeonØmac*com>  //
0017 //                                                                            ///
0018 /////////////////////////////////////////////////////////////////////////////////
0019 /**
0020 * This is a caching extension for getID3(). It works the exact same
0021 * way as the getID3 class, but return cached information much faster
0022 *
0023 *    Normal getID3 usage (example):
0024 *
0025 *       require_once 'getid3/getid3.php';
0026 *       $getID3 = new getID3;
0027 *       $getID3->encoding = 'UTF-8';
0028 *       $info1 = $getID3->analyze('file1.flac');
0029 *       $info2 = $getID3->analyze('file2.wv');
0030 *
0031 *    getID3_cached usage:
0032 *
0033 *       require_once 'getid3/getid3.php';
0034 *       require_once 'getid3/extension.cache.sqlite3.php';
0035 *       // all parameters are optional, defaults are:
0036 *       $getID3 = new getID3_cached_sqlite3($table='getid3_cache', $hide=FALSE);
0037 *       $getID3->encoding = 'UTF-8';
0038 *       $info1 = $getID3->analyze('file1.flac');
0039 *       $info2 = $getID3->analyze('file2.wv');
0040 *
0041 *
0042 * Supported Cache Types    (this extension)
0043 *
0044 *   SQL Databases:
0045 *
0046 *   cache_type          cache_options
0047 *   -------------------------------------------------------------------
0048 *   mysql               host, database, username, password
0049 *
0050 *   sqlite3             table='getid3_cache', hide=false        (PHP5)
0051 *
0052 
0053 ***  database file will be stored in the same directory as this script,
0054 ***  webserver must have write access to that directory!
0055 ***  set $hide to TRUE to prefix db file with .ht to pervent access from web client
0056 ***  this is a default setting in the Apache configuration:
0057 
0058 # The following lines prevent .htaccess and .htpasswd files from being viewed by Web clients.
0059 
0060 <Files ~ "^\.ht">
0061     Order allow,deny
0062     Deny from all
0063     Satisfy all
0064 </Files>
0065 
0066 ********************************************************************************
0067 *
0068 *   -------------------------------------------------------------------
0069 *   DBM-Style Databases:    (use extension.cache.dbm)
0070 *
0071 *   cache_type          cache_options
0072 *   -------------------------------------------------------------------
0073 *   gdbm                dbm_filename, lock_filename
0074 *   ndbm                dbm_filename, lock_filename
0075 *   db2                 dbm_filename, lock_filename
0076 *   db3                 dbm_filename, lock_filename
0077 *   db4                 dbm_filename, lock_filename  (PHP5 required)
0078 *
0079 *   PHP must have write access to both dbm_filename and lock_filename.
0080 *
0081 * Recommended Cache Types
0082 *
0083 *   Infrequent updates, many reads      any DBM
0084 *   Frequent updates                    mysql
0085 ********************************************************************************
0086 *
0087 * IMHO this is still a bit slow, I'm using this with MP4/MOV/ M4v files
0088 * there is a plan to add directory scanning and analyzing to make things work much faster
0089 *
0090 *
0091 */
0092 class getID3_cached_sqlite3 extends getID3 {
0093 
0094     /**
0095      * __construct()
0096      *
0097      * @param string $table holds name of sqlite table
0098      * @param bool   $hide
0099      */
0100   public function __construct($table='getid3_cache', $hide=false) {
0101     $this->table = $table; // Set table
0102     $file = dirname(__FILE__).'/'.basename(__FILE__, 'php').'sqlite';
0103     if ($hide) {
0104       $file = dirname(__FILE__).'/.ht.'.basename(__FILE__, 'php').'sqlite';
0105     }
0106     $this->db = new SQLite3($file);
0107     $db = $this->db;
0108     $this->create_table();   // Create cache table if not exists
0109     $version = '';
0110     $sql = $this->version_check;
0111     $stmt = $db->prepare($sql);
0112     $stmt->bindValue(':filename', getID3::VERSION, SQLITE3_TEXT);
0113     $result = $stmt->execute();
0114     list($version) = $result->fetchArray();
0115     if ($version != getID3::VERSION) { // Check version number and clear cache if changed
0116       $this->clear_cache();
0117     }
0118     return parent::__construct();
0119   }
0120 
0121   /**
0122   * close the database connection
0123   */
0124   public function __destruct() {
0125     $db=$this->db;
0126     $db->close();
0127   }
0128 
0129   /**
0130   * hold the sqlite db
0131   * @var SQLite Resource
0132   */
0133   private $db;
0134 
0135   /**
0136   * table to use for caching
0137   * @var string $table
0138   */
0139   private $table;
0140 
0141   /**
0142   * clear the cache
0143   * @access private
0144   * @return type
0145   */
0146   private function clear_cache() {
0147     $db = $this->db;
0148     $sql = $this->delete_cache;
0149     $db->exec($sql);
0150     $sql = $this->set_version;
0151     $stmt = $db->prepare($sql);
0152     $stmt->bindValue(':filename', getID3::VERSION, SQLITE3_TEXT);
0153     $stmt->bindValue(':dirname', getID3::VERSION, SQLITE3_TEXT);
0154     $stmt->bindValue(':val', getID3::VERSION, SQLITE3_TEXT);
0155     return $stmt->execute();
0156   }
0157 
0158   /**
0159   * analyze file and cache them, if cached pull from the db
0160   * @param type $filename
0161   * @return boolean
0162   */
0163   public function analyze($filename) {
0164     if (!file_exists($filename)) {
0165       return false;
0166     }
0167     // items to track for caching
0168     $filetime = filemtime($filename);
0169     $filesize = filesize($filename);
0170     // this will be saved for a quick directory lookup of analized files
0171     // ... why do 50 seperate sql quries when you can do 1 for the same result
0172     $dirname  = dirname($filename);
0173     // Lookup file
0174     $db = $this->db;
0175     $sql = $this->get_id3_data;
0176     $stmt = $db->prepare($sql);
0177     $stmt->bindValue(':filename', $filename, SQLITE3_TEXT);
0178     $stmt->bindValue(':filesize', $filesize, SQLITE3_INTEGER);
0179     $stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER);
0180     $res = $stmt->execute();
0181     list($result) = $res->fetchArray();
0182     if (count($result) > 0 ) {
0183       return unserialize(base64_decode($result));
0184     }
0185     // if it hasn't been analyzed before, then do it now
0186     $analysis = parent::analyze($filename);
0187     // Save result
0188     $sql = $this->cache_file;
0189     $stmt = $db->prepare($sql);
0190     $stmt->bindValue(':filename', $filename, SQLITE3_TEXT);
0191     $stmt->bindValue(':dirname', $dirname, SQLITE3_TEXT);
0192     $stmt->bindValue(':filesize', $filesize, SQLITE3_INTEGER);
0193     $stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER);
0194     $stmt->bindValue(':atime', time(), SQLITE3_INTEGER);
0195     $stmt->bindValue(':val', base64_encode(serialize($analysis)), SQLITE3_TEXT);
0196     $res = $stmt->execute();
0197     return $analysis;
0198   }
0199 
0200   /**
0201   * create data base table
0202   * this is almost the same as MySQL, with the exception of the dirname being added
0203   * @return type
0204   */
0205   private function create_table() {
0206     $db = $this->db;
0207     $sql = $this->make_table;
0208     return $db->exec($sql);
0209   }
0210 
0211   /**
0212   * get cached directory
0213   *
0214   * This function is not in the MySQL extention, it's ment to speed up requesting multiple files
0215   * which is ideal for podcasting, playlists, etc.
0216   *
0217   * @access public
0218   * @param string $dir directory to search the cache database for
0219   * @return array return an array of matching id3 data
0220   */
0221   public function get_cached_dir($dir) {
0222     $db = $this->db;
0223     $rows = array();
0224     $sql = $this->get_cached_dir;
0225     $stmt = $db->prepare($sql);
0226     $stmt->bindValue(':dirname', $dir, SQLITE3_TEXT);
0227     $res = $stmt->execute();
0228     while ($row=$res->fetchArray()) {
0229       $rows[] = unserialize(base64_decode($row));
0230     }
0231     return $rows;
0232     }
0233 
0234     /**
0235      * use the magical __get() for sql queries
0236      *
0237      * access as easy as $this->{case name}, returns NULL if query is not found
0238      * @param $name
0239      * @return string|null
0240      */
0241   public function __get($name) {
0242     switch($name) {
0243       case 'version_check':
0244         return "SELECT val FROM $this->table WHERE filename = :filename AND filesize = '-1' AND filetime = '-1' AND analyzetime = '-1'";
0245         break;
0246       case 'delete_cache':
0247         return "DELETE FROM $this->table";
0248         break;
0249       case 'set_version':
0250         return "INSERT INTO $this->table (filename, dirname, filesize, filetime, analyzetime, val) VALUES (:filename, :dirname, -1, -1, -1, :val)";
0251         break;
0252       case 'get_id3_data':
0253         return "SELECT val FROM $this->table WHERE filename = :filename AND filesize = :filesize AND filetime = :filetime";
0254         break;
0255       case 'cache_file':
0256         return "INSERT INTO $this->table (filename, dirname, filesize, filetime, analyzetime, val) VALUES (:filename, :dirname, :filesize, :filetime, :atime, :val)";
0257         break;
0258       case 'make_table':
0259         return "CREATE TABLE IF NOT EXISTS $this->table (filename VARCHAR(255) NOT NULL DEFAULT '', dirname VARCHAR(255) NOT NULL DEFAULT '', filesize INT(11) NOT NULL DEFAULT '0', filetime INT(11) NOT NULL DEFAULT '0', analyzetime INT(11) NOT NULL DEFAULT '0', val text not null, PRIMARY KEY (filename, filesize, filetime))";
0260         break;
0261       case 'get_cached_dir':
0262         return "SELECT val FROM $this->table WHERE dirname = :dirname";
0263         break;
0264     }
0265     return null;
0266   }
0267 
0268 }