├── .editorconfig ├── .gitignore ├── LICENSE.md ├── README.md ├── composer.json ├── examples ├── simple_cache.php ├── simple_cache_meta.php └── simple_cache_traditional.php ├── src └── PhpFileCache.php └── tests └── PhpFileCacheTest.php /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | indent_style = space 12 | indent_size = 4 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Windows template 3 | # Windows thumbnail cache files 4 | Thumbs.db 5 | ehthumbs.db 6 | ehthumbs_vista.db 7 | 8 | # Dump file 9 | *.stackdump 10 | 11 | # Folder config file 12 | [Dd]esktop.ini 13 | 14 | # Recycle Bin used on file shares 15 | $RECYCLE.BIN/ 16 | 17 | # Windows Installer files 18 | *.cab 19 | *.msi 20 | *.msm 21 | *.msp 22 | 23 | # Windows shortcuts 24 | *.lnk 25 | ### macOS template 26 | # General 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Icon must end with two \r 32 | Icon 33 | 34 | # Thumbnails 35 | ._* 36 | 37 | # Files that might appear in the root of a volume 38 | .DocumentRevisions-V100 39 | .fseventsd 40 | .Spotlight-V100 41 | .TemporaryItems 42 | .Trashes 43 | .VolumeIcon.icns 44 | .com.apple.timemachine.donotpresent 45 | 46 | # Directories potentially created on remote AFP share 47 | .AppleDB 48 | .AppleDesktop 49 | Network Trash Folder 50 | Temporary Items 51 | .apdisk 52 | ### Composer template 53 | composer.phar 54 | /vendor/ 55 | 56 | # Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control 57 | # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file 58 | # composer.lock 59 | ### JetBrains template 60 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 61 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 62 | 63 | # User-specific stuff: 64 | .idea/**/workspace.xml 65 | .idea/**/tasks.xml 66 | .idea/dictionaries 67 | 68 | # Sensitive or high-churn files: 69 | .idea/**/dataSources/ 70 | .idea/**/dataSources.ids 71 | .idea/**/dataSources.xml 72 | .idea/**/dataSources.local.xml 73 | .idea/**/sqlDataSources.xml 74 | .idea/**/dynamic.xml 75 | .idea/**/uiDesigner.xml 76 | 77 | # Gradle: 78 | .idea/**/gradle.xml 79 | .idea/**/libraries 80 | 81 | # CMake 82 | cmake-build-debug/ 83 | 84 | # Mongo Explorer plugin: 85 | .idea/**/mongoSettings.xml 86 | 87 | ## File-based project format: 88 | *.iws 89 | 90 | ## Plugin-specific files: 91 | 92 | # IntelliJ 93 | out/ 94 | 95 | # mpeltonen/sbt-idea plugin 96 | .idea_modules/ 97 | 98 | # JIRA plugin 99 | atlassian-ide-plugin.xml 100 | 101 | # Cursive Clojure plugin 102 | .idea/replstate.xml 103 | 104 | # Crashlytics plugin (for Android Studio and IntelliJ) 105 | com_crashlytics_export_strings.xml 106 | crashlytics.properties 107 | crashlytics-build.properties 108 | fabric.properties 109 | ### Linux template 110 | *~ 111 | 112 | # temporary files which can be created if a process still has a handle open of a deleted file 113 | .fuse_hidden* 114 | 115 | # KDE directory preferences 116 | .directory 117 | 118 | # Linux trash folder which might appear on any partition or disk 119 | .Trash-* 120 | 121 | # .nfs files are created when an open file is removed but is still being accessed 122 | .nfs* 123 | 124 | .idea/ 125 | composer.lock 126 | cache/ 127 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Wruczek 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deprecation notice 2 | This project is not in active development. Issues remain with cache files sometimes being saved with invalid data and unable to be read (see: [issue #3](https://github.com/Wruczek/PHP-File-Cache/issues/3) and [#4](https://github.com/Wruczek/PHP-File-Cache/issues/4)). The API is confusing and a rewrite would be necessary (for example renaming "retrive" function to "get", "store" to "set" etc.). 3 | 4 | A community fork has been created, with authors planning on continuing the devlopment. 5 | ### Check out a maintaned community fork: https://github.com/flightphp/PHP-File-Cache 6 | 7 | # PHP-File-Cache [![Latest Stable Version](https://poser.pugx.org/wruczek/php-file-cache/version)](https://packagist.org/packages/wruczek/php-file-cache) [![Latest Unstable Version](https://poser.pugx.org/wruczek/php-file-cache/v/unstable)](//packagist.org/packages/wruczek/php-file-cache) [![License](https://poser.pugx.org/wruczek/php-file-cache/license)](https://packagist.org/packages/wruczek/php-file-cache) 8 | Light, simple and standalone PHP in-file caching class 9 | 10 | ### Advantages 11 | - Light, standalone and simple 12 | - All code in one file - no pointless drivers. 13 | - Secure - every generated cache file have a php header with `die`, making direct access impossible even if someone knows the path and your server is not configured properly 14 | - Well documented and tested 15 | - Handles concurrency correctly via flock 16 | - Supports PHP 5.4.0 - 7.1+ 17 | - Free under a MIT license 18 | 19 | ### Requirements and Installation 20 | You need PHP 5.4.0+ for usage and PHP 5.6+ for development (PHPUnit) 21 | 22 | Require with composer:
23 | `composer require wruczek/php-file-cache` 24 | 25 | ### Usage 26 | ```php 27 | refreshIfExpired("simple-cache-test", function () { 34 | return date("H:i:s"); // return data to be cached 35 | }, 10); 36 | 37 | echo "Latest cache save: $data"; 38 | ``` 39 | See [examples](https://github.com/Wruczek/PHP-File-Cache/tree/master/examples) for more 40 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wruczek/php-file-cache", 3 | "description": "Light, simple and standalone PHP in-file caching class", 4 | "minimum-stability": "stable", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Wruczek", 9 | "email": "wruczekk@gmail.com", 10 | "homepage": "https://wruczek.tech" 11 | } 12 | ], 13 | "require": { 14 | "php": ">=5.4.0" 15 | }, 16 | "require-dev": { 17 | "php": ">=5.6.0", 18 | "phpunit/phpunit": "5.6.*" 19 | }, 20 | "autoload": { 21 | "psr-4": {"Wruczek\\PhpFileCache\\": "src/"} 22 | }, 23 | "autoload-dev": { 24 | "psr-4": {"Wruczek\\PhpFileCache\\": "tests/"} 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/simple_cache.php: -------------------------------------------------------------------------------- 1 | refreshIfExpired("simple-cache-test", function () { 12 | echo "Refreshing data!" . PHP_EOL; 13 | return date("H:i:s"); // return data to be cached 14 | }, 10); 15 | 16 | echo "Latest cache save: $data"; 17 | -------------------------------------------------------------------------------- /examples/simple_cache_meta.php: -------------------------------------------------------------------------------- 1 | refreshIfExpired("simple-cache-meta-test", function () { 10 | echo "Refreshing data!" . PHP_EOL; 11 | return date("H:i:s"); // return data to be cached 12 | }, 10, true); // true = return with metadata 13 | 14 | /* 15 | Example cached item retrieved with metadata: 16 | { 17 | "time":1511667506, <-- save unix timestamp 18 | "expire":10, <-- expire time in seconds 19 | "data":"04:38:26", <-- unserialized data 20 | "permanent":false 21 | } 22 | 23 | Using metadata, we can, for example, calculate when item was saved or when it expires 24 | We can also access the data itself with the "data" key 25 | */ 26 | 27 | $expiresin = ($data["time"] + $data["expire"]) - time(); // get unix timestamp when data expires and subtract current timestamp from it 28 | $cacheddate = $data["data"]; // we access the data itself with the "data" key 29 | 30 | echo "Latest cache save: $cacheddate, expires in $expiresin seconds"; 31 | -------------------------------------------------------------------------------- /examples/simple_cache_traditional.php: -------------------------------------------------------------------------------- 1 | isExpired("simple-cache-test")) { 11 | $store = date("H:i:s"); // data to cache. can be any type you like 12 | $cache->store("simple-cache-test", $store, 10); 13 | } 14 | 15 | $data = $cache->retrieve("simple-cache-test"); 16 | 17 | echo "Latest cache save: $data"; 18 | -------------------------------------------------------------------------------- /src/PhpFileCache.php: -------------------------------------------------------------------------------- 1 | setCacheFilename($cacheFileName); 58 | $this->setCacheDir($cacheDirPath); 59 | $this->setCacheFileExtension($cacheFileExtension); 60 | $this->setDevMode(false); 61 | 62 | $this->reloadFromDisc(); 63 | } 64 | 65 | /** 66 | * Loads cache 67 | * @return array array filled with data 68 | * @throws \Exception if there is a problem loading the cache 69 | */ 70 | private function loadCacheFile() { 71 | $filepath = $this->getCacheFilePath(); 72 | 73 | if(($fp = fopen($filepath, "r+")) === false) 74 | throw new \Exception("Could not fopen $filepath"); 75 | 76 | if (flock($fp, LOCK_SH)) { 77 | $file = fread($fp, filesize($filepath)); 78 | flock($fp, LOCK_UN); 79 | } else { 80 | throw new \Exception("Could not get the lock for $filepath"); 81 | } 82 | fclose($fp); 83 | 84 | 85 | if (!$file) { 86 | unlink($filepath); 87 | throw new \Exception("Cannot read cache file! ({$this->getCacheFilename()})"); 88 | } 89 | 90 | // Remove the first line which prevents direct access to the file 91 | $file = $this->stripFirstLine($file); 92 | $data = unserialize($file); 93 | 94 | if ($data === false) { 95 | unlink($filepath); 96 | throw new \Exception("Cannot unserialize cache file, cache file deleted. ({$this->getCacheFilename()})"); 97 | } 98 | 99 | if (!isset($data["hash-sum"])) { 100 | unlink($filepath); 101 | throw new \Exception("No hash found in cache file, cache file deleted"); 102 | } 103 | 104 | $hash = $data["hash-sum"]; 105 | unset($data["hash-sum"]); 106 | 107 | if ($hash !== $this->getStringHash(serialize($data))) { 108 | unlink($filepath); 109 | throw new \Exception("Cache data miss-hashed, cache file deleted"); 110 | } 111 | 112 | return $data; 113 | } 114 | 115 | /** 116 | * Saves current cacheArray into the cache file 117 | * @return $this 118 | * @throws \Exception if the file cannot be saved 119 | */ 120 | private function saveCacheFile() { 121 | if (!file_exists($this->getCacheDir())) 122 | @mkdir($this->getCacheDir()); 123 | 124 | $cache = $this->cacheArray; 125 | $cache["hash-sum"] = $this->getStringHash(serialize($cache)); 126 | $data = serialize($cache); 127 | $firstLine = '' . PHP_EOL; 128 | if(file_put_contents($this->getCacheFilePath(), $firstLine . $data, LOCK_EX) === false) 129 | throw new \Exception("Cannot save cache"); 130 | 131 | return $this; 132 | } 133 | 134 | /** 135 | * Stores $data under $key for $expiration seconds 136 | * If $key is already used, then current data will be overwritten 137 | * @param $key string key associated with the current data 138 | * @param $data mixed data to store 139 | * @param $expiration int number of seconds before the $key expires 140 | * @param $permanent bool if true, this item will not be automatically cleared after expiring 141 | * @return $this 142 | * @throws \Exception if the file cannot be saved 143 | */ 144 | public function store($key, $data, $expiration = 60, $permanent = false) { 145 | if(!is_string($key)) { 146 | throw new \InvalidArgumentException('$key must be a string, got type "' . get_class($key) . '" instead'); 147 | } 148 | 149 | if ($this->isDevMode()) 150 | $expiration = 1; 151 | 152 | $storeData = [ 153 | "time" => time(), 154 | "expire" => $expiration, 155 | "data" => $data, 156 | "permanent" => $permanent 157 | ]; 158 | 159 | $this->cacheArray[$key] = $storeData; 160 | $this->saveCacheFile(); 161 | return $this; 162 | } 163 | 164 | /** 165 | * Returns data associated with $key 166 | * @param $key string 167 | * @param bool $meta if true, array will be returned containing metadata alongside data itself 168 | * @return mixed|null returns data if $key is valid and not expired, NULL otherwise 169 | * @throws \Exception if the file cannot be saved 170 | */ 171 | public function retrieve($key, $meta = false) { 172 | $this->eraseExpired(); 173 | 174 | if (!isset($this->cacheArray[$key])) 175 | return null; 176 | 177 | $data = $this->cacheArray[$key]; 178 | return $meta ? $data : @$data["data"]; 179 | } 180 | 181 | /** 182 | * Calls $refreshCallback if $key does not exists or is expired. 183 | * Also returns latest data associated with $key. 184 | * This is basically a shortcut, turns this: 185 | * 186 | * if($cache->isExpired(key)) { 187 | * $cache->store(key, $newdata, 10); 188 | * } 189 | * 190 | * $data = $cache->retrieve(key); 191 | * 192 | * 193 | * to this: 194 | * 195 | * 196 | * $data = $cache->refreshIfExpired(key, function () { 197 | * return $newdata; 198 | * }, 10); 199 | * 200 | * 201 | * @param $key 202 | * @param $refreshCallback Callback called when data needs to be refreshed. Should return data to be cached. 203 | * @param int $cacheTime Cache time. Defaults to 60 204 | * @param bool $meta If true, returns data with meta. @see retrieve 205 | * @return mixed|null Data currently stored under key 206 | * @throws \Exception if the file cannot be saved 207 | */ 208 | public function refreshIfExpired($key, $refreshCallback, $cacheTime = 60, $meta = false) { 209 | if ($this->isExpired($key)) { 210 | $this->store($key, $refreshCallback(), $cacheTime); 211 | } 212 | 213 | return $this->retrieve($key, $meta); 214 | } 215 | 216 | /** 217 | * Erases data associated with $key 218 | * @param $key string 219 | * @return bool true if $key was found and removed, false otherwise 220 | * @throws \Exception if the file cannot be saved 221 | */ 222 | public function eraseKey($key) { 223 | if (!$this->isCached($key, false)) { 224 | return false; 225 | } 226 | 227 | unset($this->cacheArray[$key]); 228 | $this->saveCacheFile(); 229 | return true; 230 | } 231 | 232 | /** 233 | * Erases expired keys from cache 234 | * @return int number of erased entries 235 | * @throws \Exception if the file cannot be saved 236 | */ 237 | public function eraseExpired() { 238 | $counter = 0; 239 | 240 | foreach ($this->cacheArray as $key => $value) { 241 | if (!$value["permanent"] && $this->isExpired($key, false)) { 242 | $this->eraseKey($key); 243 | $counter++; 244 | } 245 | } 246 | 247 | if ($counter > 0) 248 | $this->saveCacheFile(); 249 | 250 | return $counter; 251 | } 252 | 253 | /** 254 | * Clears the cache 255 | * @throws \Exception if the file cannot be saved 256 | */ 257 | public function clearCache() { 258 | $this->cacheArray = []; 259 | $this->saveCacheFile(); 260 | } 261 | 262 | /** 263 | * Checks if $key has expired 264 | * @param $key 265 | * @param bool $eraseExpired if true, expired data will 266 | * be cleared before running this function 267 | * @return bool 268 | * @throws \Exception if the file cannot be saved 269 | */ 270 | public function isExpired($key, $eraseExpired = true) { 271 | if ($eraseExpired) 272 | $this->eraseExpired(); 273 | 274 | if (!$this->isCached($key, false)) 275 | return true; 276 | 277 | $item = $this->cacheArray[$key]; 278 | 279 | return $this->isTimestampExpired($item["time"], $item["expire"]); 280 | } 281 | 282 | /** 283 | * Checks if $key is cached 284 | * @param $key 285 | * @param bool $eraseExpired if true, expired data will 286 | * be cleared before running this function 287 | * @return bool 288 | * @throws \Exception if the file cannot be saved 289 | */ 290 | public function isCached($key, $eraseExpired = true) { 291 | if ($eraseExpired) 292 | $this->eraseExpired(); 293 | 294 | return isset($this->cacheArray[$key]); 295 | } 296 | 297 | /** 298 | * Checks if the timestamp expired 299 | * @param $timestamp int 300 | * @param $expiration int number of seconds after the timestamp expires 301 | * @return bool true if the timestamp expired, false otherwise 302 | */ 303 | private function isTimestampExpired($timestamp, $expiration) { 304 | $timeDiff = time() - $timestamp; 305 | return $timeDiff >= $expiration; 306 | } 307 | 308 | /** 309 | * Prints cache file using var_dump, useful for debugging 310 | */ 311 | public function debugCache() { 312 | if (file_exists($this->getCacheFilePath())) 313 | var_dump(unserialize($this->stripFirstLine(file_get_contents($this->getCacheFilePath())))); 314 | } 315 | 316 | /** 317 | * Reloads cache from disc. Can be used after changing file name, extension or cache dir 318 | * using functions instead of constructor. (This class loads data once, when is created) 319 | * @throws \Exception if there is a problem loading the cache 320 | */ 321 | public function reloadFromDisc() { 322 | // Try to load the cache, otherwise create a empty array 323 | $this->cacheArray = is_readable($this->getCacheFilePath()) ? $this->loadCacheFile() : []; 324 | } 325 | 326 | /** 327 | * Returns md5 hash of the given string. 328 | * @param $str string String to be hashed 329 | * @return string MD5 hash 330 | * @throws \InvalidArgumentException if $str is not a string 331 | */ 332 | private function getStringHash($str) { 333 | if(!is_string($str)) { 334 | throw new \InvalidArgumentException('$key must be a string, got type "' . get_class($str) . '" instead'); 335 | } 336 | 337 | return md5($str); 338 | } 339 | 340 | // Utils 341 | 342 | /** 343 | * Strips the first line from string 344 | * https://stackoverflow.com/a/7740485 345 | * @param $str 346 | * @return bool|string stripped text without the first line or false on failure 347 | */ 348 | private function stripFirstLine($str) { 349 | $position = strpos($str, "\n"); 350 | 351 | if ($position === false) 352 | return $str; 353 | 354 | return substr($str, $position + 1); 355 | } 356 | 357 | // Generic setters and getters below 358 | 359 | /** 360 | * Returns cache directory 361 | * @return string 362 | */ 363 | public function getCacheDir() { 364 | return $this->cacheDir; 365 | } 366 | 367 | /** 368 | * Sets new cache directory. If you want to read data from new file, consider calling reloadFromDisc. 369 | * @param string $cacheDir new cache directory. Must end with "/" 370 | * @return $this 371 | */ 372 | public function setCacheDir($cacheDir) { 373 | // Add "/" to the end if its not here 374 | if (substr($cacheDir, -1) !== "/") 375 | $cacheDir .= "/"; 376 | 377 | $this->cacheDir = $cacheDir; 378 | return $this; 379 | } 380 | 381 | /** 382 | * Returns cache file name, hashed with sha1. Used as an actual file name 383 | * The new value is computed when using setCacheFilename method. 384 | * @return string 385 | */ 386 | public function getCacheFilenameHashed() { 387 | return $this->cacheFilenameHashed; 388 | } 389 | 390 | /** 391 | * Returns cache file name 392 | * @return string 393 | */ 394 | public function getCacheFilename() { 395 | return $this->cacheFilename; 396 | } 397 | 398 | /** 399 | * Sets new cache file name. If you want to read data from new file, consider calling reloadFromDisc. 400 | * @param string $cacheFilename 401 | * @return $this 402 | * @throws \InvalidArgumentException if $cacheFilename is not a string 403 | */ 404 | public function setCacheFilename($cacheFilename) { 405 | if(!is_string($cacheFilename)) { 406 | throw new \InvalidArgumentException('$key must be a string, got type "' . get_class($cacheFilename) . '" instead'); 407 | } 408 | 409 | $this->cacheFilename = $cacheFilename; 410 | $this->cacheFilenameHashed = $this->getStringHash($cacheFilename); 411 | return $this; 412 | } 413 | 414 | /** 415 | * Returns cache file extension 416 | * @return string 417 | */ 418 | public function getCacheFileExtension() { 419 | return $this->cacheFileExtension; 420 | } 421 | 422 | /** 423 | * Sets new cache file extension. If you want to read data from new file, consider calling reloadFromDisc. 424 | * @param string $cacheFileExtension new cache file extension. Must end with ".php" 425 | * @return $this 426 | */ 427 | public function setCacheFileExtension($cacheFileExtension) { 428 | // Add ".php" to the end if its not here 429 | if (substr($cacheFileExtension, -4) !== ".php") 430 | $cacheFileExtension .= ".php"; 431 | 432 | $this->cacheFileExtension = $cacheFileExtension; 433 | return $this; 434 | } 435 | 436 | /** 437 | * Combines directory, filename and extension into a path 438 | * @return string 439 | */ 440 | public function getCacheFilePath() { 441 | return $this->getCacheDir() . $this->getCacheFilenameHashed() . $this->getCacheFileExtension(); 442 | } 443 | 444 | /** 445 | * Returns raw cache array 446 | * @return array 447 | */ 448 | public function getCacheArray() { 449 | return $this->cacheArray; 450 | } 451 | 452 | /** 453 | * Returns true if dev mode is on 454 | * If dev mode is on, cache expire after one second 455 | * @return bool 456 | */ 457 | public function isDevMode() { 458 | return $this->devMode; 459 | } 460 | 461 | /** 462 | * Sets dev mode on or off 463 | * If dev mode is on, cache expire after one second 464 | * @param $devMode 465 | * @return $this 466 | */ 467 | public function setDevMode($devMode) { 468 | $this->devMode = $devMode; 469 | return $this; 470 | } 471 | } 472 | -------------------------------------------------------------------------------- /tests/PhpFileCacheTest.php: -------------------------------------------------------------------------------- 1 | foo = "value"; 18 | 19 | $this->testarray = [ 20 | "string" => "asd123", 21 | "int" => 123, 22 | "array" => [[["test"]]], 23 | "object" => $obj, 24 | "bool" => false, 25 | "binary" => $data 26 | ]; 27 | } 28 | 29 | public function testConstructor() { 30 | $cache = new PhpFileCache("testdir/", "fileName", ".test.php"); 31 | 32 | self::assertSame("fileName", $cache->getCacheFilename()); 33 | self::assertSame("testdir/", $cache->getCacheDir()); 34 | self::assertSame(".test.php", $cache->getCacheFileExtension()); 35 | } 36 | 37 | public function testPathRequirements() { 38 | $cache = new PhpFileCache(self::__TESTDIR); 39 | 40 | $cache->setCacheDir("directory"); 41 | $this->assertSame("directory/", $cache->getCacheDir()); // "/" should be added automatically 42 | 43 | $cache->setCacheFileExtension(".test"); 44 | $this->assertSame(".test.php", $cache->getCacheFileExtension()); // ".php" should be added automatically 45 | } 46 | 47 | public function testStore() { 48 | $cache = new PhpFileCache(self::__TESTDIR); 49 | 50 | $cache->store("test", $this->testarray); 51 | 52 | self::assertSame($this->testarray, $cache->retrieve("test")); 53 | self::assertFalse($cache->isExpired("test")); 54 | } 55 | 56 | public function testKeyCharacters() { 57 | $cache = new PhpFileCache(self::__TESTDIR); 58 | 59 | foreach (["'", "\"", "test & test", "óÓłć€$123"] as $key) { 60 | self::assertSame($this->testarray, $cache->store($key, $this->testarray)->retrieve($key)); 61 | } 62 | } 63 | 64 | public function testRetrieve() { 65 | $cache = new PhpFileCache(self::__TESTDIR); 66 | 67 | self::assertEquals($this->testarray, $cache->retrieve("test")); 68 | self::assertFalse($cache->isExpired("test")); 69 | } 70 | 71 | public function testRefreshIfExpired() { 72 | $cache = new PhpFileCache(self::__TESTDIR); 73 | 74 | $data = $cache->refreshIfExpired("refreshtest", function () { 75 | return $this->testarray; 76 | }, 1); 77 | 78 | self::assertEquals($this->testarray, $data); 79 | self::assertEquals($this->testarray, $cache->retrieve("refreshtest")); 80 | sleep(2); 81 | self::assertNull($cache->retrieve("refreshtest")); 82 | } 83 | 84 | 85 | public function testEraseExpired() { 86 | $cache = new PhpFileCache(self::__TESTDIR); 87 | 88 | $cache->store("test", "test123", 1); 89 | sleep(2); 90 | self::assertSame(1, $cache->eraseExpired()); 91 | self::assertNull($cache->retrieve("test")); 92 | } 93 | 94 | public function testOverride() { 95 | $cache = new PhpFileCache(self::__TESTDIR); 96 | 97 | $cache->store("test", "first"); 98 | $cache->store("test", "second"); 99 | self::assertSame("second", $cache->retrieve("test")); 100 | } 101 | 102 | public function testClear() { 103 | $cache = new PhpFileCache(self::__TESTDIR); 104 | 105 | $cache->store("test2", "test123"); 106 | 107 | self::assertTrue($cache->eraseKey("test2")); 108 | self::assertNull($cache->retrieve("test2")); 109 | 110 | $cache->store("test3", "test123"); 111 | $cache->store("test4", "test123"); 112 | 113 | $cache->clearCache(); 114 | 115 | self::assertNull($cache->retrieve("test3")); 116 | self::assertNull($cache->retrieve("test4")); 117 | } 118 | 119 | public static function tearDownAfterClass() { 120 | foreach (glob(self::__TESTDIR . "*") as $item) { 121 | @unlink($item); 122 | } 123 | 124 | @rmdir(self::__TESTDIR); 125 | } 126 | 127 | } 128 | --------------------------------------------------------------------------------