I use Yii2 sessions for storing session data for guest users.
During sessions there are files generated in #runtime directory. These files are named with a database id (e.g. 234.pdf).
When a user selects something, the selection is saved in the db, stored in the session and a file is generated:
$model->save();
file_put_contents($model->id.".pdf", ...);
Yii::$app->session->set("model_id",$model->id);
When a session expires the sesseion related files should be removed. The database contents have to be kept for statistical reasons.
How do I get recognized when a session expires?
Yii does not have configurable session event handlers, in your case I would create own specific session handler extending PHP's built-in SessionHandler.
namespace app\components;
class CustomSessionHandler extends \SessionHandler
{
public function destroy($sessionId)
{
// here you could implement your custom requirements
return parent::destroy($sessionId);
}
}
and here is your configuration
'components' => [
'session' => [
'handler' => \app\components\CustomSessionHandler::class
],
...
];
Related
I have a module which uses a secondary database. In it, I am trying to log in to the user table from that secondary database. The problem is that the \Yii::$app->user->identity->id is using the first database. How should I override the class to do it like this? What I got in my LoginForm.php in the module is :
public function login()
{
if ($this->validate() && $this->user) {
$isLogged = Yii::$app->getUser()->login($this->user, $this->rememberMe ? $this->module->rememberFor : 0);
//var_dump($this->user);exit;
if ($isLogged) {
$user = \frontend\modules\store\models\User::findOne(Yii::$app->user->identity->id);
$user->last_login_at = time();
$user->update();
// $this->user->updateAttributes(['last_login_at' => time()]);
}
return $isLogged;
}
return false;
}
As you can see the user class here is overridden and it is using the secondary database. But how should I override the Yii::$app->user->identity->id to use this database also? Thank you in advance!
As you are using Yii2 advanced template, you should consider adding a new sub application. Yii2 advanced template allows you to have different sessions for frontend and backend sub applications. Advanced Template on Same Domain and different sessions
Similarly, you can add a new app, in your case it may be called store. If you do it as a separate app, you can simply override identity class and even have different model for user. Help about adding new app is here.
You can override user identity in config
'user' => [
'identityClass' => 'app\models\User', // User must implement the IdentityInterface
'enableAutoLogin' => true,
// 'loginUrl' => ['user/login'],
// ...
]
more info here
Im using Zend Framework 3 and the SessionManager and im trying to build a controller plugin / view helper to display confirm dialogues after validating some Data . The idea was simply to set a Session variable with everything the confirm dialogue needs, reading it by the view, and unsetting it. But even this simple cycle fails. The plugin basically does this when invoked by the controller:
$dataArray = [
'some_data' => 'data'
];
$this->sessionManager->getStorage()->confirmDialog = $dataArray;
in the layout.phtml i call my view Helper which does this:
public function __invoke() {
$data = $this->sessionManager->getStorage()->confirmDialog;
$this->sessionManager->getStorage()->clear('confirmDialog');
return $this->getDialog($data);
}
I do inject the sessionManager to both the plugin and the view helper. When not clearing the variable after receiving its data i get the changed data from the session variable and it gets updated by the Plugin as it should.But when clearing the variable after the first time reading it, its always empty.
Here my global.php setup:
'session_manager' => [
'validators' => [
RemoteAddr::class,
HttpUserAgent::class,
]
],
'session_storage' => [
'type' => SessionArrayStorage::class
]
Because the value is passed by reference, when you clear it, you clear the read information with it also.
As I mentioned in a comment, I suggest using the default falsh messenger plugin, but if you want to create your own plugin, here is a hint from that's source code, which shows you how you can achieve a default clear after read from session.
https://github.com/zendframework/zend-mvc-plugin-flashmessenger/blob/843654a029a19c38e0c3b2e940e59edec75c3e4f/src/FlashMessenger.php#L165
This setting is actually tells the session container to drop that information after '1 hop', ie. in case of a next request.
I have been facing issue related to Session timeout using Zend Framework 3. Session expired within 5-10 min. I had used the default code for the session, which Zf3 skeleton provides in global.php as below.
// Session configuration.
'session_config' => [
'cookie_lifetime' => 60*60*1, // Session cookie will expire in 1 hour.
'gc_maxlifetime' => 60*60*1, // Store session data on server maximum for 1 hour.
],
// Session manager configuration.
'session_manager' =>
[
'validators' => [
RemoteAddr::class,
HttpUserAgent::class,
]
],
// Session storage configuration.
'session_storage' => [
'type' => SessionArrayStorage::class
],
After using above code still session expired within 5-10 minutes.I want session expired time more than 30 minutes.How to configure it in Zf3.
Please provide solution.
You have the correct settings for the session manager, but this is not enough for these session settings to be used as the default one.
My assumption is that you do not make this session manager your default one. In order to make it, you need to instantiate it as early as possible.
One solution would be to do this is in module Module.php
use Zend\Mvc\MvcEvent;
use Zend\Session\SessionManager;
class Module
{
//...
/**
* This method is called once the MVC bootstrapping is complete.
*/
public function onBootstrap(MvcEvent $event)
{
$application = $event->getApplication();
$serviceManager = $application->getServiceManager();
// The following line instantiates the SessionManager and automatically
// makes the SessionManager the 'default' one.
$sessionManager = $serviceManager->get(SessionManager::class);
}
}
Reference
EDIT: My 2nd assumption is that you use the global path for your sessions(eg /var/lib/php/sessions).
In Debian, there is a cron that may clear sessions according to your php.ini session settings(/etc/cron.d/php).
This cron uses your php.ini "gc_maxlifetime" and probably clears your sessions.
To find out where your sessions are saved, use session_save_path(). Check that directory for your sessions.
To overcome this, you should set "save_path" and this path should not be shared with others applications or scripts on your server(you do not want another script using the global gc settings or its own, deleting your sessions).
Add
'save_path' => '/path/to/app/data/sessions'
in your 'session_config' array.
I need to write a very specific authentication for my web application. There is API on the side which accepts login + password pair and returns the result (and, a token). I don't want to store any login information on the Yii2 side besides a login token i've got from API. And this must be the only way i auth my clients (so i don't use OAuth-like application).
What is the best practive to override "classic" code in Yii2? Just use filters and modify User model?
Example:
First, i recieve a token and save it somewhere for a session:
$token = GatewayAPI::login($user, $password);
Then, every internal request i do will look like this:
$result = GatewayAPI::addPosition($token, $data);
So, i don't have any database to work with, just cache and memory. Almost everything is handled on API side.
My task is to implement login check - if token is recieved from API - then it's considered as a success. And to store that token for use within current session (probably in memcache, it must not be opened to public).
As a matter of fact Yii2 does not require login/password anywhere.
You don't need to modify or extend User model if you mean \yii\web\User.
You need to create your own class implementing IdentityInterface and set this class as userIdentity in your config components->user->identityClass:
[
'components' => [
'user' => [
'class' => 'yii\web\User', // not necessary, this is by default
'identityClass' => 'my\namespace\User'
]
]
]
There are 5 methods in the interface and they are not about login/pass. This class of yours may store in your db everything you want.
For example you may copy any of popular user modules to your project, remove everything related to storing and searching by login/pass from that User model and add your API functionality - and it will work.
UPD.
Your added functionality will look like this:
$token = GatewayAPI::login($user, $password);
$user = \my\namespace\User::findOne(['token' => $token]);
Yii::$app->user->login($user);
I am developing an component that will take a GET variable from the URL, store it in an accessible variable and place it in a cookie. If the GET variable is not set it will load the cookie value into the accessible variable:
MyComponent extends ApplicationComponent {
protected $_var = null;
public init(){
// if isset($_GET['var']), set value to $_var and cookie;
// elseif cookie set value to $_var;
// else nothing;
}
public getVar(){
return $_var;
}
}
I always want one instance of the component and I want to run init on every frontend request (even if it is not explicitly referred to).
How do I hook this up? I am aware of the onBeginRequest, but doesn't this only allow static methods?
I could hack it in and set an app component in a separate method, but that doesn't sit well.. I'd like this to be portable across sites and set-up in my config if possible.
You can just add it to the preload section of your config:
protected/config/main.php
return array(
// some parameters
'preload' => array( 'myComponent' ),
'components' => array(
'myComponent' => array(
'class' => 'path.to.your.component.MyComponent'
),
),
);
This will automatically instantiate the component on each frontend request. Please refer to the corresponding section of The Definitive Guide to Yii.