1<?php 2 3///////////////////////////////////////////////////////////////// 4/// getID3() by James Heinrich <info@getid3.org> // 5// available at https://github.com/JamesHeinrich/getID3 // 6// or https://www.getid3.org // 7// or http://getid3.sourceforge.net // 8// // 9// extension.cache.dbm.php - part of getID3() // 10// Please see readme.txt for more information // 11// /// 12///////////////////////////////////////////////////////////////// 13// // 14// This extension written by Allan Hansen <ahØartemis*dk> // 15// /// 16///////////////////////////////////////////////////////////////// 17 18 19/** 20* This is a caching extension for getID3(). It works the exact same 21* way as the getID3 class, but return cached information very fast 22* 23* Example: 24* 25* Normal getID3 usage (example): 26* 27* require_once 'getid3/getid3.php'; 28* $getID3 = new getID3; 29* $getID3->encoding = 'UTF-8'; 30* $info1 = $getID3->analyze('file1.flac'); 31* $info2 = $getID3->analyze('file2.wv'); 32* 33* getID3_cached usage: 34* 35* require_once 'getid3/getid3.php'; 36* require_once 'getid3/getid3/extension.cache.dbm.php'; 37* $getID3 = new getID3_cached('db3', '/tmp/getid3_cache.dbm', 38* '/tmp/getid3_cache.lock'); 39* $getID3->encoding = 'UTF-8'; 40* $info1 = $getID3->analyze('file1.flac'); 41* $info2 = $getID3->analyze('file2.wv'); 42* 43* 44* Supported Cache Types 45* 46* SQL Databases: (use extension.cache.mysql) 47* 48* cache_type cache_options 49* ------------------------------------------------------------------- 50* mysql host, database, username, password 51* 52* 53* DBM-Style Databases: (this extension) 54* 55* cache_type cache_options 56* ------------------------------------------------------------------- 57* gdbm dbm_filename, lock_filename 58* ndbm dbm_filename, lock_filename 59* db2 dbm_filename, lock_filename 60* db3 dbm_filename, lock_filename 61* db4 dbm_filename, lock_filename (PHP5 required) 62* 63* PHP must have write access to both dbm_filename and lock_filename. 64* 65* 66* Recommended Cache Types 67* 68* Infrequent updates, many reads any DBM 69* Frequent updates mysql 70*/ 71 72 73class getID3_cached_dbm extends getID3 74{ 75 /** 76 * @var resource 77 */ 78 private $dba; 79 80 /** 81 * @var resource|bool 82 */ 83 private $lock; 84 85 /** 86 * @var string 87 */ 88 private $cache_type; 89 90 /** 91 * @var string 92 */ 93 private $dbm_filename; 94 95 /** 96 * constructor - see top of this file for cache type and cache_options 97 * 98 * @param string $cache_type 99 * @param string $dbm_filename 100 * @param string $lock_filename 101 * 102 * @throws Exception 103 * @throws getid3_exception 104 */ 105 public function __construct($cache_type, $dbm_filename, $lock_filename) { 106 107 // Check for dba extension 108 if (!extension_loaded('dba')) { 109 throw new Exception('PHP is not compiled with dba support, required to use DBM style cache.'); 110 } 111 112 // Check for specific dba driver 113 if (!function_exists('dba_handlers') || !in_array($cache_type, dba_handlers())) { 114 throw new Exception('PHP is not compiled --with '.$cache_type.' support, required to use DBM style cache.'); 115 } 116 117 // Create lock file if needed 118 if (!file_exists($lock_filename)) { 119 if (!touch($lock_filename)) { 120 throw new Exception('failed to create lock file: '.$lock_filename); 121 } 122 } 123 124 // Open lock file for writing 125 if (!is_writeable($lock_filename)) { 126 throw new Exception('lock file: '.$lock_filename.' is not writable'); 127 } 128 $this->lock = fopen($lock_filename, 'w'); 129 130 // Acquire exclusive write lock to lock file 131 flock($this->lock, LOCK_EX); 132 133 // Create dbm-file if needed 134 if (!file_exists($dbm_filename)) { 135 if (!touch($dbm_filename)) { 136 throw new Exception('failed to create dbm file: '.$dbm_filename); 137 } 138 } 139 140 // Try to open dbm file for writing 141 $this->dba = dba_open($dbm_filename, 'w', $cache_type); 142 if (!$this->dba) { 143 144 // Failed - create new dbm file 145 $this->dba = dba_open($dbm_filename, 'n', $cache_type); 146 147 if (!$this->dba) { 148 throw new Exception('failed to create dbm file: '.$dbm_filename); 149 } 150 151 // Insert getID3 version number 152 dba_insert(getID3::VERSION, getID3::VERSION, $this->dba); 153 } 154 155 // Init misc values 156 $this->cache_type = $cache_type; 157 $this->dbm_filename = $dbm_filename; 158 159 // Register destructor 160 register_shutdown_function(array($this, '__destruct')); 161 162 // Check version number and clear cache if changed 163 if (dba_fetch(getID3::VERSION, $this->dba) != getID3::VERSION) { 164 $this->clear_cache(); 165 } 166 167 parent::__construct(); 168 } 169 170 171 172 /** 173 * destructor 174 */ 175 public function __destruct() { 176 177 // Close dbm file 178 dba_close($this->dba); 179 180 // Release exclusive lock 181 flock($this->lock, LOCK_UN); 182 183 // Close lock file 184 fclose($this->lock); 185 } 186 187 188 189 /** 190 * clear cache 191 * 192 * @throws Exception 193 */ 194 public function clear_cache() { 195 196 // Close dbm file 197 dba_close($this->dba); 198 199 // Create new dbm file 200 $this->dba = dba_open($this->dbm_filename, 'n', $this->cache_type); 201 202 if (!$this->dba) { 203 throw new Exception('failed to clear cache/recreate dbm file: '.$this->dbm_filename); 204 } 205 206 // Insert getID3 version number 207 dba_insert(getID3::VERSION, getID3::VERSION, $this->dba); 208 209 // Re-register shutdown function 210 register_shutdown_function(array($this, '__destruct')); 211 } 212 213 214 215 /** 216 * clear cache 217 * 218 * @param string $filename 219 * @param int $filesize 220 * @param string $original_filename 221 * @param resource $fp 222 * 223 * @return mixed 224 */ 225 public function analyze($filename, $filesize=null, $original_filename='', $fp=null) { 226 227 if (file_exists($filename)) { 228 229 // Calc key filename::mod_time::size - should be unique 230 $key = $filename.'::'.filemtime($filename).'::'.filesize($filename); 231 232 // Loopup key 233 $result = dba_fetch($key, $this->dba); 234 235 // Hit 236 if ($result !== false) { 237 return unserialize($result); 238 } 239 } 240 241 // Miss 242 $result = parent::analyze($filename, $filesize, $original_filename, $fp); 243 244 // Save result 245 if (isset($key) && file_exists($filename)) { 246 dba_insert($key, serialize($result), $this->dba); 247 } 248 249 return $result; 250 } 251 252} 253