/Kwf/Cache/SimpleStatic.php

https://github.com/koala-framework/koala-framework · PHP · 197 lines · 160 code · 11 blank · 26 comment · 53 complexity · 8fcd8424bc79140da3bf09b94b62cbd9 MD5 · raw file

  1. <?php
  2. /**
  3. * A simple and fast cache that can't delete individual entries. Doesn't have all the Zend_Cache bloat.
  4. *
  5. * Use for values depending on static settings that won't change except code changes.
  6. *
  7. * If available it uses apc user cache direclty (highly recommended!!), else it falls
  8. * back to Zend_Cache using a memcache backend.
  9. */
  10. class Kwf_Cache_SimpleStatic
  11. {
  12. private static $_cache = array(); //only used when apc is not used (and also on cli)
  13. private static $_fileCacheDisabled = false;
  14. private static function _processId($cacheId)
  15. {
  16. return str_replace(array('/', '+', '='), array('_', '__', ''), base64_encode($cacheId));
  17. }
  18. //for 'file' backend
  19. private static function _getFileNameForCacheId($cacheId)
  20. {
  21. $cacheId = str_replace('/', '_', base64_encode($cacheId));
  22. if (strlen($cacheId) > 50) {
  23. $cacheId = substr($cacheId, 0, 50).md5($cacheId);
  24. }
  25. return "cache/simpleStatic/".$cacheId;
  26. }
  27. public static function fetch($cacheId, &$success = true)
  28. {
  29. static $prefix;
  30. static $extensionLoaded;
  31. if (!isset($extensionLoaded)) $extensionLoaded = extension_loaded('apc');
  32. if ($extensionLoaded && PHP_SAPI != 'cli') {
  33. if (!isset($prefix)) $prefix = Kwf_Cache_Simple::$uniquePrefix.'-';
  34. return apc_fetch($prefix.$cacheId, $success);
  35. } else {
  36. if (isset(self::$_cache[$cacheId])) {
  37. $success = true;
  38. return self::$_cache[$cacheId];
  39. }
  40. if (self::$_fileCacheDisabled) {
  41. $success = false;
  42. return false;
  43. }
  44. $file = self::_getFileNameForCacheId($cacheId);
  45. if (!file_exists($file)) {
  46. $success = false;
  47. return false;
  48. }
  49. $success = true;
  50. $ret = unserialize(file_get_contents($file));
  51. self::$_cache[$cacheId] = $ret;
  52. return $ret;
  53. }
  54. }
  55. public static function fetchMultiple(array $cacheIds)
  56. {
  57. static $prefix;
  58. static $extensionLoaded;
  59. if (!isset($extensionLoaded)) $extensionLoaded = extension_loaded('apc');
  60. if ($extensionLoaded && PHP_SAPI != 'cli') {
  61. if (!isset($prefix)) $prefix = Kwf_Cache_Simple::$uniquePrefix.'-';
  62. $cacheIds = array_map(function($i) use ($prefix) { return $prefix.$i; }, $cacheIds);
  63. return apc_fetch($cacheIds);
  64. } else {
  65. $ret = array();
  66. foreach ($cacheIds as $id) {
  67. $data = self::fetch($id, $success);
  68. if ($success) {
  69. $ret[$id] = $data;
  70. }
  71. }
  72. return $ret;
  73. }
  74. }
  75. public static function exists($cacheId)
  76. {
  77. static $prefix;
  78. static $extensionLoaded;
  79. if (!isset($extensionLoaded)) $extensionLoaded = extension_loaded('apc');
  80. if ($extensionLoaded && PHP_SAPI != 'cli') {
  81. if (!isset($prefix)) $prefix = Kwf_Cache_Simple::$uniquePrefix.'-';
  82. return apc_exists($prefix.$cacheId);
  83. } else {
  84. if (self::$_fileCacheDisabled) {
  85. return false;
  86. }
  87. $file = self::_getFileNameForCacheId($cacheId);
  88. return file_exists($file);
  89. }
  90. }
  91. public static function add($cacheId, $data)
  92. {
  93. static $prefix;
  94. static $extensionLoaded;
  95. if (!isset($extensionLoaded)) $extensionLoaded = extension_loaded('apc');
  96. if ($extensionLoaded && PHP_SAPI != 'cli') {
  97. if (!isset($prefix)) $prefix = Kwf_Cache_Simple::$uniquePrefix.'-';
  98. return apc_add($prefix.$cacheId, $data);
  99. } else {
  100. self::$_cache[$cacheId] = $data;
  101. if (self::$_fileCacheDisabled) {
  102. return true;
  103. }
  104. $file = self::_getFileNameForCacheId($cacheId);
  105. return file_put_contents($file, serialize($data));
  106. }
  107. }
  108. /**
  109. * clear static cache with prefix, don't use except in clear-cache-watcher
  110. *
  111. * @internal
  112. */
  113. public static function clear($cacheIdPrefix)
  114. {
  115. if (!extension_loaded('apc') || PHP_SAPI == 'cli') {
  116. self::$_cache = array();
  117. //don't use $cacheIdPrefix as filenames are base64 encoded
  118. foreach (glob('cache/simpleStatic/*') as $f) {
  119. unlink($f);
  120. }
  121. if (extension_loaded('apc')) {
  122. Kwf_Util_Apc::callClearCacheByCli(array('clearCacheSimpleStatic'=>$cacheIdPrefix));
  123. }
  124. } else {
  125. if (!class_exists('APCIterator')) {
  126. throw new Kwf_Exception_NotYetImplemented("We don't want to clear the whole");
  127. } else {
  128. static $prefix;
  129. if (!isset($prefix)) $prefix = Kwf_Cache_Simple::$uniquePrefix.'-';
  130. $it = new APCIterator('user', '#^'.preg_quote($prefix.$cacheIdPrefix).'#', APC_ITER_NONE);
  131. if ($it->getTotalCount() && !$it->current()) {
  132. //APCIterator is borked, delete everything
  133. //see https://bugs.php.net/bug.php?id=59938
  134. if (extension_loaded('apcu')) {
  135. apc_clear_cache();
  136. } else {
  137. apc_clear_cache('user');
  138. }
  139. } else {
  140. //APCIterator seems to work, use it for deletion
  141. apc_delete($it);
  142. }
  143. }
  144. }
  145. }
  146. /**
  147. * Delete static cache, don't use except in unittests
  148. *
  149. * @internal
  150. */
  151. public static function _delete($cacheIds)
  152. {
  153. if (!is_array($cacheIds)) $cacheIds = array($cacheIds);
  154. $ret = true;
  155. if (!extension_loaded('apc') || PHP_SAPI == 'cli') {
  156. foreach ($cacheIds as $cacheId) {
  157. unset(self::$_cache[$cacheId]);
  158. $file = self::_getFileNameForCacheId($cacheId);
  159. if (!file_exists($file)) {
  160. $ret = false;
  161. } else {
  162. if (!unlink($file)) $ret = false;
  163. }
  164. }
  165. if (extension_loaded('apc')) {
  166. $result = Kwf_Util_Apc::callClearCacheByCli(array('clearCacheSimpleStatic' => implode(',', $cacheIds)));
  167. if (!$result['result']) $ret = false;
  168. }
  169. } else {
  170. $prefix = Kwf_Cache_Simple::$uniquePrefix.'-';
  171. foreach ($cacheIds as $cacheId) {
  172. if (!apc_delete($prefix.$cacheId)) {
  173. $ret = false;
  174. }
  175. }
  176. }
  177. return $ret;
  178. }
  179. /**
  180. * Disables the cache/simple file based cache
  181. */
  182. public static function disableFileCache()
  183. {
  184. self::$_fileCacheDisabled = true;
  185. }
  186. }