FileCache.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: Jenner
  5. * Date: 2016/6/22
  6. * Time: 16:18
  7. */
  8. namespace Jenner\SimpleFork\Cache;
  9. class FileCache implements CacheInterface
  10. {
  11. /**
  12. * 缓存目录
  13. * @var
  14. */
  15. private $cache_dir;
  16. /**
  17. * @param string $cache_dir
  18. * @throws \Exception
  19. */
  20. public function __construct($cache_dir)
  21. {
  22. $this->cache_dir = $cache_dir;
  23. if (!is_dir($cache_dir)) {
  24. $make_dir_result = mkdir($cache_dir, 0755, true);
  25. if ($make_dir_result === false) throw new \Exception('Cannot create the cache directory');
  26. }
  27. }
  28. /**
  29. * get value by key, and check if it is expired
  30. * @param string $key
  31. * @param string $default
  32. * @return mixed
  33. */
  34. public function get($key, $default = null)
  35. {
  36. $cache_data = $this->getItem($key);
  37. if ($cache_data === false || !is_array($cache_data)) return $default;
  38. return $cache_data['data'];
  39. }
  40. /**
  41. * 添加或覆盖一个key
  42. * @param string $key
  43. * @param mixed $value
  44. * @param int $expire expire time in seconds
  45. * @return mixed
  46. */
  47. public function set($key, $value, $expire = 0)
  48. {
  49. return $this->setItem($key, $value, time(), $expire);
  50. }
  51. /**
  52. * 设置包含元数据的信息
  53. * @param $key
  54. * @param $value
  55. * @param $time
  56. * @param $expire
  57. * @return bool
  58. */
  59. private function setItem($key, $value, $time, $expire)
  60. {
  61. $cache_file = $this->createCacheFile($key);
  62. if ($cache_file === false) return false;
  63. $cache_data = array('data' => $value, 'time' => $time, 'expire' => $expire);
  64. $cache_data = serialize($cache_data);
  65. $put_result = file_put_contents($cache_file, $cache_data);
  66. if ($put_result === false) return false;
  67. return true;
  68. }
  69. /**
  70. * 创建缓存文件
  71. * @param $key
  72. * @return bool|string
  73. */
  74. private function createCacheFile($key)
  75. {
  76. $cache_file = $this->path($key);
  77. if (!file_exists($cache_file)) {
  78. $directory = dirname($cache_file);
  79. if (!is_dir($directory)) {
  80. $make_dir_result = mkdir($directory, 0755, true);
  81. if ($make_dir_result === false) return false;
  82. }
  83. $create_result = touch($cache_file);
  84. if ($create_result === false) return false;
  85. }
  86. return $cache_file;
  87. }
  88. /**
  89. * 判断Key是否存在
  90. * @param $key
  91. * @return mixed
  92. */
  93. public function has($key)
  94. {
  95. $value = $this->get($key);
  96. if ($value === false) return false;
  97. return true;
  98. }
  99. /**
  100. * 加法递增
  101. * @param $key
  102. * @param int $value
  103. * @return mixed
  104. */
  105. public function increment($key, $value = 1)
  106. {
  107. $item = $this->getItem($key);
  108. if ($item === false) {
  109. $set_result = $this->set($key, $value);
  110. if ($set_result === false) return false;
  111. return $value;
  112. }
  113. $check_expire = $this->checkExpire($item);
  114. if ($check_expire === false) return false;
  115. $item['data'] += $value;
  116. $result = $this->setItem($key, $item['data'], $item['time'], $item['expire']);
  117. if ($result === false) return false;
  118. return $item['data'];
  119. }
  120. /**
  121. * 减法递增
  122. * @param $key
  123. * @param int $value
  124. * @return mixed
  125. */
  126. public function decrement($key, $value = 1)
  127. {
  128. $item = $this->getItem($key);
  129. if ($item === false) {
  130. $value = 0 - $value;
  131. $set_result = $this->set($key, $value);
  132. if ($set_result === false) return false;
  133. return $value;
  134. }
  135. $check_expire = $this->checkExpire($item);
  136. if ($check_expire === false) return false;
  137. $item['data'] -= $value;
  138. $result = $this->setItem($key, $item['data'], $item['time'], $item['expire']);
  139. if ($result === false) return false;
  140. return $item['data'];
  141. }
  142. /**
  143. * 删除一个key,同事会删除缓存文件
  144. * @param $key
  145. * @return boolean
  146. */
  147. public function delete($key)
  148. {
  149. $cache_file = $this->path($key);
  150. if (file_exists($cache_file)) {
  151. $unlink_result = unlink($cache_file);
  152. if ($unlink_result === false) return false;
  153. }
  154. return true;
  155. }
  156. /**
  157. * 清楚所有缓存
  158. * @return mixed
  159. */
  160. public function flush()
  161. {
  162. return $this->delTree($this->cache_dir);
  163. }
  164. /**
  165. * 递归删除目录
  166. * @param $dir
  167. * @return bool
  168. */
  169. function delTree($dir)
  170. {
  171. $files = array_diff(scandir($dir), array('.', '..'));
  172. foreach ($files as $file) {
  173. (is_dir("$dir/$file")) ? $this->delTree("$dir/$file") : unlink("$dir/$file");
  174. }
  175. return rmdir($dir);
  176. }
  177. /**
  178. * 根据key获取缓存文件路径
  179. *
  180. * @param string $key
  181. * @return string
  182. */
  183. protected function path($key)
  184. {
  185. $parts = array_slice(str_split($hash = md5($key), 2), 0, 2);
  186. return $this->cache_dir . '/' . implode('/', $parts) . '/' . $hash;
  187. }
  188. /**
  189. * 获取含有元数据的信息
  190. * @param $key
  191. * @return bool|mixed|string
  192. */
  193. protected function getItem($key)
  194. {
  195. $cache_file = $this->path($key);
  196. if (!file_exists($cache_file) || !is_readable($cache_file)) {
  197. return false;
  198. }
  199. $data = file_get_contents($cache_file);
  200. if (empty($data)) return false;
  201. $cache_data = unserialize($data);
  202. if ($cache_data === false) {
  203. return false;
  204. }
  205. $check_expire = $this->checkExpire($cache_data);
  206. if ($check_expire === false) {
  207. $this->delete($key);
  208. return false;
  209. }
  210. return $cache_data;
  211. }
  212. /**
  213. * 检查key是否过期
  214. * @param $cache_data
  215. * @return bool
  216. */
  217. protected function checkExpire($cache_data)
  218. {
  219. $time = time();
  220. $is_expire = intval($cache_data['expire']) !== 0 && (intval($cache_data['time']) + intval($cache_data['expire']) < $time);
  221. if ($is_expire) return false;
  222. return true;
  223. }
  224. }