PageRenderTime 24ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/engine/lib/cache.php

https://github.com/masuman/elgg-1
PHP | 439 lines | 167 code | 68 blank | 204 comment | 19 complexity | 45b4b7723e5ef4fab08c02bc4db158b9 MD5 | raw file
  1. <?php
  2. /**
  3. * Elgg cache
  4. * Cache file interface for caching data.
  5. *
  6. * @package Elgg
  7. * @subpackage API
  8. * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2
  9. * @author Curverider Ltd <info@elgg.com>
  10. * @copyright Curverider Ltd 2008-2009
  11. * @link http://elgg.org/
  12. */
  13. /**
  14. * ElggCache The elgg cache superclass.
  15. * This defines the interface for a cache (wherever that cache is stored).
  16. *
  17. * @author Curverider Ltd <info@elgg.com>
  18. * @package Elgg
  19. * @subpackage API
  20. */
  21. abstract class ElggCache implements
  22. ArrayAccess // Override for array access
  23. {
  24. /**
  25. * Variables for the cache object.
  26. *
  27. * @var array
  28. */
  29. private $variables;
  30. /**
  31. * Set the constructor.
  32. */
  33. function __construct() { $this->variables = array(); }
  34. /**
  35. * Set a cache variable.
  36. *
  37. * @param string $variable
  38. * @param string $value
  39. */
  40. public function set_variable($variable, $value)
  41. {
  42. if (!is_array($this->variables))
  43. $this->variables = array();
  44. $this->variables[$variable] = $value;
  45. }
  46. /**
  47. * Get variables for this cache.
  48. *
  49. * @param string $variable
  50. * @return mixed The variable or null;
  51. */
  52. public function get_variable($variable)
  53. {
  54. if (isset($this->variables[$variable]))
  55. return $this->variables[$variable];
  56. return null;
  57. }
  58. /**
  59. * Class member get overloading, returning key using $this->load defaults.
  60. *
  61. * @param string $key
  62. * @return mixed
  63. */
  64. function __get($key) { return $this->load($key); }
  65. /**
  66. * Class member set overloading, setting a key using $this->save defaults.
  67. *
  68. * @param string $key
  69. * @param mixed $value
  70. * @return mixed
  71. */
  72. function __set($key, $value) { return $this->save($key, $value); }
  73. /**
  74. * Supporting isset, using $this->load() with default values.
  75. *
  76. * @param string $key The name of the attribute or metadata.
  77. * @return bool
  78. */
  79. function __isset($key) { return (bool)$this->load($key); }
  80. /**
  81. * Supporting unsetting of magic attributes.
  82. *
  83. * @param string $key The name of the attribute or metadata.
  84. */
  85. function __unset($key) { return $this->delete($key); }
  86. /**
  87. * Save data in a cache.
  88. *
  89. * @param string $key
  90. * @param string $data
  91. * @return bool
  92. */
  93. abstract public function save($key, $data);
  94. /**
  95. * Load data from the cache using a given key.
  96. *
  97. * @param string $key
  98. * @param int $offset
  99. * @param int $limit
  100. * @return mixed The stored data or false.
  101. */
  102. abstract public function load($key, $offset = 0, $limit = null);
  103. /**
  104. * Invalidate a key
  105. *
  106. * @param string $key
  107. * @return bool
  108. */
  109. abstract public function delete($key);
  110. /**
  111. * Clear out all the contents of the cache.
  112. *
  113. */
  114. abstract public function clear();
  115. /**
  116. * Add a key only if it doesn't already exist.
  117. * Implemented simply here, if you extend this class and your caching engine provides a better way then
  118. * override this accordingly.
  119. *
  120. * @param string $key
  121. * @param string $data
  122. * @return bool
  123. */
  124. public function add($key, $data)
  125. {
  126. if (!isset($this[$key]))
  127. return $this->save($key, $data);
  128. return false;
  129. }
  130. // ARRAY ACCESS INTERFACE //////////////////////////////////////////////////////////
  131. function offsetSet($key, $value)
  132. {
  133. $this->save($key, $value);
  134. }
  135. function offsetGet($key)
  136. {
  137. return $this->load($key);
  138. }
  139. function offsetUnset($key)
  140. {
  141. if ( isset($this->key) ) {
  142. unset($this->key);
  143. }
  144. }
  145. function offsetExists($offset)
  146. {
  147. return isset($this->$offset);
  148. }
  149. }
  150. /**
  151. * Shared memory cache description.
  152. * Extends ElggCache with functions useful to shared memory style caches (static variables, memcache etc)
  153. */
  154. abstract class ElggSharedMemoryCache extends ElggCache
  155. {
  156. /**
  157. * Namespace variable used to keep various bits of the cache
  158. * separate.
  159. *
  160. * @var string
  161. */
  162. private $namespace;
  163. /**
  164. * Set the namespace of this cache.
  165. * This is useful for cache types (like memcache or static variables) where there is one large
  166. * flat area of memory shared across all instances of the cache.
  167. *
  168. * @param string $namespace
  169. */
  170. public function setNamespace($namespace = "default") { $this->namespace = $namespace; }
  171. /**
  172. * Get the namespace currently defined.
  173. *
  174. * @return string
  175. */
  176. public function getNamespace() { return $this->namespace; }
  177. }
  178. /**
  179. * ElggStaticVariableCache
  180. * Dummy cache which stores values in a static array. Using this makes future replacements to other caching back
  181. * ends (eg memcache) much easier.
  182. *
  183. * @author Curverider Ltd <info@elgg.com>
  184. * @package Elgg
  185. * @subpackage API
  186. */
  187. class ElggStaticVariableCache extends ElggSharedMemoryCache
  188. {
  189. /**
  190. * The cache.
  191. *
  192. * @var unknown_type
  193. */
  194. private static $__cache;
  195. /**
  196. * Create the variable cache.
  197. *
  198. * This function creates a variable cache in a static variable in memory, optionally with a given namespace (to avoid overlap).
  199. *
  200. * @param string $namespace The namespace for this cache to write to - note, namespaces of the same name are shared!
  201. */
  202. function __construct($namespace = 'default')
  203. {
  204. $this->setNamespace($namespace);
  205. $this->clear();
  206. }
  207. public function save($key, $data)
  208. {
  209. $namespace = $this->getNamespace();
  210. ElggStaticVariableCache::$__cache[$namespace][$key] = $data;
  211. return true;
  212. }
  213. public function load($key, $offset = 0, $limit = null)
  214. {
  215. $namespace = $this->getNamespace();
  216. if (isset(ElggStaticVariableCache::$__cache[$namespace][$key]))
  217. return ElggStaticVariableCache::$__cache[$namespace][$key];
  218. return false;
  219. }
  220. public function delete($key)
  221. {
  222. $namespace = $this->getNamespace();
  223. unset(ElggStaticVariableCache::$__cache[$namespace][$key]);
  224. return true;
  225. }
  226. public function clear()
  227. {
  228. $namespace = $this->getNamespace();
  229. if (!isset(ElggStaticVariableCache::$__cache))
  230. ElggStaticVariableCache::$__cache = array();
  231. //if (!isset(ElggStaticVariableCache::$__cache[$namespace]))
  232. ElggStaticVariableCache::$__cache[$namespace] = array();
  233. }
  234. }
  235. /**
  236. * ElggFileCache
  237. * Store cached data in a file store.
  238. *
  239. * @author Curverider Ltd <info@elgg.com>
  240. * @package Elgg
  241. * @subpackage API
  242. */
  243. class ElggFileCache extends ElggCache
  244. {
  245. /**
  246. * Set the Elgg cache.
  247. *
  248. * @param string $cache_path The cache path.
  249. * @param int $max_age Maximum age in seconds, 0 if no limit.
  250. * @param int $max_size Maximum size of cache in seconds, 0 if no limit.
  251. */
  252. function __construct($cache_path, $max_age = 0, $max_size = 0)
  253. {
  254. $this->set_variable("cache_path", $cache_path);
  255. $this->set_variable("max_age", $max_age);
  256. $this->set_variable("max_size", $max_size);
  257. if ($cache_path=="") throw new ConfigurationException(elgg_echo('ConfigurationException:NoCachePath'));
  258. }
  259. /**
  260. * Create and return a handle to a file.
  261. *
  262. * @param string $filename
  263. * @param string $rw
  264. */
  265. protected function create_file($filename, $rw = "rb")
  266. {
  267. // Create a filename matrix
  268. $matrix = "";
  269. $depth = strlen($filename);
  270. if ($depth > 5) $depth = 5;
  271. // for ($n = 0; $n < $depth; $n++)
  272. // $matrix .= $filename[$n] . "/";
  273. // Create full path
  274. $path = $this->get_variable("cache_path") . $matrix;
  275. // if (!mkdir($path, 0700, true)) throw new IOException("Could not make $path");
  276. // Open the file
  277. if ((!file_exists($path . $filename)) && ($rw=="rb")) return false;
  278. return fopen($path . $filename, $rw);
  279. }
  280. /**
  281. * Create a sanitised filename for the file.
  282. *
  283. * @param string $filename
  284. */
  285. protected function sanitise_filename($filename)
  286. {
  287. // TODO : Writeme
  288. return $filename;
  289. }
  290. /**
  291. * Save a key
  292. *
  293. * @param string $key
  294. * @param string $data
  295. * @return boolean
  296. */
  297. public function save($key, $data)
  298. {
  299. $f = $this->create_file($this->sanitise_filename($key), "wb");
  300. if ($f)
  301. {
  302. $result = fwrite($f, $data);
  303. fclose($f);
  304. return $result;
  305. }
  306. return false;
  307. }
  308. /**
  309. * Load a key
  310. *
  311. * @param string $key
  312. * @param int $offset
  313. * @param int $limit
  314. * @return string
  315. */
  316. public function load($key, $offset = 0, $limit = null)
  317. {
  318. $f = $this->create_file($this->sanitise_filename($key));
  319. if ($f)
  320. {
  321. //fseek($f, $offset);
  322. if (!$limit) $limit = -1;
  323. $data = stream_get_contents($f, $limit, $offset);
  324. fclose($f);
  325. return $data;
  326. }
  327. return false;
  328. }
  329. /**
  330. * Invalidate a given key.
  331. *
  332. * @param string $key
  333. * @return bool
  334. */
  335. public function delete($key)
  336. {
  337. $dir = $this->get_variable("cache_path");
  338. return unlink($dir.$key);
  339. }
  340. public function clear()
  341. {
  342. // TODO : writeme
  343. }
  344. public function __destruct()
  345. {
  346. // TODO: Check size and age, clean up accordingly
  347. $size = 0;
  348. $dir = $this->get_variable("cache_path");
  349. // Short circuit if both size and age are unlimited
  350. if (($this->get_variable("max_age")==0) && ($this->get_variable("max_size")==0))
  351. return;
  352. $exclude = array(".","..");
  353. $files = scandir($dir);
  354. if (!$files) throw new IOException(sprintf(elgg_echo('IOException:NotDirectory'), $dir));
  355. // Perform cleanup
  356. foreach ($files as $f)
  357. {
  358. if (!in_array($f, $exclude))
  359. {
  360. $stat = stat($dir.$f);
  361. // Add size
  362. $size .= $stat['size'];
  363. // Is this older than my maximum date?
  364. if (($this->get_variable("max_age")>0) && (time() - $stat['mtime'] > $this->get_variable("max_age")))
  365. unlink($dir.$f);
  366. // TODO: Size
  367. }
  368. }
  369. }
  370. }
  371. ?>