• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • Examples
  • File List

E:/E/GEAMP/www/openbiz/openbiz/others/Zend/Cache/Backend/Sqlite.php

00001 <?php
00027 require_once 'Zend/Cache/Backend/ExtendedInterface.php';
00028 
00032 require_once 'Zend/Cache/Backend.php';
00033 
00040 class Zend_Cache_Backend_Sqlite extends Zend_Cache_Backend implements Zend_Cache_Backend_ExtendedInterface
00041 {
00058     protected $_options = array(
00059         'cache_db_complete_path' => null,
00060         'automatic_vacuum_factor' => 10
00061     );
00062 
00068     private $_db = null;
00069 
00075     private $_structureChecked = false;
00076 
00084     public function __construct(array $options = array())
00085     {
00086         parent::__construct($options);
00087         if ($this->_options['cache_db_complete_path'] === null) {
00088             Zend_Cache::throwException('cache_db_complete_path option has to set');
00089         }
00090         if (!extension_loaded('sqlite')) {
00091             Zend_Cache::throwException("Cannot use SQLite storage because the 'sqlite' extension is not loaded in the current PHP environment");
00092         }
00093         $this->_getConnection();
00094     }
00095 
00101     public function __destruct()
00102     {
00103         @sqlite_close($this->_getConnection());
00104     }
00105 
00113     public function load($id, $doNotTestCacheValidity = false)
00114     {
00115         $this->_checkAndBuildStructure();
00116         $sql = "SELECT content FROM cache WHERE id='$id'";
00117         if (!$doNotTestCacheValidity) {
00118             $sql = $sql . " AND (expire=0 OR expire>" . time() . ')';
00119         }
00120         $result = $this->_query($sql);
00121         $row = @sqlite_fetch_array($result);
00122         if ($row) {
00123             return $row['content'];
00124         }
00125         return false;
00126     }
00127 
00134     public function test($id)
00135     {
00136         $this->_checkAndBuildStructure();
00137         $sql = "SELECT lastModified FROM cache WHERE id='$id' AND (expire=0 OR expire>" . time() . ')';
00138         $result = $this->_query($sql);
00139         $row = @sqlite_fetch_array($result);
00140         if ($row) {
00141             return ((int) $row['lastModified']);
00142         }
00143         return false;
00144     }
00145 
00159     public function save($data, $id, $tags = array(), $specificLifetime = false)
00160     {
00161         $this->_checkAndBuildStructure();
00162         $lifetime = $this->getLifetime($specificLifetime);
00163         $data = @sqlite_escape_string($data);
00164         $mktime = time();
00165         if ($lifetime === null) {
00166             $expire = 0;
00167         } else {
00168             $expire = $mktime + $lifetime;
00169         }
00170         $this->_query("DELETE FROM cache WHERE id='$id'");
00171         $sql = "INSERT INTO cache (id, content, lastModified, expire) VALUES ('$id', '$data', $mktime, $expire)";
00172         $res = $this->_query($sql);
00173         if (!$res) {
00174             $this->_log("Zend_Cache_Backend_Sqlite::save() : impossible to store the cache id=$id");
00175             return false;
00176         }
00177         $res = true;
00178         foreach ($tags as $tag) {
00179             $res = $this->_registerTag($id, $tag) && $res;
00180         }
00181         return $res;
00182     }
00183 
00190     public function remove($id)
00191     {
00192         $this->_checkAndBuildStructure();
00193         $res = $this->_query("SELECT COUNT(*) AS nbr FROM cache WHERE id='$id'");
00194         $result1 = @sqlite_fetch_single($res);
00195         $result2 = $this->_query("DELETE FROM cache WHERE id='$id'");
00196         $result3 = $this->_query("DELETE FROM tag WHERE id='$id'");
00197         $this->_automaticVacuum();
00198         return ($result1 && $result2 && $result3);
00199     }
00200 
00218     public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
00219     {
00220         $this->_checkAndBuildStructure();
00221         $return = $this->_clean($mode, $tags);
00222         $this->_automaticVacuum();
00223         return $return;
00224     }
00225 
00231     public function getIds()
00232     {
00233         $this->_checkAndBuildStructure();
00234         $res = $this->_query("SELECT id FROM cache WHERE (expire=0 OR expire>" . time() . ")");
00235         $result = array();
00236         while ($id = @sqlite_fetch_single($res)) {
00237             $result[] = $id;
00238         }
00239         return $result;
00240     }
00241 
00247     public function getTags()
00248     {
00249         $this->_checkAndBuildStructure();
00250         $res = $this->_query("SELECT DISTINCT(name) AS name FROM tag");
00251         $result = array();
00252         while ($id = @sqlite_fetch_single($res)) {
00253             $result[] = $id;
00254         }
00255         return $result;
00256     }
00257 
00266     public function getIdsMatchingTags($tags = array())
00267     {
00268         $first = true;
00269         $ids = array();
00270         foreach ($tags as $tag) {
00271             $res = $this->_query("SELECT DISTINCT(id) AS id FROM tag WHERE name='$tag'");
00272             if (!$res) {
00273                 return array();
00274             }
00275             $rows = @sqlite_fetch_all($res, SQLITE_ASSOC);
00276             $ids2 = array();
00277             foreach ($rows as $row) {
00278                 $ids2[] = $row['id'];
00279             }
00280             if ($first) {
00281                 $ids = $ids2;
00282                 $first = false;
00283             } else {
00284                 $ids = array_intersect($ids, $ids2);
00285             }
00286         }
00287         $result = array();
00288         foreach ($ids as $id) {
00289             $result[] = $id;
00290         }
00291         return $result;
00292     }
00293 
00302     public function getIdsNotMatchingTags($tags = array())
00303     {
00304         $res = $this->_query("SELECT id FROM cache");
00305         $rows = @sqlite_fetch_all($res, SQLITE_ASSOC);
00306         $result = array();
00307         foreach ($rows as $row) {
00308             $id = $row['id'];
00309             $matching = false;
00310             foreach ($tags as $tag) {
00311                 $res = $this->_query("SELECT COUNT(*) AS nbr FROM tag WHERE name='$tag' AND id='$id'");
00312                 if (!$res) {
00313                     return array();
00314                 }
00315                 $nbr = (int) @sqlite_fetch_single($res);
00316                 if ($nbr > 0) {
00317                     $matching = true;
00318                 }
00319             }
00320             if (!$matching) {
00321                 $result[] = $id;
00322             }
00323         }
00324         return $result;
00325     }
00326 
00335     public function getIdsMatchingAnyTags($tags = array())
00336     {
00337         $first = true;
00338         $ids = array();
00339         foreach ($tags as $tag) {
00340             $res = $this->_query("SELECT DISTINCT(id) AS id FROM tag WHERE name='$tag'");
00341             if (!$res) {
00342                 return array();
00343             }
00344             $rows = @sqlite_fetch_all($res, SQLITE_ASSOC);
00345             $ids2 = array();
00346             foreach ($rows as $row) {
00347                 $ids2[] = $row['id'];
00348             }
00349             if ($first) {
00350                 $ids = $ids2;
00351                 $first = false;
00352             } else {
00353                 $ids = array_merge($ids, $ids2);
00354             }
00355         }
00356         $result = array();
00357         foreach ($ids as $id) {
00358             $result[] = $id;
00359         }
00360         return $result;
00361     }
00362 
00369     public function getFillingPercentage()
00370     {
00371         $dir = dirname($this->_options['cache_db_complete_path']);
00372         $free = disk_free_space($dir);
00373         $total = disk_total_space($dir);
00374         if ($total == 0) {
00375             Zend_Cache::throwException('can\'t get disk_total_space');
00376         } else {
00377             if ($free >= $total) {
00378                 return 100;
00379             }
00380             return ((int) (100. * ($total - $free) / $total));
00381         }
00382     }
00383 
00395     public function getMetadatas($id)
00396     {
00397         $tags = array();
00398         $res = $this->_query("SELECT name FROM tag WHERE id='$id'");
00399         if ($res) {
00400             $rows = @sqlite_fetch_all($res, SQLITE_ASSOC);
00401             foreach ($rows as $row) {
00402                 $tags[] = $row['name'];
00403             }
00404         }
00405         $this->_query('CREATE TABLE cache (id TEXT PRIMARY KEY, content BLOB, lastModified INTEGER, expire INTEGER)');
00406         $res = $this->_query("SELECT lastModified,expire FROM cache WHERE id='$id'");
00407         if (!$res) {
00408             return false;
00409         }
00410         $row = @sqlite_fetch_array($res, SQLITE_ASSOC);
00411         return array(
00412             'tags' => $tags,
00413             'mtime' => $row['lastModified'],
00414             'expire' => $row['expire']
00415         );
00416     }
00417 
00425     public function touch($id, $extraLifetime)
00426     {
00427         $sql = "SELECT expire FROM cache WHERE id='$id' AND (expire=0 OR expire>" . time() . ')';
00428         $res = $this->_query($sql);
00429         if (!$res) {
00430             return false;
00431         }
00432         $expire = @sqlite_fetch_single($res);
00433         $newExpire = $expire + $extraLifetime;
00434         $res = $this->_query("UPDATE cache SET lastModified=" . time() . ", expire=$newExpire WHERE id='$id'");
00435         if ($res) {
00436             return true;
00437         } else {
00438             return false;
00439         }
00440     }
00441 
00456     public function getCapabilities()
00457     {
00458         return array(
00459             'automatic_cleaning' => true,
00460             'tags' => true,
00461             'expired_read' => true,
00462             'priority' => false,
00463             'infinite_lifetime' => true,
00464             'get_list' => true
00465         );
00466     }
00467 
00475     public function ___expire($id)
00476     {
00477         $time = time() - 1;
00478         $this->_query("UPDATE cache SET lastModified=$time, expire=$time WHERE id='$id'");
00479     }
00480 
00489     private function _getConnection()
00490     {
00491         if (is_resource($this->_db)) {
00492             return $this->_db;
00493         } else {
00494             $this->_db = @sqlite_open($this->_options['cache_db_complete_path']);
00495             if (!(is_resource($this->_db))) {
00496                 Zend_Cache::throwException("Impossible to open " . $this->_options['cache_db_complete_path'] . " cache DB file");
00497             }
00498             return $this->_db;
00499         }
00500     }
00501 
00508     private function _query($query)
00509     {
00510         $db = $this->_getConnection();
00511         if (is_resource($db)) {
00512             $res = @sqlite_query($db, $query);
00513             if ($res === false) {
00514                 return false;
00515             } else {
00516                 return $res;
00517             }
00518         }
00519         return false;
00520     }
00521 
00527     private function _automaticVacuum()
00528     {
00529         if ($this->_options['automatic_vacuum_factor'] > 0) {
00530             $rand = rand(1, $this->_options['automatic_vacuum_factor']);
00531             if ($rand == 1) {
00532                 $this->_query('VACUUM');
00533                 @sqlite_close($this->_getConnection());
00534             }
00535         }
00536     }
00537 
00545     private function _registerTag($id, $tag) {
00546         $res = $this->_query("DELETE FROM TAG WHERE name='$tag' AND id='$id'");
00547         $res = $this->_query("INSERT INTO tag (name, id) VALUES ('$tag', '$id')");
00548         if (!$res) {
00549             $this->_log("Zend_Cache_Backend_Sqlite::_registerTag() : impossible to register tag=$tag on id=$id");
00550             return false;
00551         }
00552         return true;
00553     }
00554 
00560     private function _buildStructure()
00561     {
00562         $this->_query('DROP INDEX tag_id_index');
00563         $this->_query('DROP INDEX tag_name_index');
00564         $this->_query('DROP INDEX cache_id_expire_index');
00565         $this->_query('DROP TABLE version');
00566         $this->_query('DROP TABLE cache');
00567         $this->_query('DROP TABLE tag');
00568         $this->_query('CREATE TABLE version (num INTEGER PRIMARY KEY)');
00569         $this->_query('CREATE TABLE cache (id TEXT PRIMARY KEY, content BLOB, lastModified INTEGER, expire INTEGER)');
00570         $this->_query('CREATE TABLE tag (name TEXT, id TEXT)');
00571         $this->_query('CREATE INDEX tag_id_index ON tag(id)');
00572         $this->_query('CREATE INDEX tag_name_index ON tag(name)');
00573         $this->_query('CREATE INDEX cache_id_expire_index ON cache(id, expire)');
00574         $this->_query('INSERT INTO version (num) VALUES (1)');
00575     }
00576 
00582     private function _checkStructureVersion()
00583     {
00584         $result = $this->_query("SELECT num FROM version");
00585         if (!$result) return false;
00586         $row = @sqlite_fetch_array($result);
00587         if (!$row) {
00588             return false;
00589         }
00590         if (((int) $row['num']) != 1) {
00591             // old cache structure
00592             $this->_log('Zend_Cache_Backend_Sqlite::_checkStructureVersion() : old cache structure version detected => the cache is going to be dropped');
00593             return false;
00594         }
00595         return true;
00596     }
00597 
00615     private function _clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
00616     {
00617         switch ($mode) {
00618             case Zend_Cache::CLEANING_MODE_ALL:
00619                 $res1 = $this->_query('DELETE FROM cache');
00620                 $res2 = $this->_query('DELETE FROM tag');
00621                 return $res1 && $res2;
00622                 break;
00623             case Zend_Cache::CLEANING_MODE_OLD:
00624                 $mktime = time();
00625                 $res1 = $this->_query("DELETE FROM tag WHERE id IN (SELECT id FROM cache WHERE expire>0 AND expire<=$mktime)");
00626                 $res2 = $this->_query("DELETE FROM cache WHERE expire>0 AND expire<=$mktime");
00627                 return $res1 && $res2;
00628                 break;
00629             case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
00630                 $ids = $this->getIdsMatchingTags($tags);
00631                 $result = true;
00632                 foreach ($ids as $id) {
00633                     $result = $this->remove($id) && $result;
00634                 }
00635                 return $result;
00636                 break;
00637             case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
00638                 $ids = $this->getIdsNotMatchingTags($tags);
00639                 $result = true;
00640                 foreach ($ids as $id) {
00641                     $result = $this->remove($id) && $result;
00642                 }
00643                 return $result;
00644                 break;
00645             case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
00646                 $ids = $this->getIdsMatchingAnyTags($tags);
00647                 $result = true;
00648                 foreach ($ids as $id) {
00649                     $result = $this->remove($id) && $result;
00650                 }
00651                 return $result;
00652                 break;
00653             default:
00654                 break;
00655         }
00656         return false;
00657     }
00658 
00665     private function _checkAndBuildStructure()
00666     {
00667         if (!($this->_structureChecked)) {
00668             if (!$this->_checkStructureVersion()) {
00669                 $this->_buildStructure();
00670                 if (!$this->_checkStructureVersion()) {
00671                     Zend_Cache::throwException("Impossible to build cache structure in " . $this->_options['cache_db_complete_path']);
00672                 }
00673             }
00674             $this->_structureChecked = true;
00675         }
00676         return true;
00677     }
00678 
00679 }

Generated on Thu Apr 19 2012 17:01:16 for openbiz by  doxygen 1.7.2