PageRenderTime 43ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/include/Cache/Container/mdb.php

https://github.com/usagi-project/mynets1
PHP | 380 lines | 218 code | 30 blank | 132 comment | 32 complexity | 0fc2dd9e4e4e0df62e78ec009f05f1c9 MD5 | raw file
  1. <?php
  2. // +----------------------------------------------------------------------+
  3. // | PEAR :: Cache :: MDB Container |
  4. // +----------------------------------------------------------------------+
  5. // | Copyright (c) 1997-2003 The PHP Group |
  6. // +----------------------------------------------------------------------+
  7. // | This source file is subject to version 2.0 of the PHP license, |
  8. // | that is bundled with this package in the file LICENSE, and is |
  9. // | available at through the world-wide-web at |
  10. // | http://www.php.net/license/2_02.txt. |
  11. // | If you did not receive a copy of the PHP license and are unable to |
  12. // | obtain it through the world-wide-web, please send a note to |
  13. // | license@php.net so we can mail you a copy immediately. |
  14. // +----------------------------------------------------------------------+
  15. // | Note: This is a MDB-oriented rewrite of Cache/Container/db.php. |
  16. // | Thanks to Lukas Smith for his patience in answering my questions |
  17. // +----------------------------------------------------------------------+
  18. // | Author: Lorenzo Alberton <l.alberton at quipo.it> |
  19. // +----------------------------------------------------------------------+
  20. //
  21. // $Id: mdb.php,v 1.5 2004/12/15 09:09:30 dufuz Exp $
  22. require_once 'MDB.php';
  23. require_once 'Cache/Container.php';
  24. /**
  25. * PEAR/MDB Cache Container.
  26. *
  27. * NB: The field 'changed' has no meaning for the Cache itself. It's just there
  28. * because it's a good idea to have an automatically updated timestamp
  29. * field for debugging in all of your tables.
  30. *
  31. * A XML MDB-compliant schema example for the table needed is provided.
  32. * Look at the file "mdb_cache_schema.xml" for that.
  33. *
  34. * ------------------------------------------
  35. * A basic usage example:
  36. * ------------------------------------------
  37. *
  38. * $dbinfo = array(
  39. * 'database' => 'dbname',
  40. * 'phptype' => 'mysql',
  41. * 'username' => 'root',
  42. * 'password' => '',
  43. * 'cache_table' => 'cache'
  44. * );
  45. *
  46. *
  47. * $cache = new Cache('mdb', $dbinfo);
  48. * $id = $cache->generateID('testentry');
  49. *
  50. * if ($data = $cache->get($id)) {
  51. * echo 'Cache hit.<br />Data: '.$data;
  52. *
  53. * } else {
  54. * $data = 'data of any kind';
  55. * $cache->save($id, $data);
  56. * echo 'Cache miss.<br />';
  57. * }
  58. *
  59. * ------------------------------------------
  60. *
  61. * @author Lorenzo Alberton <l.alberton at quipo.it>
  62. * @version $Id: mdb.php,v 1.5 2004/12/15 09:09:30 dufuz Exp $
  63. * @package Cache
  64. */
  65. class Cache_Container_mdb extends Cache_Container
  66. {
  67. /**
  68. * Name of the MDB table to store caching data
  69. *
  70. * @see Cache_Container_file::$filename_prefix
  71. */
  72. var $cache_table = '';
  73. /**
  74. * PEAR MDB object
  75. *
  76. * @var object PEAR_MDB
  77. */
  78. var $db;
  79. /**
  80. * Constructor
  81. *
  82. * @param mixed Array with connection info or dsn string
  83. */
  84. function Cache_Container_mdb($options)
  85. {
  86. $this->db = &MDB::Connect($options);
  87. if (MDB::isError($this->db)) {
  88. return new Cache_Error('MDB::connect failed: '
  89. . $this->db->getMessage(), __FILE__, __LINE__);
  90. } else {
  91. $this->db->setFetchMode(MDB_FETCHMODE_ASSOC);
  92. }
  93. $this->setOptions($options, array_merge($this->allowed_options,
  94. array('dsn', 'cache_table')));
  95. }
  96. /**
  97. * Fetch in the db the data that matches input parameters
  98. *
  99. * @param string dataset ID
  100. * @param string cache group
  101. * @return mixed dataset value or null/Cache_Error on failure
  102. * @access public
  103. */
  104. function fetch($id, $group)
  105. {
  106. $query = 'SELECT cachedata FROM ' . $this->cache_table
  107. .' WHERE id=' . $this->db->getTextValue($id)
  108. .' AND cachegroup=' . $this->db->getTextValue($group);
  109. if ($res = $this->db->query($query)) {
  110. if ($this->db->endOfResult($res)) {
  111. //no rows returned
  112. $data = array(null, null, null);
  113. } else {
  114. $clob = $this->db->fetchClob($res,0,'cachedata');
  115. if (!MDB::isError($clob)) {
  116. $cached_data = '';
  117. while(!$this->db->endOfLOB($clob)) {
  118. if (MDB::isError($error =
  119. $this->db->readLob($clob,$data,8000)<0)) {
  120. return new Cache_Error('MDB::query failed: '
  121. . $error->getMessage(), __FILE__, __LINE__);
  122. }
  123. $cached_data .= $data;
  124. }
  125. unset($data);
  126. $this->db->destroyLob($clob);
  127. $this->db->freeResult($res);
  128. //finished fetching LOB, now fetch other fields...
  129. $query = 'SELECT userdata, expires FROM ' . $this->cache_table
  130. .' WHERE id=' . $this->db->getTextValue($id)
  131. .' AND cachegroup=' . $this->db->getTextValue($group);
  132. if ($res = $this->db->query($query)) {
  133. $row = $this->db->fetchInto($res);
  134. if (is_array($row)) {
  135. $data = array(
  136. $row['expires'],
  137. $this->decode($cached_data),
  138. $row['userdata']
  139. );
  140. } else {
  141. $data = array(null, null, null);
  142. }
  143. } else {
  144. $data = array(null, null, null);
  145. }
  146. } else {
  147. return new Cache_Error('MDB::query failed: '
  148. . $clob->getMessage(), __FILE__, __LINE__);
  149. }
  150. }
  151. $this->db->freeResult($res);
  152. } else {
  153. //return new Cache_Error('MDB::query failed: '
  154. // . $result->getMessage(), __FILE__, __LINE__);
  155. $data = array(null, null, null);
  156. }
  157. // last used required by the garbage collection
  158. $query = 'UPDATE ' . $this->cache_table
  159. .' SET changed=' . time()
  160. .' WHERE id=' . $this->db->getTextValue($id)
  161. .' AND cachegroup=' . $this->db->getTextValue($group);
  162. $res = $this->db->query($query);
  163. if (MDB::isError($res)) {
  164. return new Cache_Error('MDB::query failed: '
  165. . $this->db->errorMessage($res), __FILE__, __LINE__);
  166. }
  167. return $data;
  168. }
  169. /**
  170. * Stores a dataset in the database
  171. *
  172. * If dataset_ID already exists, overwrite it with new data,
  173. * else insert data in a new record.
  174. *
  175. * @param string dataset ID
  176. * @param mixed data to be cached
  177. * @param integer expiration time
  178. * @param string cache group
  179. * @param string userdata
  180. * @access public
  181. */
  182. function save($id, $data, $expires, $group, $userdata)
  183. {
  184. global $db;
  185. $this->flushPreload($id, $group);
  186. $fields = array(
  187. 'id' => array(
  188. 'Type' => 'text',
  189. 'Value' => $id,
  190. 'Key' => true
  191. ),
  192. 'userdata' => array(
  193. 'Type' => 'integer',
  194. 'Value' => $userdata,
  195. 'null' => ($userdata ? false : true)
  196. ),
  197. 'expires' => array(
  198. 'Type' => 'integer',
  199. 'Value' => $this->getExpiresAbsolute($expires)
  200. ),
  201. 'cachegroup' => array(
  202. 'Type' => 'text',
  203. 'Value' => $group
  204. )
  205. );
  206. $result = $this->db->replace($this->cache_table, $fields);
  207. if (MDB::isError($result)) {
  208. //Var_Dump::display($result);
  209. return new Cache_Error('MDB::query failed: '
  210. . $this->db->errorMessage($result), __FILE__, __LINE__);
  211. }
  212. unset($fields); //end first part of query
  213. $query2 = 'UPDATE ' . $this->cache_table
  214. .' SET cachedata=?'
  215. .' WHERE id='. $this->db->getTextValue($id);
  216. if (($prepared_query = $this->db->prepareQuery($query2))) {
  217. $char_lob = array(
  218. 'Error' => '',
  219. 'Type' => 'data',
  220. 'Data' => $this->encode($data)
  221. );
  222. if (!MDB::isError($clob = $this->db->createLob($char_lob))) {
  223. $this->db->setParamClob($prepared_query,1,$clob,'cachedata');
  224. if(MDB::isError($error=$this->db->executeQuery($prepared_query))) {
  225. return new Cache_Error('MDB::query failed: '
  226. . $error->getMessage() , __FILE__, __LINE__);
  227. }
  228. $this->db->destroyLob($clob);
  229. } else {
  230. // creation of the handler object failed
  231. return new Cache_Error('MDB::query failed: '
  232. . $clob->getMessage() , __FILE__, __LINE__);
  233. }
  234. $this->db->freePreparedQuery($prepared_query);
  235. } else {
  236. //prepared query failed
  237. return new Cache_Error('MDB::query failed: '
  238. . $prepared_query->getMessage() , __FILE__, __LINE__);
  239. }
  240. }
  241. /**
  242. * Removes a dataset from the database
  243. *
  244. * @param string dataset ID
  245. * @param string cache group
  246. */
  247. function remove($id, $group)
  248. {
  249. $this->flushPreload($id, $group);
  250. $query = 'DELETE FROM ' . $this->cache_table
  251. .' WHERE id=' . $this->db->getTextValue($id)
  252. .' AND cachegroup=' . $this->db->getTextValue($group);
  253. $res = $this->db->query($query);
  254. if (MDB::isError($res)) {
  255. return new Cache_Error('MDB::query failed: '
  256. . $this->db->errorMessage($res), __FILE__, __LINE__);
  257. }
  258. }
  259. /**
  260. * Remove all cached data for a certain group, or empty
  261. * the cache table if no group is specified.
  262. *
  263. * @param string cache group
  264. */
  265. function flush($group = '')
  266. {
  267. $this->flushPreload();
  268. if ($group) {
  269. $query = 'DELETE FROM ' . $this->cache_table
  270. .' WHERE cachegroup=' . $this->db->getTextValue($group);
  271. } else {
  272. $query = 'DELETE FROM ' . $this->cache_table;
  273. }
  274. $res = $this->db->query($query);
  275. if (MDB::isError($res)) {
  276. return new Cache_Error('MDB::query failed: '
  277. . $this->db->errorMessage($res), __FILE__, __LINE__);
  278. }
  279. }
  280. /**
  281. * Check if a dataset ID/group exists.
  282. *
  283. * @param string dataset ID
  284. * @param string cache group
  285. * @return boolean
  286. */
  287. function idExists($id, $group)
  288. {
  289. $query = 'SELECT id FROM ' . $this->cache_table
  290. .' WHERE id=' . $this->db->getTextValue($id)
  291. .' AND cachegroup=' . $this->db->getTextValue($group);
  292. echo $query;
  293. $res = $this->db->query($query);
  294. if (MDB::isError($res)) {
  295. return new Cache_Error('MDB::query failed: '
  296. . $this->db->errorMessage($res), __FILE__, __LINE__);
  297. }
  298. $row = $this->db->fetchInto($res);
  299. if (is_array($row)) {
  300. return true;
  301. }
  302. return false;
  303. }
  304. /**
  305. * Garbage collector.
  306. *
  307. * @param int maxlifetime
  308. */
  309. function garbageCollection($maxlifetime)
  310. {
  311. $this->flushPreload();
  312. $query = 'DELETE FROM ' . $this->cache_table
  313. .' WHERE (expires <= ' . time()
  314. .' AND expires > 0) OR changed <= '. time() - $maxlifetime;
  315. $res = $this->db->query($query);
  316. $query = 'SELECT sum(length(cachedata)) as CacheSize FROM '
  317. . $this->cache_table;
  318. $cachesize = $this->db->getOne($query);
  319. if (MDB::isError($cachesize)) {
  320. return new Cache_Error('MDB::query failed: '
  321. . $this->db->errorMessage($cachesize), __FILE__, __LINE__);
  322. }
  323. //if cache is to big.
  324. if ($cachesize > $this->highwater) {
  325. //find the lowwater mark.
  326. $query = 'SELECT length(cachedata) as size, changed FROM '
  327. . $this->cache_table .' ORDER BY changed DESC';
  328. $res = $this->db->query($query);
  329. if (MDB::isError($res)) {
  330. return new Cache_Error('MDB::query failed: '
  331. . $this->db->errorMessage($res), __FILE__, __LINE__);
  332. }
  333. $numrows = $this->db->numRows($res);
  334. $keep_size = 0;
  335. while ($keep_size < $this->lowwater && $numrows--) {
  336. $entry = $this->db->fetchInto($res,MDB_FETCHMODE_ASSOC);
  337. $keep_size += $entry['size'];
  338. }
  339. //delete all entries, which were changed before the "lowwater mark"
  340. $query = 'DELETE FROM ' . $this->cache_table
  341. .' WHERE changed<='.($entry['changed'] ? $entry['changed'] : 0);
  342. $res = $this->db->query($query);
  343. if (MDB::isError($res)) {
  344. return new Cache_Error('MDB::query failed: '
  345. . $this->db->errorMessage($res), __FILE__, __LINE__);
  346. }
  347. }
  348. }
  349. }
  350. ?>