FileCache.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. <?php
  2. namespace ForkBB\Core\Cache;
  3. use RuntimeException;
  4. use InvalidArgumentException;
  5. class FileCache implements ProviderCacheInterface
  6. {
  7. /**
  8. * Директория кэша
  9. * @var string
  10. */
  11. protected $cacheDir;
  12. /**
  13. * Конструктор
  14. *
  15. * @param string $dir
  16. *
  17. * @throws \InvalidArgumentException
  18. * @throws \RuntimeException
  19. */
  20. public function __construct($dir)
  21. {
  22. if (empty($dir) || ! is_string($dir)) {
  23. throw new InvalidArgumentException('Cache directory must be set to a string');
  24. } elseif (! is_dir($dir)) {
  25. throw new RuntimeException("`$dir`: Not a directory");
  26. } elseif (! is_writable($dir)) {
  27. throw new RuntimeException("No write access to `$dir` directory");
  28. }
  29. $this->cacheDir = $dir;
  30. }
  31. /**
  32. * Получение данных из кэша по ключу
  33. *
  34. * @param string $key
  35. * @param mixed $default
  36. *
  37. * @return mixed
  38. */
  39. public function get($key, $default = null)
  40. {
  41. $file = $this->file($key);
  42. if (file_exists($file)) {
  43. require $file;
  44. if (isset($expire) && isset($data)
  45. && ($expire < 1 || $expire > time())
  46. ) {
  47. return $data;
  48. }
  49. }
  50. return $default;
  51. }
  52. /**
  53. * Установка данных в кэш по ключу
  54. *
  55. * @param string $key
  56. * @param mixed $value
  57. * @param int $ttl
  58. *
  59. * @throws \RuntimeException
  60. * @return bool
  61. */
  62. public function set($key, $value, $ttl = null)
  63. {
  64. $file = $this->file($key);
  65. $expire = null === $ttl || $ttl < 1 ? 0 : time() + $ttl;
  66. $content = "<?php\n\n" . '$expire = ' . $expire . ";\n\n" . '$data = ' . var_export($value, true) . ";\n";
  67. if (false === file_put_contents($file, $content, LOCK_EX)) {
  68. throw new RuntimeException("The key '$key' can not be saved");
  69. } else {
  70. $this->invalidate($file);
  71. return true;
  72. }
  73. }
  74. /**
  75. * Удаление данных по ключу
  76. *
  77. * @param string $key
  78. *
  79. * @throws \RuntimeException
  80. * @return bool
  81. */
  82. public function delete($key)
  83. {
  84. $file = $this->file($key);
  85. if (file_exists($file)) {
  86. if (unlink($file)) {
  87. $this->invalidate($file);
  88. return true;
  89. } else {
  90. throw new RuntimeException("The key `$key` could not be removed");
  91. }
  92. } else {
  93. return true;
  94. }
  95. }
  96. /**
  97. * Очистка кэша
  98. *
  99. * @return bool
  100. */
  101. public function clear()
  102. {
  103. $d = dir($this->cacheDir);
  104. if (! $d) {
  105. return false;
  106. }
  107. $result = true;
  108. while (($entry = $d->read()) !== false) {
  109. if (substr($entry, -4) == '.php') {
  110. $f = unlink($this->cacheDir . '/' . $entry);
  111. $result = $result && $f;
  112. }
  113. }
  114. $d->close();
  115. return $result;
  116. }
  117. /**
  118. * Проверка наличия ключа
  119. *
  120. * @param string $key
  121. *
  122. * @return bool
  123. */
  124. public function has($key)
  125. {
  126. return null !== $this->get($key);
  127. }
  128. /**
  129. * Генерация имени файла по ключу
  130. *
  131. * @param string $key
  132. *
  133. * @throws \InvalidArgumentException
  134. * @return string
  135. */
  136. protected function file($key)
  137. {
  138. if (is_string($key) && preg_match('%^[a-z0-9_-]+$%Di', $key)) {
  139. return $this->cacheDir . '/cache_' . $key . '.php';
  140. }
  141. throw new InvalidArgumentException("Key '$key' contains invalid characters.");
  142. }
  143. /**
  144. * Очистка opcache и apc от закэшированного файла
  145. *
  146. * @param string $file
  147. */
  148. protected function invalidate($file)
  149. {
  150. if (function_exists('opcache_invalidate')) {
  151. opcache_invalidate($file, true);
  152. } elseif (function_exists('apc_delete_file')) {
  153. apc_delete_file($file);
  154. }
  155. }
  156. }