Optimize a method that checks url segments issue - laravel

I've been using a method in Laravel Middleware that checks for strings in any URL segment to block the IP if it matches the "blacklisted" strings.
In the beginning, I had just a few strings to check, but now, the list is growing, and when I tried to optimize it to use a blacklist array, I ended up in a complete mess in the code and in my mind.
I believe this can be done but can't figure out the best way to optimize this middleware. Below is a sample of the Middleware code with notes where I'm having trouble.
In the handle($request, Closure $next) method is calling the $this->inUrl() method for all the blacklisted strings.
I've tried to add a protected $blacklisted array, to be used in the $this->inUrl() but can't make it work.
Thank you in advance for any suggestions that would be much appreciated and welcome. I am also thinking of providing the code as a gist on GitHub when optimized.
namespace App\Http\Middleware;
/**
* Class VerifyBlacklistedRequests
*
* #package App\Http\Middleware
*/
class VerifyBlacklistedRequests
{
/**
* The array of blacklisted request string segments
*
* #access protected
* #var array|string[]
*/
protected array $blacklisted = [
'.env', '.ftpconfig', '.vscode', ',git', '.git/HEAD'
// etc...
];
/**
* Handle an incoming request.
*
* #access public
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
*
* #return mixed
*/
public function handle($request, Closure $next)
{
if($this->inUrl('.env')
|| $this->inUrl('.ftpconfig')
|| $this->inUrl('.vscode')
|| $this->inUrl('.git')
|| $this->inUrl('.git/HEAD')
// many more checks below the above ones
) {
// logic that blocks the IP goes here and working fine
}
return $next($request);
}
/**
* Check if the string is in any URL segment or at the one specified.
*
* #access protected
*
* #param string|mixed $value Segment value/content.
* #param integer $segment Segment position.
*
* #return bool
*/
protected function inUrl(string $value, $segment = -1)
{
if($segment !== -1 && request()->segment($segment) === $value) {
return true;
}
collect(request()->segments())->each(function ($segment) use ($value) {
if($segment === $value) {
return true;
}
});
return false;
}
}

After all the suggestions, kindly posted here, I ended up with a solution that uses some of the suggested methods.
The result ended up by reducing the pages' loading time by more than 1 second.
My final implementation:
Created a config file security.php which contains the blacklisted request strings, and a shortlist of whitelisted IPs.
The security.php config file
<?php
return [
/*
|--------------------------------------------------------------------------
| Whitelisted IPs configuration
|--------------------------------------------------------------------------
|
| These are the settings for the whitelisted IPs. The array contains
| the IPs that should not trigger the IP block.
|
*/
'whitelisted_ips' => [
// whitelisted IPs array
],
/*
|--------------------------------------------------------------------------
| Blacklisted request strings configuration
|--------------------------------------------------------------------------
|
| These are the settings for the blacklisted request strings. The array contains
| the strings that should trigger the IP to be blocked.
|
*/
'blacklisted_requests' => [
'.env',
'.ftpconfig',
'.vscode',
'.git',
'.git/HEAD',
'_profiler',
'__media__',
'administrator',
//...
];
];
Optimized the middleware removing the loops on the inUrl() method
The VerifyBlacklistedRequests middleware
<?php
namespace App\Http\Middleware;
use Closure;
/**
* Class VerifyHackingAttemptsRequests
*
* #property \Illuminate\Config\Repository|\Illuminate\Contracts\Foundation\Application|mixed white_listed_ips
* #property \Illuminate\Config\Repository|\Illuminate\Contracts\Foundation\Application|mixed blacklist
* #package App\Http\Middleware
*/
class VerifyHackingAttemptsRequests
{
/**
* #access protected
* #var \Illuminate\Config\Repository|\Illuminate\Contracts\Foundation\Application|mixed
*/
protected $blacklist;
/**
* #access protected
* #var \Illuminate\Config\Repository|\Illuminate\Contracts\Foundation\Application|mixed
*/
protected $white_listed_ips;
/**
* VerifyHackingAttemptsRequests constructor
*
* #access public
*/
public function __construct()
{
$this->blacklist = config('security.blacklisted_requests');
$this->white_listed_ips = config('security.whitelisted_ips');
}
/**
* Handle an incoming request.
*
* #access public
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
*
* #return mixed
* #since 2.8.1
*/
public function handle($request, Closure $next)
{
$exists = false;
foreach(request()->segments() as $segment) {
if(in_array($segment, $this->blacklist)) {
$exists = true;
}
}
if($exists) {
$this->blockIp($request)
}
return $next($request);
}
/**
* Method to save an IP in the Blocked IP database table
*
* #access protected
*
* #param \Illuminate\Http\Request $request
*
* #return \App\Models\BlockedIp
*/
protected function blockIp(Request $request, $notes = null)
{
// the logic to persist the data through the BlockedIp model
}
}
In summary, the inUrl() method was removed, removing all the loops and method calls and, as mentioned above, the pages' loading time was sliced by more than 50%.
Thanks to all for the suggested methods which contributed to helping me solve the problem.

I recommend you to create literal routes, so it is easier to maintain. Go to RouteServiceProvider and create a new reading similar to web or api, so any route that is in that new file, it will ban/block the IP.

I don't know if doing this will optimize the code but the code is much more readable I think.
namespace App\Http\Middleware;
/**
* Class VerifyBlacklistedRequests
*
* #package App\Http\Middleware
*/
class VerifyBlacklistedRequests
{
/**
* The array of blacklisted request string segments
*
* #access protected
* #var array|string[]
*/
protected array $blacklisted = [
'.env', '.ftpconfig', '.vscode', ',git', '.git/HEAD'
// etc...
];
/**
* Handle an incoming request.
*
* #access public
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
*
* #return mixed
*/
public function handle($request, Closure $next)
{
//loop over the list instead of that long conditions
foreach($this->blacklisted as $blacklistedItem) {
if($this->inUrl($blacklistedItem))
{
// logic that blocks the IP goes here and working fine
}
}
}
/**
* Check if the string is in any URL segment or at the one specified.
*
* #access protected
*
* #param string|mixed $value Segment value/content.
* #param integer $segment Segment position.
*
* #return bool
*/
protected function inUrl(string $value, $segment = -1)
{
if($segment !== -1 && request()->segment($segment) === $value) {
return true;
}
foreach(request()->segments() as $segment) {
if($segment === $value) {
return true;
}
}
return false;
}
}

I believe you can use DB and make the blacklist as indexed in DB,
Database would handle and search for this itself with its inner Engine.
protected function urlWasInBlackList($segment = -1){
$segmentStrings= $segment != -1 ? [request()->segment($segment)] : request()->segments();
return DB::table('blacklisted')->select('*')->whereIn('pattern',$segmantStrings)->exists()
}
and using some function like this instead of the inUrl(). it will check against the forbidden words Against the DB.
Update : Avoid DB
however DB handles this situation with its InnoDB engine quickly,
maybe you want to avoid DB, because of connection overhead or simply not dependent your project just because one functionality,
if you want to a avoid DB,
you have to check url with each black listed word with a loop and it would be O(n),
and if you multiply sections count, it would be O(n*m). The
Optimal way is to avoid loop, and make a hash table like what DB does.
so I go for hash_tables in php and found in the php array doc
that php associative arrays are hash map.
and the function array_key_exists() is looking into hash table for keys, you can see in the php source for the array_key_exists() codes which addressing the ht as hash map here:
array.c line #6071
zen_hash.h line #529
so I suggest to use something like this:
protected array $blacklisted = [
'.env' => null, '.ftpconfig' => null, '.vscode' => null, ',git' => null, '.git/HEAD' => null
];
for blacklist definitions.
and
$segmentStrings= $segment != -1 ? [request()->segment($segment)] : request()->segments();
foreach(segmentStrings as $segmentString){
return array_key_exists($segmentString, $blacklisted);
}

Related

Sanctum SPA Authentication: How to log out from other devices?

Is this feature included in the SPA Authentication? By reading the docs on Laravel Sanctum, it doesn't look like it, but at the same time, this is a common feature (used if user reset password or if you want only one login instance from a user) so I thought that it must be included...
After searching, I found this:
use Illuminate\Support\Facades\Auth;
Auth::logoutOtherDevices($currentPassword);
but you'll need to uncomment this middleware in the web before you can use this.
'web' => [
// ...
\Illuminate\Session\Middleware\AuthenticateSession::class,
// ...
],
However this only works on web and not on api. So I googled again how to have the same functionality with api and I found this youttube video. Here's what the guy did:
Create his own middleware (ex. AuthenticateSessionSPA.php).
Copy everything in AuthenticateSession and paste it in the new middleware. Change namespace and class name.
Create private variable with value of 'sanctum' (ex. private $driver
= 'sanctum')
Replace all $this->auth->getDefaultDriver() with $this->driver. So
the code will use the sanctum driver instead.
The file looks like this:
<?php
namespace App\Http\Middleware\Custom;
use Closure;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Contracts\Auth\Factory as AuthFactory;
class AuthenticateSessionSPA
{
private $driver = 'sanctum';
/**
* The authentication factory implementation.
*
* #var \Illuminate\Contracts\Auth\Factory
*/
protected $auth;
/**
* Create a new middleware instance.
*
* #param \Illuminate\Contracts\Auth\Factory $auth
* #return void
*/
public function __construct(AuthFactory $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (! $request->hasSession() || ! $request->user()) {
return $next($request);
}
if ($this->guard()->viaRemember()) {
$passwordHash = explode('|', $request->cookies->get($this->auth->getRecallerName()))[2] ?? null;
if (! $passwordHash || $passwordHash != $request->user()->getAuthPassword()) {
$this->logout($request);
}
}
if (! $request->session()->has('password_hash_'.$this->driver)) {
$this->storePasswordHashInSession($request);
}
if ($request->session()->get('password_hash_'.$this->driver) !== $request->user()->getAuthPassword()) {
$this->logout($request);
}
return tap($next($request), function () use ($request) {
if (! is_null($this->guard()->user())) {
$this->storePasswordHashInSession($request);
}
});
}
/**
* Store the user's current password hash in the session.
*
* #param \Illuminate\Http\Request $request
* #return void
*/
protected function storePasswordHashInSession($request)
{
if (! $request->user()) {
return;
}
$request->session()->put([
'password_hash_'.$this->driver => $request->user()->getAuthPassword(),
]);
}
/**
* Log the user out of the application.
*
* #param \Illuminate\Http\Request $request
* #return void
*
* #throws \Illuminate\Auth\AuthenticationException
*/
protected function logout($request)
{
$this->guard()->logoutCurrentDevice();
$request->session()->flush();
throw new AuthenticationException('Unauthenticated.', [$this->driver]);
}
/**
* Get the guard instance that should be used by the middleware.
*
* #return \Illuminate\Contracts\Auth\Factory|\Illuminate\Contracts\Auth\Guard
*/
protected function guard()
{
return $this->auth;
}
}
And this works wonderfully, I can now use Auth::logoutOtherDevices($currentPassword) in my api.
So my question is if this is safe? I'm just a jr. dev (6 months) and I'm not that confident in this solution since I found it from someone on the net and not from the docs. I'm wondering maybe the laravel devs didn't implement it because they have reasons like security?
What are your thoughts on this method? If you don't agree with this, how would you implement logging out from other devices in a project that has a SPA frontend and Laravel api?
Doesn't look like this is included in Laravel Sanctum SPA Authentication. So I just did my original answer found on the youtube video

Codeigniter 4 filters don't works

hi i want create my own authorization to study the new veri=sion of framework ...
this is my route :
$routes->add('/user/login', 'User::login',['filter'=>'usersFiltersNoAuth']);
$routes->add('/login', 'User::login',['filter'=>'usersFiltersNoAuth']);
$routes->add('/user/registration', 'User::registration',['filter'=>'usersFiltersNoAuth']);
$routes->add('/logout', 'User::logout');
$routes->add('/user/changeEmail', 'User::changeEmail',['filter'=>'usersFiltersAuth']);
$routes->add('/user/changePassword', 'User::changePassword',['filter'=>'usersFiltersAuth']);
And this is my 2 filter class:
class UsersFiltersNoAuth implements FilterInterface
{
/**
* Do whatever processing this filter needs to do.
* By default it should not return anything during
* normal execution. However, when an abnormal state
* is found, it should return an instance of
* CodeIgniter\HTTP\Response. If it does, script
* execution will end and that Response will be
* sent back to the client, allowing for error pages,
* redirects, etc.
*
* #param \CodeIgniter\HTTP\RequestInterface $request
* #param array|null $params
*
* #return mixed
*/
public function before(RequestInterface $request, $params = null)
{
// if no user is logged in then send them to the login form
if (isset($_SESSION['user_id']))
{
return redirect()->to('/user/index');
}
}
//--------------------------------------------------------------------
/**
* Allows After filters to inspect and modify the response
* object as needed. This method does not allow any way
* to stop execution of other after filters, short of
* throwing an Exception or Error.
*
* #param \CodeIgniter\HTTP\RequestInterface $request
* #param \CodeIgniter\HTTP\ResponseInterface $response
* #param array|null $arguments
*
* #return void
*/
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
{
}
//--------------------------------------------------------------------
} // End of UsersFiltersNoAuth Class.
class UsersFiltersAuth implements FilterInterface
{
/**
* Do whatever processing this filter needs to do.
* By default it should not return anything during
* normal execution. However, when an abnormal state
* is found, it should return an instance of
* CodeIgniter\HTTP\Response. If it does, script
* execution will end and that Response will be
* sent back to the client, allowing for error pages,
* redirects, etc.
*
* #param \CodeIgniter\HTTP\RequestInterface $request
* #param array|null $params
*
* #return mixed
*/
public function before(RequestInterface $request, $params = null)
{
// if no user is logged in then send them to the login form
if (!isset($_SESSION['user_id']))
{
session()->set('redirect_url', current_url());
return redirect()->to('/login');
}
}
//--------------------------------------------------------------------
/**
* Allows After filters to inspect and modify the response
* object as needed. This method does not allow any way
* to stop execution of other after filters, short of
* throwing an Exception or Error.
*
* #param \CodeIgniter\HTTP\RequestInterface $request
* #param \CodeIgniter\HTTP\ResponseInterface $response
* #param array|null $arguments
*
* #return void
*/
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
{
}
//--------------------------------------------------------------------
} // End of UsersFiltersAuth Class.
if i try to go to /user/chengeEmail or /user/changePassword when ($_SESSION['user_id] is set) i am redirect to /user/index why ?
Moreover there is a way to apply a filter to an entire controller ? except some method ?

Laravel Nova: TypeError: Cannot read property 'status' of undefined

A bunch of my Nova ressources stopped working. When trying to create them, I get the following error in the console:
Uncaught (in promise) TypeError: Cannot read property 'status' of undefined
at a.<anonymous> (app.js?id=7319bf5027431449796c:1)
at y (app.js?id=7319bf5027431449796c:1)
at Generator._invoke (app.js?id=7319bf5027431449796c:1)
at Generator.e.(anonymous function) [as next] (http://url/vendor/nova/app.js?id=7319bf5027431449796c:1:460720)
at o (app.js?id=7319bf5027431449796c:1)
at app.js?id=7319bf5027431449796c:1
at new Promise (<anonymous>)
at new t (app.js?id=7319bf5027431449796c:1)
at a.<anonymous> (app.js?id=7319bf5027431449796c:1)
at a.<anonymous> (app.js?id=7319bf5027431449796c:1)
Nothing shows up in the error log at all. Any pointers to where I should be looking? Only affects some ressources, others are working fine.
Edit: Here is one of the affected Nova ressources:
<?php
namespace App\Nova;
use Laravel\Nova\Fields\BelongsTo;
use Laravel\Nova\Fields\HasMany;
use Laravel\Nova\Fields\ID;
use Illuminate\Http\Request;
use Laravel\Nova\Fields\Text;
use Laravel\Nova\Http\Requests\NovaRequest;
use Naxon\NovaFieldSortable\Concerns\SortsIndexEntries;
use Naxon\NovaFieldSortable\Sortable;
class Unterprodukt extends Resource
{
use SortsIndexEntries;
public static $defaultSortField = 'order';
/**
* The model the resource corresponds to.
*
* #var string
*/
public static $model = 'App\Unterprodukt';
/**
* Get the displayble label of the resource.
*
* #return string
*/
public static function label()
{
return 'Unterprodukte';
}
/**
* Get the displayble singular label of the resource.
*
* #return string
*/
public static function singularLabel()
{
return 'Unterprodukt';
}
/**
* The logical group associated with the resource.
*
* #var string
*/
public static $group = 'Versicherung';
/**
* The single value that should be used to represent the resource when being displayed.
*
* #var string
*/
public static $title = 'name';
/**
* The columns that should be searched.
*
* #var array
*/
public static $search = [
'id',
'name',
];
/**
* Get the fields displayed by the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function fields(Request $request)
{
return [
ID::make()
->sortable()
->hideFromIndex(),
Text::make('Name', 'name')
->sortable(),
BelongsTo::make('Produkt', 'produkt', 'App\Nova\Produkt')
->sortable(),
Sortable::make('Reihenfolge', 'id')
->sortable(),
HasMany::make('Dokumente', 'dokumente', 'App\Nova\Dokument'),
];
}
/**
* Get the cards available for the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function cards(Request $request)
{
return [];
}
/**
* Get the filters available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function filters(Request $request)
{
return [];
}
/**
* Get the lenses available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function lenses(Request $request)
{
return [];
}
/**
* Get the actions available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function actions(Request $request)
{
return [];
}
}
The quick fix for this is this way
Sortable::make('Order', 'id')->exceptOnForms()
I had this problem too, and it was because I had an incoherence between nova fields and migrations fields.
Now, another possible way to fix it is:
php artisan nova:publish
php artisan view:clear
Check this issue for more details: https://github.com/laravel/nova-issues/issues/1735

How can i add TrimString Middleware in laravel 5.3?

Just came to know that Laravel 5.4 has an awesome feature TrimString, which removes the white spaces from any input. I want this middleware in my 5.3 project, any idea how to do that?
I just copied the middleware from GitHub repo of Laravel but it is not working.
Thanks
If you want to use this feature in Laravel 5.3.
Add these two classes into your App\Http\Middleware
https://github.com/laravel/framework/blob/5.4/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php
https://github.com/laravel/laravel/blob/master/app/Http/Middleware/TrimStrings.php
Updating it's namespace to App\Http\middleware.
Like:
TransformsRequest.php
namespace App\Http\Middleware;
use Closure;
use Symfony\Component\HttpFoundation\ParameterBag;
class TransformsRequest
{
/**
* The additional attributes passed to the middleware.
*
* #var array
*/
protected $attributes = [];
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next, ...$attributes)
{
$this->attributes = $attributes;
$this->clean($request);
return $next($request);
}
/**
* Clean the request's data.
*
* #param \Illuminate\Http\Request $request
* #return void
*/
protected function clean($request)
{
$this->cleanParameterBag($request->query);
$this->cleanParameterBag($request->request);
if ($request->isJson()) {
$this->cleanParameterBag($request->json());
}
}
/**
* Clean the data in the parameter bag.
*
* #param \Symfony\Component\HttpFoundation\ParameterBag $bag
* #return void
*/
protected function cleanParameterBag(ParameterBag $bag)
{
$bag->replace($this->cleanArray($bag->all()));
}
/**
* Clean the data in the given array.
*
* #param array $data
* #return array
*/
protected function cleanArray(array $data)
{
return collect($data)->map(function ($value, $key) {
return $this->cleanValue($key, $value);
})->all();
}
/**
* Clean the given value.
*
* #param string $key
* #param mixed $value
* #return mixed
*/
protected function cleanValue($key, $value)
{
if (is_array($value)) {
return $this->cleanArray($value);
}
return $this->transform($key, $value);
}
/**
* Transform the given value.
*
* #param string $key
* #param mixed $value
* #return mixed
*/
protected function transform($key, $value)
{
return $value;
}
}
TrimStrings.php
namespace App\Http\Middleware;
class TrimStrings extends TransformsRequest
{
/**
* The attributes that should not be trimmed.
*
* #var array
*/
protected $except = [
//
];
/**
* Transform the given value.
*
* #param string $key
* #param mixed $value
* #return mixed
*/
protected function transform($key, $value)
{
if (in_array($key, $this->except)) {
return $value;
}
return is_string($value) ? trim($value) : $value;
}
}
And add into your App\Http\Kernel.php
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\App\Http\Middleware\TransformsRequest::class,
\App\Http\Middleware\TrimStrings::class,
];
To use it just use:
dd(request('email'));
More on it:
https://laravel-news.com/laravel-5-4-middleware

Typo3 Extbase Set and Get values from Session

I am writing an extbase extension on typo3 v6.1
That extension suppose to do a bus ticket booking.
Here what my plan is, user will select date and number of seats and submit the form.
Here my plan to push the date and rate of the selected seat to session (Basket).
And while making payment, I wanted to get that values from session and after payment I need to clear that particular session.
So In short, How to Push and retrieve the values to and from the session in extbase.
Any suggestions ?
Thank you.
There are different ways. The simplest would be for writing in the session
$GLOBALS['TSFE']->fe_user->setKey("ses","key",$value)
and for reading values from the session
$GLOBALS["TSFE"]->fe_user->getKey("ses","key")
I'm using for this a service class.
<?php
class Tx_EXTNAME_Service_SessionHandler implements t3lib_Singleton {
private $prefixKey = 'tx_extname_';
/**
* Returns the object stored in the userĀ“s PHP session
* #return Object the stored object
*/
public function restoreFromSession($key) {
$sessionData = $GLOBALS['TSFE']->fe_user->getKey('ses', $this->prefixKey . $key);
return unserialize($sessionData);
}
/**
* Writes an object into the PHP session
* #param $object any serializable object to store into the session
* #return Tx_EXTNAME_Service_SessionHandler this
*/
public function writeToSession($object, $key) {
$sessionData = serialize($object);
$GLOBALS['TSFE']->fe_user->setKey('ses', $this->prefixKey . $key, $sessionData);
$GLOBALS['TSFE']->fe_user->storeSessionData();
return $this;
}
/**
* Cleans up the session: removes the stored object from the PHP session
* #return Tx_EXTNAME_Service_SessionHandler this
*/
public function cleanUpSession($key) {
$GLOBALS['TSFE']->fe_user->setKey('ses', $this->prefixKey . $key, NULL);
$GLOBALS['TSFE']->fe_user->storeSessionData();
return $this;
}
public function setPrefixKey($prefixKey) {
$this->prefixKey = $prefixKey;
}
}
?>
Inject this class into your controller
/**
*
* #var Tx_EXTNAME_Service_SessionHandler
*/
protected $sessionHandler;
/**
*
* #param Tx_EXTNAME_Service_SessionHandler $sessionHandler
*/
public function injectSessionHandler(Tx_EXTNAME_Service_SessionHandler $sessionHandler) {
$this->sessionHandler = $sessionHandler;
}
Now you can use this session handler like this.
// Write your object into session
$this->sessionHandler->writeToSession('KEY_FOR_THIS_PROCESS');
// Get your object from session
$this->sessionHandler->restoreFromSession('KEY_FOR_THIS_PROCESS');
// And after all maybe you will clean the session (delete)
$this->sessionHandler->cleanUpSession('KEY_FOR_THIS_PROCESS');
Rename Tx_EXTNAME and tx_extname with your extension name and pay attention to put the session handler class into the right directory (Classes -> Service -> SessionHandler.php).
You can store any data, not only objects.
HTH
From Typo3 v7 you can also copy the native session handler (\TYPO3\CMS\Form\Utility\SessionUtility) for forms and change it to your needs. The Class makes a different between normal and logged in users and it support multiple session data seperated by the sessionPrefix.
I did the same and generalized the class for a more common purpose. I only removed one method, change the variables name and added the method hasSessionKey(). Here is my complete example:
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
/**
* Class SessionUtility
*
* this is just a adapted version from \TYPO3\CMS\Form\Utility\SessionUtility,
* but more generalized without special behavior for form
*
*
*/
class SessionUtility {
/**
* Session data
*
* #var array
*/
protected $sessionData = array();
/**
* Prefix for the session
*
* #var string
*/
protected $sessionPrefix = '';
/**
* #var TypoScriptFrontendController
*/
protected $frontendController;
/**
* Constructor
*/
public function __construct()
{
$this->frontendController = $GLOBALS['TSFE'];
}
/**
* Init Session
*
* #param string $sessionPrefix
* #return void
*/
public function initSession($sessionPrefix = '')
{
$this->setSessionPrefix($sessionPrefix);
if ($this->frontendController->loginUser) {
$this->sessionData = $this->frontendController->fe_user->getKey('user', $this->sessionPrefix);
} else {
$this->sessionData = $this->frontendController->fe_user->getKey('ses', $this->sessionPrefix);
}
}
/**
* Stores current session
*
* #return void
*/
public function storeSession()
{
if ($this->frontendController->loginUser) {
$this->frontendController->fe_user->setKey('user', $this->sessionPrefix, $this->getSessionData());
} else {
$this->frontendController->fe_user->setKey('ses', $this->sessionPrefix, $this->getSessionData());
}
$this->frontendController->storeSessionData();
}
/**
* Destroy the session data for the form
*
* #return void
*/
public function destroySession()
{
if ($this->frontendController->loginUser) {
$this->frontendController->fe_user->setKey('user', $this->sessionPrefix, null);
} else {
$this->frontendController->fe_user->setKey('ses', $this->sessionPrefix, null);
}
$this->frontendController->storeSessionData();
}
/**
* Set the session Data by $key
*
* #param string $key
* #param string $value
* #return void
*/
public function setSessionData($key, $value)
{
$this->sessionData[$key] = $value;
$this->storeSession();
}
/**
* Retrieve a member of the $sessionData variable
*
* If no $key is passed, returns the entire $sessionData array
*
* #param string $key Parameter to search for
* #param mixed $default Default value to use if key not found
* #return mixed Returns NULL if key does not exist
*/
public function getSessionData($key = null, $default = null)
{
if ($key === null) {
return $this->sessionData;
}
return isset($this->sessionData[$key]) ? $this->sessionData[$key] : $default;
}
/**
* Set the s prefix
*
* #param string $sessionPrefix
*
*/
public function setSessionPrefix($sessionPrefix)
{
$this->sessionPrefix = $sessionPrefix;
}
/**
* #param string $key
*
* #return bool
*/
public function hasSessionKey($key) {
return isset($this->sessionData[$key]);
}
}
Don't forget to call the initSession first, every time you want use any method of this class

Resources