Просмотр файла vendor/illuminate/cache/FileStore.php

Размер файла: 8.17Kb
  1. <?php
  2.  
  3. namespace Illuminate\Cache;
  4.  
  5. use Exception;
  6. use Illuminate\Contracts\Cache\LockProvider;
  7. use Illuminate\Contracts\Cache\Store;
  8. use Illuminate\Contracts\Filesystem\LockTimeoutException;
  9. use Illuminate\Filesystem\Filesystem;
  10. use Illuminate\Filesystem\LockableFile;
  11. use Illuminate\Support\InteractsWithTime;
  12.  
  13. class FileStore implements Store, LockProvider
  14. {
  15. use InteractsWithTime, HasCacheLock, RetrievesMultipleKeys;
  16.  
  17. /**
  18. * The Illuminate Filesystem instance.
  19. *
  20. * @var \Illuminate\Filesystem\Filesystem
  21. */
  22. protected $files;
  23.  
  24. /**
  25. * The file cache directory.
  26. *
  27. * @var string
  28. */
  29. protected $directory;
  30.  
  31. /**
  32. * Octal representation of the cache file permissions.
  33. *
  34. * @var int|null
  35. */
  36. protected $filePermission;
  37.  
  38. /**
  39. * Create a new file cache store instance.
  40. *
  41. * @param \Illuminate\Filesystem\Filesystem $files
  42. * @param string $directory
  43. * @param int|null $filePermission
  44. * @return void
  45. */
  46. public function __construct(Filesystem $files, $directory, $filePermission = null)
  47. {
  48. $this->files = $files;
  49. $this->directory = $directory;
  50. $this->filePermission = $filePermission;
  51. }
  52.  
  53. /**
  54. * Retrieve an item from the cache by key.
  55. *
  56. * @param string|array $key
  57. * @return mixed
  58. */
  59. public function get($key)
  60. {
  61. return $this->getPayload($key)['data'] ?? null;
  62. }
  63.  
  64. /**
  65. * Store an item in the cache for a given number of seconds.
  66. *
  67. * @param string $key
  68. * @param mixed $value
  69. * @param int $seconds
  70. * @return bool
  71. */
  72. public function put($key, $value, $seconds)
  73. {
  74. $this->ensureCacheDirectoryExists($path = $this->path($key));
  75.  
  76. $result = $this->files->put(
  77. $path, $this->expiration($seconds).serialize($value), true
  78. );
  79.  
  80. if ($result !== false && $result > 0) {
  81. $this->ensureFileHasCorrectPermissions($path);
  82.  
  83. return true;
  84. }
  85.  
  86. return false;
  87. }
  88.  
  89. /**
  90. * Store an item in the cache if the key doesn't exist.
  91. *
  92. * @param string $key
  93. * @param mixed $value
  94. * @param int $seconds
  95. * @return bool
  96. */
  97. public function add($key, $value, $seconds)
  98. {
  99. $this->ensureCacheDirectoryExists($path = $this->path($key));
  100.  
  101. $file = new LockableFile($path, 'c+');
  102.  
  103. try {
  104. $file->getExclusiveLock();
  105. } catch (LockTimeoutException $e) {
  106. $file->close();
  107.  
  108. return false;
  109. }
  110.  
  111. $expire = $file->read(10);
  112.  
  113. if (empty($expire) || $this->currentTime() >= $expire) {
  114. $file->truncate()
  115. ->write($this->expiration($seconds).serialize($value))
  116. ->close();
  117.  
  118. $this->ensureFileHasCorrectPermissions($path);
  119.  
  120. return true;
  121. }
  122.  
  123. $file->close();
  124.  
  125. return false;
  126. }
  127.  
  128. /**
  129. * Create the file cache directory if necessary.
  130. *
  131. * @param string $path
  132. * @return void
  133. */
  134. protected function ensureCacheDirectoryExists($path)
  135. {
  136. if (! $this->files->exists(dirname($path))) {
  137. $this->files->makeDirectory(dirname($path), 0777, true, true);
  138. }
  139. }
  140.  
  141. /**
  142. * Ensure the cache file has the correct permissions.
  143. *
  144. * @param string $path
  145. * @return void
  146. */
  147. protected function ensureFileHasCorrectPermissions($path)
  148. {
  149. if (is_null($this->filePermission) ||
  150. intval($this->files->chmod($path), 8) == $this->filePermission) {
  151. return;
  152. }
  153.  
  154. $this->files->chmod($path, $this->filePermission);
  155. }
  156.  
  157. /**
  158. * Increment the value of an item in the cache.
  159. *
  160. * @param string $key
  161. * @param mixed $value
  162. * @return int
  163. */
  164. public function increment($key, $value = 1)
  165. {
  166. $raw = $this->getPayload($key);
  167.  
  168. return tap(((int) $raw['data']) + $value, function ($newValue) use ($key, $raw) {
  169. $this->put($key, $newValue, $raw['time'] ?? 0);
  170. });
  171. }
  172.  
  173. /**
  174. * Decrement the value of an item in the cache.
  175. *
  176. * @param string $key
  177. * @param mixed $value
  178. * @return int
  179. */
  180. public function decrement($key, $value = 1)
  181. {
  182. return $this->increment($key, $value * -1);
  183. }
  184.  
  185. /**
  186. * Store an item in the cache indefinitely.
  187. *
  188. * @param string $key
  189. * @param mixed $value
  190. * @return bool
  191. */
  192. public function forever($key, $value)
  193. {
  194. return $this->put($key, $value, 0);
  195. }
  196.  
  197. /**
  198. * Remove an item from the cache.
  199. *
  200. * @param string $key
  201. * @return bool
  202. */
  203. public function forget($key)
  204. {
  205. if ($this->files->exists($file = $this->path($key))) {
  206. return $this->files->delete($file);
  207. }
  208.  
  209. return false;
  210. }
  211.  
  212. /**
  213. * Remove all items from the cache.
  214. *
  215. * @return bool
  216. */
  217. public function flush()
  218. {
  219. if (! $this->files->isDirectory($this->directory)) {
  220. return false;
  221. }
  222.  
  223. foreach ($this->files->directories($this->directory) as $directory) {
  224. $deleted = $this->files->deleteDirectory($directory);
  225.  
  226. if (! $deleted || $this->files->exists($directory)) {
  227. return false;
  228. }
  229. }
  230.  
  231. return true;
  232. }
  233.  
  234. /**
  235. * Retrieve an item and expiry time from the cache by key.
  236. *
  237. * @param string $key
  238. * @return array
  239. */
  240. protected function getPayload($key)
  241. {
  242. $path = $this->path($key);
  243.  
  244. // If the file doesn't exist, we obviously cannot return the cache so we will
  245. // just return null. Otherwise, we'll get the contents of the file and get
  246. // the expiration UNIX timestamps from the start of the file's contents.
  247. try {
  248. $expire = substr(
  249. $contents = $this->files->get($path, true), 0, 10
  250. );
  251. } catch (Exception $e) {
  252. return $this->emptyPayload();
  253. }
  254.  
  255. // If the current time is greater than expiration timestamps we will delete
  256. // the file and return null. This helps clean up the old files and keeps
  257. // this directory much cleaner for us as old files aren't hanging out.
  258. if ($this->currentTime() >= $expire) {
  259. $this->forget($key);
  260.  
  261. return $this->emptyPayload();
  262. }
  263.  
  264. try {
  265. $data = unserialize(substr($contents, 10));
  266. } catch (Exception $e) {
  267. $this->forget($key);
  268.  
  269. return $this->emptyPayload();
  270. }
  271.  
  272. // Next, we'll extract the number of seconds that are remaining for a cache
  273. // so that we can properly retain the time for things like the increment
  274. // operation that may be performed on this cache on a later operation.
  275. $time = $expire - $this->currentTime();
  276.  
  277. return compact('data', 'time');
  278. }
  279.  
  280. /**
  281. * Get a default empty payload for the cache.
  282. *
  283. * @return array
  284. */
  285. protected function emptyPayload()
  286. {
  287. return ['data' => null, 'time' => null];
  288. }
  289.  
  290. /**
  291. * Get the full path for the given cache key.
  292. *
  293. * @param string $key
  294. * @return string
  295. */
  296. protected function path($key)
  297. {
  298. $parts = array_slice(str_split($hash = sha1($key), 2), 0, 2);
  299.  
  300. return $this->directory.'/'.implode('/', $parts).'/'.$hash;
  301. }
  302.  
  303. /**
  304. * Get the expiration time based on the given seconds.
  305. *
  306. * @param int $seconds
  307. * @return int
  308. */
  309. protected function expiration($seconds)
  310. {
  311. $time = $this->availableAt($seconds);
  312.  
  313. return $seconds === 0 || $time > 9999999999 ? 9999999999 : $time;
  314. }
  315.  
  316. /**
  317. * Get the Filesystem instance.
  318. *
  319. * @return \Illuminate\Filesystem\Filesystem
  320. */
  321. public function getFilesystem()
  322. {
  323. return $this->files;
  324. }
  325.  
  326. /**
  327. * Get the working directory of the cache.
  328. *
  329. * @return string
  330. */
  331. public function getDirectory()
  332. {
  333. return $this->directory;
  334. }
  335.  
  336. /**
  337. * Get the cache key prefix.
  338. *
  339. * @return string
  340. */
  341. public function getPrefix()
  342. {
  343. return '';
  344. }
  345. }