Laravel 4 clear all expired cache - php

In Laravel, we can store cache with this:
Cache::put($dynamickey, 'value', $minutes);
But this will end up more and more cache files stored even after it is expired. If we try to clean it with php artisan cache:clear or Cache::flush();, it will wipe out all the cache including those that are still valid.
Is it possible to have auto clean up that will clear only expired cache? Thanks.

$value = Cache::remember('users', function()
{
return DB::table('users')->get();
});
Does the work. It validate if cache with given key exists and returns its value. It it does not exist or expired then refresh given cache key with new value.
For Images cache I uses logic like:
tore image md5($file); //where $file === full image path with
image name
Store image md5(file_get_contents($file)); //self explaining method :)
Then
if (Cache::has($cacheKey_name) && !Cache::has($cacheKey_content))
{
Cache::forget($cacheKey_name);
Cache::forget($cacheKey_content);
}
It will check if image is cached and only content changed. If yes then remove old cache and cache new image (with new content). With this logic you will have always fresh image content (with overwritten images).
Or, you can always create artisan task and create Controller to check all cache data in storage directory, then create Cron Task.

you can create an function like this
function cache($key,$value,$min){
(Cache::has($key))?Cache::put($key,$value,$min):Cache::add($key,$value,$min);
if(Cache::has('caches')){
$cache=Cache::get('caches');
$cache[time()+(60*$min)]=$key;
Cache::forget('caches');
Cache::rememberForever('caches',function() use($cache){
return $cache;
});
}else{
$cache[time()+(60*$min)]=$key;
Cache::rememberForever('caches',function() use($cache){
return $cache;
});
}
$cache=Cache::get('caches');
foreach($cache as $key=>$value)
{
if($key<time())
{
Cache::forget($value);
array_forget($cache, $key);
}
}
Cache::forget('caches');
Cache::rememberForever('caches',function() use($cache){
return $cache;
});}
and to remove this cache empty folders you can edit
vendor\laravel\framework\src\Illuminate\Cache\FileStore.php
on line 182
after this code
public function forget($key)
{
$file = $this->path($key);
if ($this->files->exists($file))
{
$this->files->delete($file);
add a function to remove all empty folders , like blow code
public function forget($key)
{
$file = $this->path($key);
if ($this->files->exists($file))
{
$this->files->delete($file);
RemoveEmptySubFolders($this->getDirectory());
to use this function you can see it
Remove empty subfolders with PHP

Related

Laravel 9 multiple tag flush not working when flushing individual tags

I've noticed an issue with my Laravel application, and i'm not quite sure if i'm just doing something stupidly wrong, or there is a genuine issue.
So i'm storing and fetching my cached data with multiple tags on my App\Models\User\User model like below
public function getSetting(String|Bool $key = false) : Mixed {
//Try
try {
return cache()->tags(["user_{$this->id}_cache", 'user_settings'])->remember("user_{$this->id}_settings", now()->addDays(1), function(){
return $this->settings()->pluck('value', 'key')->toArray();
});
} catch(\Exception $e){
//Logging errors here
}
}
This function simply grabs all of the users settings and returns an array.
I am using 2 cache tags because I want to cover both scenarios
The ability to be able to remove all cached items for a specific model (User)
The ability to be able to remove a specific type of cache across all models (Users)
The Laravel cache documentation simply states to pass the tag (or tags as an array) that you want to remove.
So my thinking is that if I want to clear user settings cache for all users, I should be able to run the following
cache()->tags('user_settings')->flush();
and if I want to remove all cache for a specific user, I should be able to run
cache()->tags('user_1_cache')->flush();
But for some reason, only the second example (using user_1_cache) works? If I run the first example and try to clear all cache with the tags user_settings, the function returns true but does not clear the cache?
Am I doing something stupidly wrong or just completely misunderstanding how the cache tags work?
Versions
PHP - 8.1
Laravel - 9.3.8
Cache driver - Redis
I reproduced your scenario here. It's working as stated in the docs.
class User extends Model
{
protected $fillable = ['id', 'name'];
public function cacheSettings()
{
return cache()->tags([$this->getUserCacheKey(), 'user_settings'])->remember("{$this->id}_settings", now()->addDay(), function () {
return $this->only('name');
});
}
public function getSettings()
{
return cache()->tags([$this->getUserCacheKey(), 'user_settings'])->get("{$this->id}_settings");
}
public function getUserCacheKey()
{
return "user_{$this->id}_cache";
}
}
These tests run with no problem:
public function test_cache_flush_all_users()
{
Cache::clear();
$alice = new User(['id' => 1, 'name' => 'alice']);
$john = new User(['id' => 2, 'name' => 'john']);
$alice->cacheSettings();
$john->cacheSettings();
Cache::tags('user_settings')->flush();
// both deleted
$this->assertNull($alice->getSettings());
$this->assertNull($john->getSettings());
}
public function test_cache_flush_specific_user()
{
Cache::clear();
$alice = new User(['id' => 1, 'name' => 'alice']);
$john = new User(['id' => 2, 'name' => 'john']);
$alice->cacheSettings();
$john->cacheSettings();
Cache::tags($alice->getUserCacheKey())->flush();
// only alice deleted
$this->assertNull($alice->getSettings());
$this->assertNotNull($john->getSettings());
}
Not having all details of your implementation, perhaps you can figure out what is causing the issue.

How to Check file exists in Laravel

I have a Laravel Controller Function file_fetch()
public function file_fetch(Request $request) {
$file = request('routename');
$destinationPath = public_path('/folder/'.$file);
if(!File::exists($destinationPath)){
$content = File::get($destinationPath);
return view('filefetch', compact('file','content'));
}
else {
return redirect('/')->witherrormessage('NO such File Exists');
}
}
This works if i check for file public/folder/app/index.html and if i check for public/newfolder (newfolder doesnt exist) and hence it executes else function and redirects with error message, but if i search for public/folder/app/ I havent specified the file name, but the directory exists, hence the if(!File::exists($destinationPath)) function is getting executed!
i want to check just and files inside the directory and even if the directory exists, if file is not present, throw a error message, saying file doesnt exists.
add one more additional condition to check given path is file but not a directory
public function file_fetch(Request $request) {
$file = request('routename');
$destinationPath = public_path('/folder/'.$file);
if(!File::exists($destinationPath) && !is_dir($destinationPath)){
$content = File::get($destinationPath);
return view('filefetch', compact('file','content'));
}
else {
return redirect('/')->witherrormessage('NO such File Exists');
}
}
You can probably fix your code by validating the routename input such that it will never be empty (and have a certain file extension maybe?)
, which is nice to do anyhow.
If that fails, you can try File::isDirectory($dir) which basically calls is_dir(...).
Note that it might give you more control on your storage solution if you use the Storage::disk('public') functionalities from Laravel. The API is a bit different but there's a wide range of probabilities associated with it. Read more about that here: https://laravel.com/docs/8.x/filesystem#introduction.
If you in different/multiple buckets.
//Do not forget to import
use Illuminate\Support\Facades\Storage;
if (Storage::disk('s3.bucketname')->exists("image1.png")) {
}

Is there a way to save values besides in the DataBase with Laravel 5.5?

I'm trying something crazy. The thing is that I need to save the Board of Directors number (the actual Board of Directors is the XXXVI but this year it will change to XXXVII) value on the variable because I think it is useless to make a table just to save a value that will change every 2 years. So it occurred to me using a global variable on the controller to save that value and everything goes wel with my code EXCEPT it's not saving the value into the variable. Here's my code:
Controller Code:
//Here I declare the variable
protected $board;
// Here I initialize the variable so I can send it to the template
public function editDirectors()
{
$numberBoard = $this->board;
return view('board.edit_directors', compact('numberBoard'));
}
//Here it's supposed to save the value into the variable
public function uploadNumber(Request $request)
{
$this->board = $request->value;
$numberBoard = $this->board;
return $numberBoard;
}
Template code:
<a href="#" id="board-number" data-type="text"
data-pk="1"
data-url="{{url('/board-of-directors/edit/number-board')}}"
data-value="{{$numberBoard}}"
data-name="numberBoard"
data-title="Number Board">{{$nummberBoard}}</a>
Board of Directors</h3>
X-Editable Initilization
$('#board-number').editable();
The Route
Route::put('/board-of-directors/edit/number-board' , 'DirectorController#uploadNumber');
The funny thing is that when I display the Web Console to check the Network Tab and inspect the XHR section it send a 200 Response and, in preview, it returns the value I enter but it doesn't save the value into the variable.
The help will be really appreciated :3
EDIT:
I created a config/board.php file and added this lines:
return [
'director' => [
'number' => 'XXXVI'
]
];
Modified the Controller with this:
// Here I get the value at config/board.php and send it to the template and works :D
public function editDirectors()
{
$numberBoard = Config::get('board.director.number');
return view('board.edit_directors', compact('numberBoard'));
}
//Here it's supposed to save the new value into the config/board.php file but doesn't works :(
public function uploadNumber(Request $request)
{
$numberBoard = $request->value;
Config::set('board.director.number', $numberBoard);
return $numberBoard;
}
The I ran this command so the config/board.php could send the value to the controller.
php artisan config:cache
Also, everytime I change the value at config/board.php it seems that I have to run this command to make it show the value.
Any ideas you could suggest? It will be really appreciated :3
You can save this in config or .env file.
Define in .env
DirectorNumber=XXVII
access in application Controller
protected $board;
function __construct($board)
{
$this->$board = env('DirectorNumber');
}
Otherwise you can save this in config files
Create a board.php in config folder
In config/board.php write <?php return ['count' => 'XXVII'];
access variable by config('board.count')
edit: in case of config:cache laravel doesn't pick updated env variable so either re-run config:cache or config:clear (it will start resuming env values in application)
Solution
I think what I did is a bad practice but it solved my problem.
Taken from: How to set .env values in laravel programmatically on the fly
First I added this in my .env file:
BOARD_NUMBER = XXXVI
Then I updated my code in the Controller:
//Here I get the value form the BOARD_NUMBER at .env and send it to the template
public function editDirectors()
{
$numberBoard = env('BOARD_NUMBER');
return view('board.edit_directors', compact('directors', 'numberBoard'));
}
//Here I open the .env and rewrite the BOARD_NUMBER value
protected function uploadNumber(Request $request)
{
$numberBoard = $request->value;
$envFile = app()->environmentFilePath();
$str = file_get_contents($envFile);
$oldValue = env('BOARD_NUMBER');
$str = str_replace("BOARD_NUMBER={$oldValue}", "BOARD_NUMBER={$numberBoard}\n", $str);
$fp = fopen($envFile, 'w');
fwrite($fp, $str);
fclose($fp);
}
In the same link where I took the solution, there's another solution where the command "php artisan config:cache" runs but I doubt it works for me because I'm uploading the web app to a shared host.
Hopes this helps other :)

How to disable cache in open cart CMS

I used to set $expire = 0; in all cache.php files. Delete all from cache folder. Put $this->cache->delete(); in some random files. Use Ctrl+F5 in my brouser. But cache still alive.
Easiest way would be to just return false from the cache->get method:
system/library/cache.php:
public function get($key) {
return false;
Open up system/library/cache.php and comment these:
public function get($key) {
// return $this->adaptor->get($key);
}
public function set($key, $value) {
// return $this->adaptor->set($key, $value);
}
I know, it's very annoying. OpenCart really should implement an easier way to disable cache.
template_cache takes the value from developer_theme. Do the following:
Go to oc_setting table (database)
Find (developer_theme) of the key column
Then change the value column to 0
I found it!! This worked for me... find vqmod.php file and before $this->_filesModded[$sourcePath] = array('cached' => $changed); Assign $changed to false like $changed = false; save and reload page.

Save file to memory and later write back

I wish to read a file using PHP, and later write it to a directory which doesn't exist at the time of reading the file. I can't create the directory first as described below. I do not wish to save it in a temporary directory to prevent possible overwrites. Am I able to read the file, save it in memory, and later write the file?
WHY I WISH TO DO THIS: I have the following method which empties a directory. I now have a need to do so but keep one file in the root of the emptied directory. I recognize I could modify this method to do so, but I rarely need to do so, and may wish another approach. Instead, before calling this method, I would like to copy the file in question, empty the directory, and then put it back.
/**
* Empty directory. Include subdirectories if $deep is true
*/
public static function emptyDir($dirname,$deep=false)
{
$dirname=(substr($dirname, -1)=='/')?$dirname:$dirname.'/';
if(!is_dir($dirname)){return false;}
// Loop through the folder
$dir = dir($dirname);
while (false !== $entry = $dir->read())
{
// Skip pointers
if ($entry == '.' || $entry == '..') {
continue;
}
elseif(is_file($dirname.$entry)) {
unlink($dirname.$entry);
}
elseif($deep && is_dir($dirname.$entry)){
self::deltree($dirname.$entry);
}
}
// Clean up
$dir->close();
return true;
}
Provided this is all done withing the same request, then yes you can.
Just save the file contents to a variable, then write it back again:
$temp = file_get_contents('path/to/file.ext');
className::emptyDir($dir);
file_put_contents('path/to/file.ext', $temp);
Yes, it could be done. Just add a property to your class. So in your class property, there will be the content of the file, while the object is exists, and it did set. It could be a class variable (static) also, so you do not need to instantiate if you do not want.
class anything {
var $fileContent = '';
public static function emptyDir($dirname,$deep=false) {
//....
}
public function setFileContent($fileOrUrlToRead) {
$this->fileContent = file_get_contents($fileOrUrlToRead);
}
public function saveFile($fileName) {
file_put_contents($fileName, $this->fileContent);
}
}
$anything = new anything();
$anything->setFileContent('url_or_path_of_file_to_get');
anything::emptyDir('./media/files/');
$anything->saveFile('./media/files/something.txt');
You can use the session to save the needed information.

Categories