ApcuEngine.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11. * @link https://cakephp.org CakePHP(tm) Project
  12. * @since 3.5.4
  13. * @license https://opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Cache\Engine;
  16. use APCuIterator;
  17. use Cake\Cache\CacheEngine;
  18. /**
  19. * APCu storage engine for cache
  20. */
  21. class ApcuEngine extends CacheEngine
  22. {
  23. /**
  24. * Contains the compiled group names
  25. * (prefixed with the global configuration prefix)
  26. *
  27. * @var string[]
  28. */
  29. protected $_compiledGroupNames = [];
  30. /**
  31. * Initialize the Cache Engine
  32. *
  33. * Called automatically by the cache frontend
  34. *
  35. * @param array $config array of setting for the engine
  36. * @return bool True if the engine has been successfully initialized, false if not
  37. */
  38. public function init(array $config = [])
  39. {
  40. if (!extension_loaded('apcu')) {
  41. return false;
  42. }
  43. return parent::init($config);
  44. }
  45. /**
  46. * Write data for key into cache
  47. *
  48. * @param string $key Identifier for the data
  49. * @param mixed $value Data to be cached
  50. * @return bool True if the data was successfully cached, false on failure
  51. * @link https://secure.php.net/manual/en/function.apcu-store.php
  52. */
  53. public function write($key, $value)
  54. {
  55. $key = $this->_key($key);
  56. $duration = $this->_config['duration'];
  57. return apcu_store($key, $value, $duration);
  58. }
  59. /**
  60. * Read a key from the cache
  61. *
  62. * @param string $key Identifier for the data
  63. * @return mixed The cached data, or false if the data doesn't exist,
  64. * has expired, or if there was an error fetching it
  65. * @link https://secure.php.net/manual/en/function.apcu-fetch.php
  66. */
  67. public function read($key)
  68. {
  69. $key = $this->_key($key);
  70. return apcu_fetch($key);
  71. }
  72. /**
  73. * Increments the value of an integer cached key
  74. *
  75. * @param string $key Identifier for the data
  76. * @param int $offset How much to increment
  77. * @return bool|int New incremented value, false otherwise
  78. * @link https://secure.php.net/manual/en/function.apcu-inc.php
  79. */
  80. public function increment($key, $offset = 1)
  81. {
  82. $key = $this->_key($key);
  83. return apcu_inc($key, $offset);
  84. }
  85. /**
  86. * Decrements the value of an integer cached key
  87. *
  88. * @param string $key Identifier for the data
  89. * @param int $offset How much to subtract
  90. * @return bool|int New decremented value, false otherwise
  91. * @link https://secure.php.net/manual/en/function.apcu-dec.php
  92. */
  93. public function decrement($key, $offset = 1)
  94. {
  95. $key = $this->_key($key);
  96. return apcu_dec($key, $offset);
  97. }
  98. /**
  99. * Delete a key from the cache
  100. *
  101. * @param string $key Identifier for the data
  102. * @return bool True if the value was successfully deleted, false if it didn't exist or couldn't be removed
  103. * @link https://secure.php.net/manual/en/function.apcu-delete.php
  104. */
  105. public function delete($key)
  106. {
  107. $key = $this->_key($key);
  108. return apcu_delete($key);
  109. }
  110. /**
  111. * Delete all keys from the cache. This will clear every cache config using APC.
  112. *
  113. * @param bool $check If true, nothing will be cleared, as entries are removed
  114. * from APC as they expired. This flag is really only used by FileEngine.
  115. * @return bool True Returns true.
  116. * @link https://secure.php.net/manual/en/function.apcu-cache-info.php
  117. * @link https://secure.php.net/manual/en/function.apcu-delete.php
  118. */
  119. public function clear($check)
  120. {
  121. if ($check) {
  122. return true;
  123. }
  124. if (class_exists('APCuIterator', false)) {
  125. $iterator = new APCuIterator(
  126. '/^' . preg_quote($this->_config['prefix'], '/') . '/',
  127. APC_ITER_NONE
  128. );
  129. apcu_delete($iterator);
  130. return true;
  131. }
  132. $cache = apcu_cache_info(); // Raises warning by itself already
  133. foreach ($cache['cache_list'] as $key) {
  134. if (strpos($key['info'], $this->_config['prefix']) === 0) {
  135. apcu_delete($key['info']);
  136. }
  137. }
  138. return true;
  139. }
  140. /**
  141. * Write data for key into cache if it doesn't exist already.
  142. * If it already exists, it fails and returns false.
  143. *
  144. * @param string $key Identifier for the data.
  145. * @param mixed $value Data to be cached.
  146. * @return bool True if the data was successfully cached, false on failure.
  147. * @link https://secure.php.net/manual/en/function.apcu-add.php
  148. */
  149. public function add($key, $value)
  150. {
  151. $key = $this->_key($key);
  152. $duration = $this->_config['duration'];
  153. return apcu_add($key, $value, $duration);
  154. }
  155. /**
  156. * Returns the `group value` for each of the configured groups
  157. * If the group initial value was not found, then it initializes
  158. * the group accordingly.
  159. *
  160. * @return array
  161. * @link https://secure.php.net/manual/en/function.apcu-fetch.php
  162. * @link https://secure.php.net/manual/en/function.apcu-store.php
  163. */
  164. public function groups()
  165. {
  166. if (empty($this->_compiledGroupNames)) {
  167. foreach ($this->_config['groups'] as $group) {
  168. $this->_compiledGroupNames[] = $this->_config['prefix'] . $group;
  169. }
  170. }
  171. $success = false;
  172. $groups = apcu_fetch($this->_compiledGroupNames, $success);
  173. if ($success && count($groups) !== count($this->_config['groups'])) {
  174. foreach ($this->_compiledGroupNames as $group) {
  175. if (!isset($groups[$group])) {
  176. $value = 1;
  177. if (apcu_store($group, $value) === false) {
  178. $this->warning(
  179. sprintf('Failed to store key "%s" with value "%s" into APCu cache.', $group, $value)
  180. );
  181. }
  182. $groups[$group] = $value;
  183. }
  184. }
  185. ksort($groups);
  186. }
  187. $result = [];
  188. $groups = array_values($groups);
  189. foreach ($this->_config['groups'] as $i => $group) {
  190. $result[] = $group . $groups[$i];
  191. }
  192. return $result;
  193. }
  194. /**
  195. * Increments the group value to simulate deletion of all keys under a group
  196. * old values will remain in storage until they expire.
  197. *
  198. * @param string $group The group to clear.
  199. * @return bool success
  200. * @link https://secure.php.net/manual/en/function.apcu-inc.php
  201. */
  202. public function clearGroup($group)
  203. {
  204. $success = false;
  205. apcu_inc($this->_config['prefix'] . $group, 1, $success);
  206. return $success;
  207. }
  208. }