19

The Cache class in laravel has methods such as get('itemKey') to retrieve items from the cache, and remember('itemKey', ['myData1', 'myData2']) to save items in the cache.

There is also a method to check if an item exists in the cache: Cache::has('myKey');

Is there any way, (when using the file-based cache driver), to get a list of all items in the cache?

For instance, something that might be named something like "Cache::all()" that would return:

[
    'itemKey' => [
        'myData1',
        'myData2'
   ],
   'myKey' => 'foo'
]

The only way I can think of doing this is to loop through all possible key names using the Cache::has() method. i.e. aaa, aab, aac, aad... but of course, this is not a solution.

I can't see anything in the documentation or the API that describes a function like this, but I don't think its unreasonable to believe that one must exist.

jedrzej.kurylo
  • 39,591
  • 9
  • 98
  • 107
kohloth
  • 742
  • 1
  • 7
  • 21
  • 1
    What caching backend are you using ? Redis? Memcached? or ? – alfallouji Aug 03 '15 at 15:40
  • File cache. I've read there is a function like the one I describe for Memcached, and that there is the option of using tags. But I need to use file as its a lot of data. – kohloth Aug 03 '15 at 15:46

7 Answers7

15

Older answers didn't work for me in Laravel 5.2 so I used this solution:

    $storage = \Cache::getStore(); // will return instance of FileStore
    $filesystem = $storage->getFilesystem(); // will return instance of Filesystem
    $dir = (\Cache::getDirectory());
    $keys = [];
    foreach ($filesystem->allFiles($dir) as $file1) {

        if (is_dir($file1->getPath())) {

            foreach ($filesystem->allFiles($file1->getPath()) as $file2) {
                $keys = array_merge($keys, [$file2->getRealpath() => unserialize(substr(\File::get($file2->getRealpath()), 10))]);
            }
        }
        else {

        }
    }
miken32
  • 42,008
  • 16
  • 111
  • 154
mangas
  • 464
  • 4
  • 8
  • On my server I found they were not in another dir, so would need the else {} $keys = array_merge($keys, [$file1->getRealpath() => unserialize(substr(\File::get($file1->getRealpath()), 10))]); – tristanbailey Jan 28 '17 at 14:31
  • This was on Laravel 5.3, as jedrzej.kurylo would not work, this did though – tristanbailey Jan 28 '17 at 14:33
11

There is no way to do that using Cache facade. Its interface represents the functionality that all underlying storages offer and some of the stores do not allow listing all keys.

If you're using the FileCache, you could try to achieve that by interacting with the underlying storage directly. It doesn't offer the method you need, so you'll need to iterate through the cache directory. It won't be too efficient due to a lot of disk I/O that might need to happen.

In order to access the storage, you need to do

$storage = Cache::getStore(); // will return instance of FileStore
$filesystem = $storage->getFilesystem(); // will return instance of Filesystem

$keys = [];
foreach ($filesystem->allFiles('') as $file1) {
  foreach ($filesystem->allFiles($file1) as $file2) {
    $keys = array_merge($keys, $filesystem->allFiles($file1 . '/' . $file2));
  }
}
jedrzej.kurylo
  • 39,591
  • 9
  • 98
  • 107
10

In 'yourKeyGoesHere' you can insert a string used as same as a like with a * or insert directly the exactly key.

 $redis = Cache::getRedis();
 $a_keys = $redis->keys("*yourKeyGoesHere*");
 foreach ($a_keys as $key){
    //Your Action ...
    //For example forget key
    $redis->del($key);
 }
nat_jea
  • 285
  • 3
  • 5
  • 1
    While this code snippet may solve the question, [including an explanation](http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Isma Feb 26 '18 at 15:24
  • 1
    Work with Redis I think, but... please explain ? what is *yourKeyGoesHere* ? – neoteknic Jun 29 '18 at 15:31
  • 1
    $redis->keys('*'); Will get you all the keys – Joel Jan 24 '19 at 11:44
  • `Cache::getRedis()` doesn't work (Laravel 8), `Cache::driver()` works but you get an instance of _Illuminate\Cache\Repository_ and it doesn't seem to provide a method to get the whole cache content. – ThCollignon Dec 01 '21 at 10:34
7

For Memcached, you can do this:

cache()->getMemcached()->getAllKeys()
  1. get Illuminate\Cache\CacheManager
  2. Get Memcached: http://php.net/manual/de/class.memcached.php
  3. getAllKeys(): http://php.net/manual/de/memcached.getallkeys.php

This gives you an array of keys you can go through.

repat
  • 320
  • 3
  • 12
4

in \config\database.php make a redis store for the cache

   // store cache in their own redis store ...
    'cache-connection' => [
        'host'               => ...,
        'password'           => ...,
        'port'               => env('REDIS_PORT', 6379),
        'database'           => 2,
        'read_write_timeout' => 60,
        'timeout'            => 6.0,
    ],

in \config\cache.php use this redis database

'stores' => [
   ...
   'redis' => [
        'driver'     => 'redis',
        'connection' => 'cache-connection',
    ],
],

now you can use Redis class to check what is in your cache

$a = Redis::connection('cache-connection')->keys('*');
\Log::debug($a);
Yevgeniy Afanasyev
  • 37,872
  • 26
  • 173
  • 191
  • I tried following this advice but am getting stuck on the part where I get the values from the keys: [question here](https://stackoverflow.com/questions/63959859/get-all-the-values-that-ive-set-using-cacheput) – TKoL Sep 18 '20 at 16:56
3

Step 1

// Add Namespace
use Illuminate\Support\Facades\Redis;

Step 2

// Get All Available Keys
$cacheKeys = Redis::connection('cache')->keys('*');

Step 3

// Laravel DDD
ddd($cacheKeys);

OR

// PHP Variable Dump
var_dump($cacheKeys);
  • 1
    Thank you for contributing, but this answer was [already given](https://stackoverflow.com/questions/2860052/php-how-to-call-standard-library-functions) and does not need to be repeated. – miken32 Dec 24 '21 at 16:31
  • 2
    @miken32 there is nothing on your link, his answer is very helpful. – Tahola Aug 13 '22 at 06:04
  • @Tahola obviously wrong link, probably meant this one, another answer on this question: https://stackoverflow.com/a/58514663/1255289 – miken32 Aug 14 '22 at 18:50
  • This Can be done using Redis but in my case, I'm using laravel cache and I'm not sure I'll use Redis as a cache. – Niyanta Bhayani Oct 14 '22 at 13:16
1

I know this is an old question but I ran into the issue the other day and couldn't find a solution anywhere for the file storage system.

My use case was that I wanted to be able to remove based on the naming convention of full stops seperating groups. For example cache()->forget('foo') wouldn't remove the key foo.bar.

The way it works is it keeps a json encoded array of all the keys you add to the file store, then when you want to remove it loops through and if it matches it is removed. This may be useful to you as well but if not your use case could utilize the cache()->getKeys() method which now works too.

Steps to follow:

In your AppServiceProvider.php register method add the following:

use Illuminate\Support\Facades\Cache;
use App\Extensions\FileStore;
...
$this->app->booting(function () {
    Cache::extend('file', function ($app) {
        return Cache::repository(new FileStore($app['files'], config('cache.stores.file.path'), null));
    });
});

Then create a new directory in app called Extensions. Add a new file in the new Extensions directory called FileStore.php with the following contents:

<?php

namespace App\Extensions;

class FileStore extends \Illuminate\Cache\FileStore
{
    /**
     * Get path for our keys store
     * @return string
     */
    private function keysPath()
    {
        return storage_path(implode(DIRECTORY_SEPARATOR, ['framework','cache','keys.json']));
    }

    /**
     * Get all keys from our store
     * @return array
     */
    public function getKeys()
    {
        if (!file_exists($this->keysPath())) {
            return [];
        }

        return json_decode(file_get_contents($this->keysPath()), true) ?? [];
    }

    /**
     * Save all keys to file
     * @param  array $keys
     * @return bool
     */
    private function saveKeys($keys)
    {
        return file_put_contents($this->keysPath(), json_encode($keys)) !== false;
    }

    /**
     * Store a key in our store
     * @param string $key [description]
     */
    private function addKey($key)
    {
        $keys = $this->getKeys();

        // Don't add duplicate keys into our store
        if (!in_array($key, $keys)) {
            $keys[] = $key;
        }

        $this->saveKeys($keys);
    }

    // -------------------------------------------------------------------------
    // LARAVEL METHODS
    // -------------------------------------------------------------------------

    /**
     * Store an item in the cache for a given number of seconds.
     *
     * @param  string  $key
     * @param  mixed  $value
     * @param  int  $seconds
     * @return bool
     */
    public function put($key, $value, $seconds)
    {
        $this->addKey($key);
        return parent::put($key, $value, $seconds);
    }

    /**
     * Remove an item from the cache.
     *
     * @param  string  $key
     * @return bool
     */
    public function forget($forgetKey, $seperator = '.')
    {
        // Get all stored keys
        $storedKeys = $this->getKeys();

        // This value will be returned as true if we match at least 1 key
        $keyFound = false;

        foreach ($storedKeys as $i => $storedKey) {
            // Only proceed if stored key starts with OR matches forget key
            if (!str_starts_with($storedKey, $forgetKey.$seperator) && $storedKey != $forgetKey) {
                continue;
            }

            // Set to return true after all processing
            $keyFound = true;

            // Remove key from our records
            unset($storedKeys[$i]);
            
            // Remove key from the framework
            parent::forget($storedKey);
        }

        // Update our key list
        $this->saveKeys($storedKeys);

        // Return true if at least 1 key was found
        return $keyFound;
    }
    
    /**
     * Remove all items from the cache.
     *
     * @return bool
     */
    public function flush()
    {
        $this->saveKeys([]);
        return parent::flush();
    }
}