diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..67d9065 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016-2023 Rasmus Schultz + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 11fe438..ac5dbca 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,21 @@ To reduce storage overhead and speed up expiration time-checks, the file modific ## Usage +Use the following example as a guideline: + +```php + $absolutePathToCacheDir = realpath(__DIR__ . '/../../cache/api-cache/'); + $ttl = 86400; + $cacher = new \Kodus\Cache\FileCache( + $absolutePathToCacheDir, + $ttl + ); +``` + +There are also optional parameters: `$dir_mode = 0775, $file_mode = 0664`. + +Then pass this `$cacher` object to whatever uses a PSR-16 cacher. + Please refer to the [PSR-16 spec](https://packagist.org/packages/psr/simple-cache) for the API description. ### Security @@ -48,3 +63,8 @@ A public method `cleanExpired()` will flush expired entries - depending on your set up a cron-job to call the `cleanExpired()` method periodically, say, once per day. For cache-entries with dynamic keys in the millions, as mentioned, you probably don't want a file-based cache. + +## License + +MIT license. Please see the [license file](LICENSE) for more information. + diff --git a/src/FileCache.php b/src/FileCache.php index ef8b5cc..40c7cd6 100644 --- a/src/FileCache.php +++ b/src/FileCache.php @@ -21,27 +21,7 @@ class FileCache implements CacheInterface /** * @var string control characters for keys, reserved by PSR-16 */ - const PSR16_RESERVED = '/\{|\}|\(|\)|\/|\\\\|\@|\:/u'; - - /** - * @var string - */ - private $cache_path; - - /** - * @var int - */ - private $default_ttl; - - /** - * @var int - */ - private $dir_mode; - - /** - * @var int - */ - private $file_mode; + const PSR16_RESERVED = "/\{|\}|\(|\)|\/|\\\\|\@|\:/u"; /** * @param string $cache_path absolute root path of cache-file folder @@ -51,24 +31,29 @@ class FileCache implements CacheInterface * * @throws InvalidArgumentException */ - public function __construct($cache_path, $default_ttl, $dir_mode = 0775, $file_mode = 0664) - { - $this->default_ttl = $default_ttl; - $this->dir_mode = $dir_mode; - $this->file_mode = $file_mode; - - if (! file_exists($cache_path) && file_exists(dirname($cache_path))) { + public function __construct( + private string $cache_path, + private int $default_ttl, + private int $dir_mode = 0775, + private int $file_mode = 0664 + ) { + $cache_path = $this->cache_path; + if (!file_exists($cache_path) && file_exists(dirname($cache_path))) { $this->mkdir($cache_path); // ensure that the parent path exists } $path = realpath($cache_path); if ($path === false) { - throw new InvalidArgumentException("cache path does not exist: {$cache_path}"); + throw new InvalidArgumentException( + "cache path does not exist: {$cache_path}" + ); } - if (! is_writable($path . DIRECTORY_SEPARATOR)) { - throw new InvalidArgumentException("cache path is not writable: {$cache_path}"); + if (!is_writable($path . "/")) { + throw new InvalidArgumentException( + "cache path is not writable: {$cache_path}" + ); } $this->cache_path = $path; @@ -96,7 +81,7 @@ public function get(string $key, mixed $default = null): mixed return $default; // race condition: file not found } - if ($data === 'b:0;') { + if ($data === "b:0;") { return false; // because we can't otherwise distinguish a FALSE return-value from unserialize() } @@ -120,7 +105,7 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null $this->mkdir($dir); } - $temp_path = $this->cache_path . DIRECTORY_SEPARATOR . uniqid('', true); + $temp_path = $this->cache_path . "/" . uniqid("", true); if (is_int($ttl)) { $expires_at = $this->getTime() + $ttl; @@ -165,7 +150,7 @@ public function clear(): bool $paths = $this->listPaths(); foreach ($paths as $path) { - if (! unlink($path)) { + if (!unlink($path)) { $success = false; } } @@ -225,11 +210,11 @@ public function increment($key, $step = 1) $dir = dirname($path); - if (! file_exists($dir)) { + if (!file_exists($dir)) { $this->mkdir($dir); // ensure that the parent path exists } - $lock_path = $dir . DIRECTORY_SEPARATOR . ".lock"; // allows max. 256 client locks at one time + $lock_path = $dir . "/" . ".lock"; // allows max. 256 client locks at one time $lock_handle = fopen($lock_path, "w"); @@ -288,13 +273,13 @@ protected function getPath($key) $hash = hash("sha256", $key); - return $this->cache_path - . DIRECTORY_SEPARATOR - . strtoupper($hash[0]) - . DIRECTORY_SEPARATOR - . strtoupper($hash[1]) - . DIRECTORY_SEPARATOR - . substr($hash, 2); + return sprintf( + "%s/%s/%s/%s", + $this->cache_path, + strtoupper($hash[0]), + strtoupper($hash[1]), + substr($hash, 2) + ); } /** @@ -333,7 +318,7 @@ protected function listPaths() */ protected function validateKey($key) { - if (! is_string($key)) { + if (!is_string($key)) { $type = is_object($key) ? get_class($key) : gettype($key); throw new InvalidArgumentException("invalid key type: {$type} given");