Laravel session data not sticking across page loads - php

I tried running the following code:
Session::put('progress', '5%');
dd(Session::get('progress'));
This will show '5%' in the dump.
If I rerun the same page but comment out Session::put('progress', '5%'); so that only the dd() line is called, I get a null value instead of the 5% values stored in the previous page load.
Here is my sessions config, so I know it should be storing the data:
'driver' => 'native',
'lifetime' => 120,
'expire_on_close' => false,
Why is Laravel not storing the session data across page loads?

The problem is because you are killing the script before Laravel finishes its application lifecycle, so the values put in session (but not yet stored) got killed too.
When a Laravel application lifecycle starts, any value put in Session are not yet stored until the application lifecycle ends. That is when any value put in Session will be finally/really stored.
If you check the source you will find the same aforementioned behavior:
public function put($key, $value)
{
$all = $this->all();
array_set($all, $key, $value);
$this->replace($all);
}
If you want to test it, do the following:
Store a value in session without killing the script.
Route::get('test', function() {
Session::put('progress', '5%');
// dd(Session::get('progress'));
});
Retrieve the value already stored:
Route::get('test', function() {
// Session::put('progress', '5%');
dd(Session::get('progress'));
});

Rubens Mariuzzo's answer is very good. I just want to add that if you need the data to be stored immediately you could use the save method:
Session::put('progress', '5%');
Session::save();

For me, even after data has been stored to session properly:
dd(Session::all());
returns nothing, but:
print_r(Session::all());
returns all session data!

In my case I flashed the variable in one request and then put it into session in another request (with the same name).
Unfortunatelly, terminating method went through all the previously flashed properties and cleaned my newly created session property (it was flushed in previous request so laravel thought it was no longer required and couldn't tell it was newly created). I figured it out debugging Kernel->terminateMiddleware method. You can put a breakpoint in terminating method. At some stage it reaches Store->ageFlashData. This is the method responsible for deleting my property.

I moved the session middleware
\Illuminate\Session\Middleware\StartSession::class
to the property $middleware in
app/Http/Kernel.php
In this case, you need to remove it from the web group ($middlewareGroups)
It helped me, I hope it helps you too

Related

How to set database dynamically based on client request in Laravel

I am using a Laravel Application as a backend and wish to set the database connection dynamically (and keep it until the page is refreshed) through an axios request which will contain the database to use and the credentials.
For that purpose, I am storing the received DB configuration in a session and set the env variables with it in the constructor of whichever controller I am trying to use.
Here are the default database settings in .env :
DB_DATABASE=database1
DB_USERNAME=username1
DB_PASSWORD=password1
However, the issue seems to be that the session is not being kept alive, as each sent request contains a different session ID and therefore returns an Access denied error whenever I try to interact with the Database because the session variables are undefined.
Here is how the request is sent from the client :
axios
.post("https://data-test.io/api/Setconnection", {
database: "database2",
username: "username2",
password: "password2",
})
.then((result) => {
// console.log(result);
// do stuff here
});
This is how I store the DB connection in the session :
class RootController extends Controller
{
public function setConnection(Request $request){
session(['database' => $request->database]);
session(['username' => $request->username]);
session(['password' => $request->password]);
return $request->session()->all(); // this returns the correct values
}
}
And I set the route in api.php like so :
Route::post('/Setconnection',[RootController::class, 'setConnection']);
Then, on all subsequent requests, I set the connection in the constructor this way :
public function __construct() {
Artisan::call('config:cache');
Config::set('database', session('database'));
Config::set('username', session('username'));
Config::set('password', session('password'));
}
public function getConfig(){
return [session('database'),session('username'),session('password')];
// this returns an array of undefined elements.
}
Am I making a mistake here or is this not how I am supposed to set database connections dynamically? If not then what is the best way do so ?
As Tim Lewis said, APIs are supposed to be "Stateless" which no previously stored data that may be utilized in every transaction/request. If you don't want to use a database to store the dynamic database credentials, you need to save dynamic database credentials on the client side and send them each request.
But if you really want to create "Stateful" which can use session in the API you can follow these instructions.
Then to change database config you should use Config::set('database.connections.dbdrivername.configname','configvalue') and there is no need Artisan::call('config:cache')
an example:
Config::set('database.connections.mysql.database', session('database'));
Config::set('database.connections.mysql.username', session('username'));
Config::set('database.connections.mysql.password', session('password'));
You should really know what you are doing because it may have a big security hole.
I have needed this in the past for a multi-tenant application, and my solution was this:
DB::purge('mysql');
Config::set('database.connections.mysql.database', $request->database);
Config::set('database.connections.mysql.username', $request->username);
Config::set('database.connections.mysql.password', $request->password);
DB::reconnect('mysql');
Without the DB::purge and the DB::reconnect, the changes would not be applied to the connection.
With that out of the way, I too think this is a super risky practice. You are giving the world your database name and credentials.

Force logout of all users in Laravel

How can I force all users to be logged out in a SPA? I want it so that when I deploy a new version, all users automatically get logged out.
I tried the following, but I'm not sure if it's the safest way to do it.
php artisan key:generate
If your session data is stored in the database, you need to clear the sessions table. Running a simple SQL query will solve the problem:
DELETE FROM sessions;
If you sessions are stored in files, then as #Karl suggests, you need to delete the session files from the filesystem:
rm -rf storage/framework/sessions/*
The name of the session cookie can also be changed to force all sessions to be invalid, but this is a code change rather than clearing data. The name can be updated in the cookie key in config/session.php file. This option is NOT recommended.
As you can see, the SessionGuard does a few things, and they are agnostic of the type of SESSION_DRIVER you have set in your environment.
So after reading some of the discussion on forums with Taylor and some other Laravel heavy-weights about why there isn't such a simple function, perhaps the best solution would be create a post-deploy Job or Command that you could run that would simply cycle through all users, so for whatever is Session is set. I'd try something like:
\App\User::each(function ($u) {
Auth::login($u);
Auth::logout();
});
You can destroy all the sessions. If you use Laravel Envoy to handle deployments, you can add the following line.
rm -rf storage/framework/sessions/*
If you're using the database session driver, clearing the sessions table is easy.
DB::table('sessions')->truncate();
it's really depend on with session drive you picked.
if you using file drive you can delete storage/framework/sessions
path
if you using database drive you can delete all rows of session
table,
for any other drive you can do that like others.
You can also change cookie value in app/session.php, so user will automatically logout because of cookie is not match with the config
It's worth noting that Laravel actually only stores active sessions in
the session folder; those that are 'remembered' but haven't been
actively accessing your application do not count among these sessions.
As such, just deleting the files won't finish the job.
You must also clear all Remember Tokens from the users table, as this
token is used in conjunction with the local token stored in the cookie
to re-create the session when a user reconnects.
I'm updating all user's remember tokens to blank and then flushing stored session and then modifying HomeController.
\DB::table('users')->update(array(
'remember_token' => '',
'logout_at' => Carbon::now()->toDateTimeString()));
Session::flush();
Then in HomeController modify index function
public function index()
{
if (Auth::check()) {
$token = Auth::user()->remember_token;
if ($token) {
return view('home');
} else {
return redirect('/logout');
}
} else {
return view('home');
}
}
I'd like to share another way to achieve this, if the driver used is file.
This is the "pure" php way, so it could be a helper 'flush_sessions()':
$sessions = glob(storage_path("framework/sessions/*"));
foreach($sessions as $file){
if(is_file($file))
unlink($file);
}
It is safe to use this function? PHP will keep hidden files inside given directory (.gitignore)... so, try it out, it is safe.
It is worth to mention that if you put this inside a controller method, then your session will be restored after delete the file (apparently, Laravel will try to update the file after the request ends and if it doesn't exists, will re-create it). But all other sessions (users) will be logged out. If you run this code in php artisan tinker, for example, will not keep your own session file (because artisan runs with 'array' driver).
But, that is useful in my opinion. For example: if admin user wants to logout all users except himself.
For example:
You have two sessions:
After running the function, you have only one (the user that used it):
I hope this helps someone.
//To Logout Specific user:
//$id == user id to to whom you want to logout
\DB::table('users')->where('id', $id)->update(['remember_token' => null]);
\DB::table('sessions')->where('user_id', $id)->delete();
//To Logout All Users
$sessions = glob(storage_path("framework/sessions/*"));
foreach ($sessions as $file) {
if (is_file($file))
unlink($file);
}
//$id == user id to to whom you want to logout
\DB::table('users')->update(['remember_token' => null]);
\DB::table('sessions')->truncate();
No need to use sessions table operation if you are not using database as session driver.

Cannot update Laravel Session variable?

I have an ongoing problem in Laravel. I am building "load more" system for comments with Laravel and Ajax, and using Session variable for counting and skipping already loaded rows. But for some reason my session variable wont persist, for unknown reason (trying whole the day to resolve this).. Ok here is some code:
public function load_more() {
$comments = Comments::whereid(Input::get('article_id'))->orderBy('id','DESC')->skip(Session::get('loaded')->take(12)->get();
Session::set('loaded', Session::get('loaded') + 12 ) ;
return \Response::json($comments);
}
So as you can see i am trying to increment variable each call. But the variable stays the same all the time.. When I make another variable for example Session::set('another', Session::get('loaded') + 12 ) ;
it actually get summed and i have sum in this variable.. but why it cannot update itself?
Fixed the problem in frontend with Jquery global counter which I am sending as an GET argument on every request, instead of using Session variables. Still don't know what's the problem with session, maybe some bug in my Laravel installation.
If your have laravel 5.2 the probleme is you put your route into group web
Route::group(['middleware' => ['web']], function () {
PUT YOUR ROUTE HERE
}

Set session variable in laravel

I would like to set a variable in the session using laravel this way
Session::set('variableName')=$value;
but the problem is that I don't know where to put this code, 'cause I would like to set it for one time (when the guest visite the home page or any other page)?
The main idea is to use a global variable to use it in all application controllers, I heared about something related to configuration variables but I'm not sure if it will be a good Idea to use config variables or only the session?
Thanks
The correct syntax for this is:
Session::set('variableName', $value);
For Laravel 5.4 and later, the correct method to use is put:
Session::put('variableName', $value);
To get the variable, you would use:
Session::get('variableName');
If you need to set it once, I'd figure out when exactly you want it set and use Events to do it.
For example, if you want to set it when someone logs in, you'd use:
Event::listen('auth.login', function() {
Session::set('variableName', $value);
});
I think your question ultimately can be boiled down to this:
Where can I set a long-lived value that is accessible globally in my application?
The obvious answer is that it depends. What it depends on are a couple of factors:
Will the value ever be different, or is it going to be the same for everybody?
How long exactly is long-lived? (Forever? A Day? One browsing 'session'?)
Config
If the value is the same for everyone and will seldom change, the best place to probably put it is in a configuration file somewhere underneath app/config, e.g. app/config/companyname.php:
<?php
return [
'somevalue' => 10,
];
You could access this value from anywhere in your application via Config::get('companyname.somevalue')
Session
If the value you are intending to store is going to be different for each user, the most logical place to put it is in Session. This is what you allude to in your question, but you are using incorrect syntax. The correct syntax to store a variable in Session is:
Session::put('somekey', 'somevalue');
The correct syntax to retrieve it back out later is:
Session::get('somekey');
As far as when to perform these operations, that's a little up to you. I would probably choose a route filter if on Laravel 4.x or Middleware if using Laravel 5. Below is an example of using a route filter that leverages another class to actually come up with the value:
// File: ValueMaker.php (saved in some folder that can be autoloaded)
class ValueMaker
{
public function makeValue()
{
return 42;
}
}
// File: app/filters.php is probably the best place
Route::filter('set_value', function() {
$valueMaker = app()->make('ValueMaker');
Session::put('somevalue', $valueMaker->makeValue());
});
// File: app/routes.php
Route::group(['before' => 'set_value'], function() {
// Value has already been 'made' by this point.
return View::make('view')
->with('value', Session::get('somevalue'))
;
});
In Laravel 5.6, you will need to set it as:
session(['variableName' => $value]);
To retrieve it, is as simple as:
$variableName = session('variableName');
For example, To store data in the session, you will typically use the putmethod or the session helper:
// Via a request instance...
$request->session()->put('key', 'value');
or
// Via the global helper...
session(['key' => 'value']);
for retrieving an item from the session, you can use get :
$value = $request->session()->get('key', 'default value');
or global session helper :
$value = session('key', 'default value');
To determine if an item is present in the session, you may use the has method:
if ($request->session()->has('users')) {
//
}
in Laravel 5.4
use this method:
Session::put('variableName', $value);
To add to the above answers, ensure you define your function like this:
public function functionName(Request $request) {
//
}
Note the "(Request $request)", now set a session like this:
$request->session()->put('key', 'value');
And retrieve the session in this way:
$data = $request->session()->get('key');
To erase the session try this:
$request->session()->forget('key');
or
$request->session()->flush();
You can try
Session::put('variable_Name', "Your Data Save Successfully !");
Session::get('variable_Name');
In Laravel 6.x
// Retrieve a piece of data from the session...
$value = session('key');
// Specifying a default value...
$value = session('key', 'default');
// Store a piece of data in the session...
session(['key' => 'value']);
https://laravel.com/docs/6.x/session
If you want persistence sessions,
Method 1: use session()->save() or Session::save()
session(['key' => 'value']);
//or
session()->put('key', 'value');
//then
session()->save();
echo session('key');
Method 2: Move bellow line from protected $middlewareGroups of app\Http\Kernel.php to protected $middleware array as first line
\Illuminate\Session\Middleware\StartSession::class,
Make sure the storage directory has write permission
chmod -R a+rw storage/
Don't use dd() to verify session, use print_r()
to set session you can try this:
$request->session()->put('key','value');
also to get session data you can try this:
$request->session()->get('key');
If you want to get all session data:
$request->session()->all();

yii Session gets cleaned on every request

Example of my code:
class SiteController extends Controller {
/**
* This is the default 'index' action that is invoked
* when an action is not explicitly requested by users.
*/
public function actionIndex() {
$_SESSION['test'] = 'testdata';
var_dump($_SESSION); exit;
}
Example on the second request:
class SiteController extends Controller {
/**
* This is the default 'index' action that is invoked
* when an action is not explicitly requested by users.
*/
public function actionIndex() {
var_dump($_SESSION);exit;
}
I have a project in yii. Project not mine - I'm just trying to fix errors.
My problem is:
first var_dump() shows that $_SESSION variable HAS the "test" index with "testdata". On the second request though I get an empty array of $_SESSION variable. Meaning, that every request session gets cleaned up. I've checked - the session ID stays the same. I've also checked this projects config - i can't find any references to extending SESSION component and changing it's behaviors. Also, when logging in yii DOES save states into SESSION, but the login fails because of SESSION being cleaned after redirect. That is to say COOKIE BASED authentication works which just proves the root of the problem.
Would very much appreciate help.
UPDATE
I've narrowed it down. This is the code for FRONT YII FRONT CONTROLLER(index.php):
<?php
#session_start(); // this line is at cwebuser.php at init() method and it is called at every request. should work properly.
var_dump($_SESSION);
$_SESSION['test'] = 'asdasd';
var_dump($_SESSION);exit;
It still prints empty $_SESSION on the second REQUEST. So the problem is probably not with the framework.
You can set session details in your /protected/config/main.php (this is the default unless you have changed it in index.html)
'session' => array(
'autostart' => true,
'timeout' => 1440, // time in seconds
),
Read about Session on CHttpSession
My problem was that I accessed my website via server ip : 123.123.123.123/site/index and this has conflicts with accessing and saving the session. Though I don't know the details. If someone has knowledge on this stuff I will gladly accept his(her) answer as the right one.
There is a file called controller.php under protected/components/controller.php which will be called before any action get called .. u can check that file and see... is there done any logout function calledthere...
//It clears all the sesstion data... or any php way
Yii::app()->user->logout();
Yes if u are in moule then u can also check ModuleName.php under module directopry ... if there is any session clearing script...
which clears the session... And yes this is not the right way of using session in Yii yes it is PHP but YII .... u can use folowing sytax dfor sessions..
//to set a session variable mnamed test
Yii::app()->user->setState('test',$test);
//to get a session variable named tets
Yii::app()->user->getState('test');

Categories