/vendor/laravel/framework/src/Illuminate/Cache/FileStore.php

https://gitlab.com/jjpa2018/dashboard · PHP · 351 lines · 160 code · 54 blank · 137 comment · 13 complexity · 8323cecc7a2144c156f9eeaf4e116227 MD5 · raw file

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