| 1 |
lars |
1 |
<?php
|
|
|
2 |
/**
|
|
|
3 |
* TSqliteCache class file
|
|
|
4 |
*
|
|
|
5 |
* @author Qiang Xue <qiang.xue@gmail.com>
|
|
|
6 |
* @link http://www.pradosoft.com/
|
|
|
7 |
* @copyright Copyright © 2005-2008 PradoSoft
|
|
|
8 |
* @license http://www.pradosoft.com/license/
|
|
|
9 |
* @version $Id: TSqliteCache.php 2541 2008-10-21 15:05:13Z qiang.xue $
|
|
|
10 |
* @package System.Caching
|
|
|
11 |
*/
|
|
|
12 |
|
|
|
13 |
/**
|
|
|
14 |
* TSqliteCache class
|
|
|
15 |
*
|
|
|
16 |
* TSqliteCache implements a cache application module based on SQLite database.
|
|
|
17 |
*
|
|
|
18 |
* To use this module, the sqlite PHP extension must be loaded. Note, Sqlite extension
|
|
|
19 |
* is no longer loaded by default since PHP 5.1.
|
|
|
20 |
*
|
|
|
21 |
* Sine PRADO v3.1.0, a new DB-based cache module called {@link TDbCache}
|
|
|
22 |
* is provided. If you have PDO extension installed, you may consider using
|
|
|
23 |
* the new cache module instead as it allows you to use different database
|
|
|
24 |
* to store the cached data.
|
|
|
25 |
*
|
|
|
26 |
* The database file is specified by the {@link setDbFile DbFile} property.
|
|
|
27 |
* If not set, the database file will be created under the system state path.
|
|
|
28 |
* If the specified database file does not exist, it will be created automatically.
|
|
|
29 |
* Make sure the directory containing the specified DB file and the file itself is
|
|
|
30 |
* writable by the Web server process.
|
|
|
31 |
*
|
|
|
32 |
* The following basic cache operations are implemented:
|
|
|
33 |
* - {@link get} : retrieve the value with a key (if any) from cache
|
|
|
34 |
* - {@link set} : store the value with a key into cache
|
|
|
35 |
* - {@link add} : store the value only if cache does not have this key
|
|
|
36 |
* - {@link delete} : delete the value with the specified key from cache
|
|
|
37 |
* - {@link flush} : delete all values from cache
|
|
|
38 |
*
|
|
|
39 |
* Each value is associated with an expiration time. The {@link get} operation
|
|
|
40 |
* ensures that any expired value will not be returned. The expiration time by
|
|
|
41 |
* the number of seconds. A expiration time 0 represents never expire.
|
|
|
42 |
*
|
|
|
43 |
* By definition, cache does not ensure the existence of a value
|
|
|
44 |
* even if it never expires. Cache is not meant to be an persistent storage.
|
|
|
45 |
*
|
|
|
46 |
* Do not use the same database file for multiple applications using TSqliteCache.
|
|
|
47 |
* Also note, cache is shared by all user sessions of an application.
|
|
|
48 |
*
|
|
|
49 |
* Some usage examples of TSqliteCache are as follows,
|
|
|
50 |
* <code>
|
|
|
51 |
* $cache=new TSqliteCache; // TSqliteCache may also be loaded as a Prado application module
|
|
|
52 |
* $cache->setDbFile($dbFilePath);
|
|
|
53 |
* $cache->init(null);
|
|
|
54 |
* $cache->add('object',$object);
|
|
|
55 |
* $object2=$cache->get('object');
|
|
|
56 |
* </code>
|
|
|
57 |
*
|
|
|
58 |
* If loaded, TSqliteCache will register itself with {@link TApplication} as the
|
|
|
59 |
* cache module. It can be accessed via {@link TApplication::getCache()}.
|
|
|
60 |
*
|
|
|
61 |
* TSqliteCache may be configured in application configuration file as follows
|
|
|
62 |
* <code>
|
|
|
63 |
* <module id="cache" class="System.Caching.TSqliteCache" DbFile="Application.Data.site" />
|
|
|
64 |
* </code>
|
|
|
65 |
* where {@link getDbFile DbFile} is a property specifying the location of the
|
|
|
66 |
* SQLite DB file (in the namespace format).
|
|
|
67 |
*
|
|
|
68 |
* @author Qiang Xue <qiang.xue@gmail.com>
|
|
|
69 |
* @version $Id: TSqliteCache.php 2541 2008-10-21 15:05:13Z qiang.xue $
|
|
|
70 |
* @package System.Caching
|
|
|
71 |
* @since 3.0
|
|
|
72 |
*/
|
|
|
73 |
class TSqliteCache extends TCache
|
|
|
74 |
{
|
|
|
75 |
/**
|
|
|
76 |
* name of the table storing cache data
|
|
|
77 |
*/
|
|
|
78 |
const CACHE_TABLE='cache';
|
|
|
79 |
/**
|
|
|
80 |
* extension of the db file name
|
|
|
81 |
*/
|
|
|
82 |
const DB_FILE_EXT='.db';
|
|
|
83 |
|
|
|
84 |
/**
|
|
|
85 |
* @var boolean if the module has been initialized
|
|
|
86 |
*/
|
|
|
87 |
private $_initialized=false;
|
|
|
88 |
/**
|
|
|
89 |
* @var SQLiteDatabase the sqlite database instance
|
|
|
90 |
*/
|
|
|
91 |
private $_db=null;
|
|
|
92 |
/**
|
|
|
93 |
* @var string the database file name
|
|
|
94 |
*/
|
|
|
95 |
private $_file=null;
|
|
|
96 |
|
|
|
97 |
/**
|
|
|
98 |
* Destructor.
|
|
|
99 |
* Disconnect the db connection.
|
|
|
100 |
*/
|
|
|
101 |
public function __destruct()
|
|
|
102 |
{
|
|
|
103 |
$this->_db=null;
|
|
|
104 |
}
|
|
|
105 |
|
|
|
106 |
/**
|
|
|
107 |
* Initializes this module.
|
|
|
108 |
* This method is required by the IModule interface. It checks if the DbFile
|
|
|
109 |
* property is set, and creates a SQLiteDatabase instance for it.
|
|
|
110 |
* The database or the cache table does not exist, they will be created.
|
|
|
111 |
* Expired values are also deleted.
|
|
|
112 |
* @param TXmlElement configuration for this module, can be null
|
|
|
113 |
* @throws TConfigurationException if sqlite extension is not installed,
|
|
|
114 |
* DbFile is set invalid, or any error happens during creating database or cache table.
|
|
|
115 |
*/
|
|
|
116 |
public function init($config)
|
|
|
117 |
{
|
|
|
118 |
if(!function_exists('sqlite_open'))
|
|
|
119 |
throw new TConfigurationException('sqlitecache_extension_required');
|
|
|
120 |
if($this->_file===null)
|
|
|
121 |
$this->_file=$this->getApplication()->getRuntimePath().'/sqlite.cache';
|
|
|
122 |
$error='';
|
|
|
123 |
if(($this->_db=new SQLiteDatabase($this->_file,0666,$error))===false)
|
|
|
124 |
throw new TConfigurationException('sqlitecache_connection_failed',$error);
|
|
|
125 |
if(@$this->_db->query('DELETE FROM '.self::CACHE_TABLE.' WHERE expire<>0 AND expire<'.time())===false)
|
|
|
126 |
{
|
|
|
127 |
if($this->_db->query('CREATE TABLE '.self::CACHE_TABLE.' (key CHAR(128) PRIMARY KEY, value BLOB, expire INT)')===false)
|
|
|
128 |
throw new TConfigurationException('sqlitecache_table_creation_failed',sqlite_error_string(sqlite_last_error()));
|
|
|
129 |
}
|
|
|
130 |
$this->_initialized=true;
|
|
|
131 |
parent::init($config);
|
|
|
132 |
}
|
|
|
133 |
|
|
|
134 |
/**
|
|
|
135 |
* @return string database file path (in namespace form)
|
|
|
136 |
*/
|
|
|
137 |
public function getDbFile()
|
|
|
138 |
{
|
|
|
139 |
return $this->_file;
|
|
|
140 |
}
|
|
|
141 |
|
|
|
142 |
/**
|
|
|
143 |
* @param string database file path (in namespace form)
|
|
|
144 |
* @throws TInvalidOperationException if the module is already initialized
|
|
|
145 |
* @throws TConfigurationException if the file is not in proper namespace format
|
|
|
146 |
*/
|
|
|
147 |
public function setDbFile($value)
|
|
|
148 |
{
|
|
|
149 |
if($this->_initialized)
|
|
|
150 |
throw new TInvalidOperationException('sqlitecache_dbfile_unchangeable');
|
|
|
151 |
else if(($this->_file=Prado::getPathOfNamespace($value,self::DB_FILE_EXT))===null)
|
|
|
152 |
throw new TConfigurationException('sqlitecache_dbfile_invalid',$value);
|
|
|
153 |
}
|
|
|
154 |
|
|
|
155 |
/**
|
|
|
156 |
* Retrieves a value from cache with a specified key.
|
|
|
157 |
* This is the implementation of the method declared in the parent class.
|
|
|
158 |
* @param string a unique key identifying the cached value
|
|
|
159 |
* @return string the value stored in cache, false if the value is not in the cache or expired.
|
|
|
160 |
*/
|
|
|
161 |
protected function getValue($key)
|
|
|
162 |
{
|
|
|
163 |
$sql='SELECT value FROM '.self::CACHE_TABLE.' WHERE key=\''.$key.'\' AND (expire=0 OR expire>'.time().') LIMIT 1';
|
|
|
164 |
if(($ret=$this->_db->query($sql))!=false && ($row=$ret->fetch(SQLITE_ASSOC))!==false)
|
|
|
165 |
return $row['value'];
|
|
|
166 |
else
|
|
|
167 |
return false;
|
|
|
168 |
}
|
|
|
169 |
|
|
|
170 |
/**
|
|
|
171 |
* Stores a value identified by a key in cache.
|
|
|
172 |
* This is the implementation of the method declared in the parent class.
|
|
|
173 |
*
|
|
|
174 |
* @param string the key identifying the value to be cached
|
|
|
175 |
* @param string the value to be cached
|
|
|
176 |
* @param integer the number of seconds in which the cached value will expire. 0 means never expire.
|
|
|
177 |
* @return boolean true if the value is successfully stored into cache, false otherwise
|
|
|
178 |
*/
|
|
|
179 |
protected function setValue($key,$value,$expire)
|
|
|
180 |
{
|
|
|
181 |
$expire=($expire<=0)?0:time()+$expire;
|
|
|
182 |
$sql='REPLACE INTO '.self::CACHE_TABLE.' VALUES(\''.$key.'\',\''.sqlite_escape_string($value).'\','.$expire.')';
|
|
|
183 |
return $this->_db->query($sql)!==false;
|
|
|
184 |
}
|
|
|
185 |
|
|
|
186 |
/**
|
|
|
187 |
* Stores a value identified by a key into cache if the cache does not contain this key.
|
|
|
188 |
* This is the implementation of the method declared in the parent class.
|
|
|
189 |
*
|
|
|
190 |
* @param string the key identifying the value to be cached
|
|
|
191 |
* @param string the value to be cached
|
|
|
192 |
* @param integer the number of seconds in which the cached value will expire. 0 means never expire.
|
|
|
193 |
* @return boolean true if the value is successfully stored into cache, false otherwise
|
|
|
194 |
*/
|
|
|
195 |
protected function addValue($key,$value,$expire)
|
|
|
196 |
{
|
|
|
197 |
$expire=($expire<=0)?0:time()+$expire;
|
|
|
198 |
$sql='INSERT INTO '.self::CACHE_TABLE.' VALUES(\''.$key.'\',\''.sqlite_escape_string($value).'\','.$expire.')';
|
|
|
199 |
return @$this->_db->query($sql)!==false;
|
|
|
200 |
}
|
|
|
201 |
|
|
|
202 |
/**
|
|
|
203 |
* Deletes a value with the specified key from cache
|
|
|
204 |
* This is the implementation of the method declared in the parent class.
|
|
|
205 |
* @param string the key of the value to be deleted
|
|
|
206 |
* @return boolean if no error happens during deletion
|
|
|
207 |
*/
|
|
|
208 |
protected function deleteValue($key)
|
|
|
209 |
{
|
|
|
210 |
$sql='DELETE FROM '.self::CACHE_TABLE.' WHERE key=\''.$key.'\'';
|
|
|
211 |
return $this->_db->query($sql)!==false;
|
|
|
212 |
}
|
|
|
213 |
|
|
|
214 |
/**
|
|
|
215 |
* Deletes all values from cache.
|
|
|
216 |
* Be careful of performing this operation if the cache is shared by multiple applications.
|
|
|
217 |
*/
|
|
|
218 |
public function flush()
|
|
|
219 |
{
|
|
|
220 |
return $this->_db->query('DELETE FROM '.self::CACHE_TABLE)!==false;
|
|
|
221 |
}
|
|
|
222 |
}
|
|
|
223 |
|