/lib/Cache/DataCache.php

https://github.com/bshelton229/Kurogo-Mobile-Web · PHP · 253 lines · 195 code · 57 blank · 1 comment · 36 complexity · f65433ec5b655dd4653712a9b9efa514 MD5 · raw file

  1. <?php
  2. class DataCache
  3. {
  4. const CACHE_STATUS_EMPTY=1;
  5. const CACHE_STATUS_EXPIRED=2;
  6. const CACHE_STATUS_FRESH=3;
  7. protected $cacheFolder=CACHE_DIR;
  8. protected $useMemoryCache = true;
  9. protected $cacheBaseKey = 'DataCache';
  10. protected $serialize = true;
  11. protected $cacheLifetime = 0;
  12. protected $cacheGroup = null;
  13. public static function factory($cacheClass, $args)
  14. {
  15. if (!class_exists($cacheClass)) {
  16. throw new KurogoConfigurationException("Data cache class $cacheClass not defined");
  17. }
  18. $cache = new $cacheClass();
  19. if (!$cache instanceOf DataCache) {
  20. throw new KurogoConfigurationException("$cacheClass is not a subclass of DataCache");
  21. }
  22. $cache->init($args);
  23. return $cache;
  24. }
  25. protected function createCacheFolderIfNeeded() {
  26. $cacheFolder = $this->getCacheFolder();
  27. if (!is_dir($cacheFolder)) {
  28. if (!mkdir($cacheFolder, 0700, true)) {
  29. throw new KurogoDataException("Could not create cache folder $cacheFolder");
  30. }
  31. }
  32. }
  33. protected function getCacheFolder() {
  34. $return = rtrim($this->cacheFolder, DIRECTORY_SEPARATOR);
  35. if ($this->cacheGroup) {
  36. $return .= DIRECTORY_SEPARATOR . $this->cacheGroup;
  37. }
  38. return $return;
  39. }
  40. public function setSerialize($serialize) {
  41. $this->serialize = (bool) $serialize;
  42. }
  43. public function setUseMemoaryCache($useMemoryCache) {
  44. $this->useMemoryCache = (bool) $useMemoryCache;
  45. }
  46. public function setCacheLifetime($cacheLifetime) {
  47. $this->cacheLifetime = intval($cacheLifetime);
  48. }
  49. public function setCacheGroup($group) {
  50. $this->cacheGroup = $group;
  51. }
  52. protected function getValueFromMemory($key) {
  53. if ($memoryCache = $this->getMemoryCache()) {
  54. return $memoryCache->get($this->getMemoryCacheKey($key));
  55. }
  56. return false;
  57. }
  58. public function cacheStatus($key) {
  59. $age = $this->getDiskAge($key);
  60. if (is_null($age)) {
  61. return self::CACHE_STATUS_EMPTY;
  62. }
  63. if ($age < $this->cacheLifetime) {
  64. return self::CACHE_STATUS_FRESH;
  65. }
  66. return self::CACHE_STATUS_EXPIRED;
  67. }
  68. protected function getValueFromDisk($key) {
  69. $path = $this->getFullPath($key);
  70. if (file_exists($path)) {
  71. if ($contents = file_get_contents($path)) {
  72. Kurogo::log(LOG_DEBUG, "Reading cache $path", 'cache');
  73. if ($this->serialize) {
  74. return unserialize($contents);
  75. } else {
  76. return $contents;
  77. }
  78. }
  79. }
  80. return FALSE;
  81. }
  82. protected function getDiskAge($key) {
  83. $modified = $this->getModified($key);
  84. if (!is_null($modified)) {
  85. return time() - $modified;
  86. }
  87. return null;
  88. }
  89. public function getModified($key) {
  90. $path = $this->getFullPath($key);
  91. if (is_readable($path)) {
  92. return filemtime($path);
  93. } else {
  94. return null;
  95. }
  96. }
  97. public function getFullPath($key) {
  98. $return = $this->getCacheFolder() . DIRECTORY_SEPARATOR . $key;
  99. return $return;
  100. }
  101. public function getStaleValue($key) {
  102. return $this->getValueFromDisk($key);
  103. }
  104. public function get($key) {
  105. if ( ($val = $this->getValueFromMemory($key)) !== false) {
  106. Kurogo::log(LOG_DEBUG, "Reading $key from memory cache", 'cache');
  107. return $val;
  108. }
  109. $val = false;
  110. switch ($this->cacheStatus($key)) {
  111. case self::CACHE_STATUS_EMPTY:
  112. Kurogo::log(LOG_DEBUG, "Cache not available for $key", 'cache');
  113. break;
  114. case self::CACHE_STATUS_EXPIRED:
  115. Kurogo::log(LOG_DEBUG, "Cache expired for $key", 'cache');
  116. break;
  117. case self::CACHE_STATUS_FRESH:
  118. Kurogo::log(LOG_DEBUG, "Reading $key from disk cache", 'cache');
  119. $val = $this->getValueFromDisk($key);
  120. break;
  121. }
  122. return $val;
  123. }
  124. protected function getMemoryCache() {
  125. if ($this->useMemoryCache) {
  126. return Kurogo::sharedInstance()->cacher();
  127. }
  128. return false;
  129. }
  130. protected function getMemoryCacheKey($key) {
  131. $return = $this->cacheBaseKey . '-';
  132. if ($this->cacheGroup) {
  133. $return .= $this->cacheGroup . '-';
  134. }
  135. $return .= $key;
  136. return $return;
  137. }
  138. public function delete($key) {
  139. if ($memoryCache = $this->getMemoryCache()) {
  140. $memoryCache->delete($this->getMemoryCacheKey($key));
  141. }
  142. }
  143. public function set($key, $data) {
  144. /* Don't cache on 0 lifetime */
  145. if ($this->cacheLifetime == 0) {
  146. return false;
  147. }
  148. if ($memoryCache = $this->getMemoryCache()) {
  149. $memoryCache->set($this->getMemoryCacheKey($key), $data, $this->cacheLifetime);
  150. }
  151. return $this->setValueToDisk($key, $data);
  152. }
  153. protected function setValueToDisk($key, $data) {
  154. $this->createCacheFolderIfNeeded();
  155. $path = $this->getFullPath($key);
  156. $umask = umask(0077);
  157. Kurogo::log(LOG_DEBUG, "Saving cache to $path", 'cache');
  158. $fh = fopen($path, 'w');
  159. if ($fh !== FALSE) {
  160. if ($this->serialize) {
  161. fwrite($fh, serialize($data));
  162. } else {
  163. fwrite($fh, $data);
  164. }
  165. fclose($fh);
  166. umask($umask);
  167. return TRUE;
  168. }
  169. umask($umask);
  170. return false;
  171. }
  172. public function setCacheFolder($cacheFolder, $create = false) {
  173. $this->cacheFolder = $cacheFolder;
  174. if ($create) {
  175. $this->createCacheFolderIfNeeded();
  176. }
  177. if (!realpath_exists($this->cacheFolder)) {
  178. throw new KurogoDataException("Path $this->cacheFolder is not valid for cache");
  179. }
  180. if (!is_writable($cacheFolder)) {
  181. throw new KurogoDataException("Path $this->cacheFolder is not writable");
  182. }
  183. }
  184. protected function init($args) {
  185. if (isset($args['CACHE_FOLDER']) && !empty($args['CACHE_FOLDER'])) {
  186. $this->cacheBaseKey = $args['CACHE_FOLDER'];
  187. $this->setCacheFolder(CACHE_DIR . DIRECTORY_SEPARATOR . $args['CACHE_FOLDER'], true);
  188. }
  189. if (isset($args['USE_MEMORY_CACHE'])) {
  190. $this->useMemoryCache = (bool) $args['USE_MEMORY_CACHE'];
  191. }
  192. if (isset($args['CACHE_LIFETIME'])) {
  193. $this->cacheLifetime = intval($args['CACHE_LIFETIME']);
  194. }
  195. }
  196. }