Cookie read correctly in controllers but not in middleware - Laravel - laravel

I was trying to set a cookie to define a user-preferred language. I did that by having a link that leads to a helper controller :
/set-locale/{locale}
public function edit_locale($locale) {
$durata= 2628000; // "forever"
if (Cookie::has('locale')) {
Cookie::queue(Cookie::forget('locale')); // If locale cookie is already defined, delete it
}
Cookie::queue("locale", $locale, $durata); // Set the cookie to either "en", "fr" or "ar"
return redirect()->back();
}
I know this works correctly because if I do :
dd(Cookie::get('locale'));
It shows the correct locale chosen. So next step was to actually apply this chosen locale everywhere using a middleware, I named it "SetLocale" :
public function handle(Request $request, Closure $next)
{
if (Cookie::has('locale')) {
$locale = Cookie::get('locale'); // The cookie gotten here is all scrambled for some reason
} else {
// other logic for when cookie is not set (irrelevant for this question)
}
App::setLocale($locale);
return $next($request);
}
But if I execute
dd(Cookie::get('locale'));
here in the middleware, it reads the cookie all scrambled.
So my question is why is it doing that and how do I read the cookie correctly from here?

use this to get cookie from request :
\Crypt::decrypt(Cookie::get('locale'))
or use
\Crypt::decryptString(Cookie::get('locale'))

Okay, esmaill's answer didn't work for me (Got a "unserialize(): Error at offset 0 of 43 bytes" error) but it did help point me in the right direction to solve it.
All I did was add 'locale' to the $except attribute of the EncryptCookies middleware and reset the cookie and now it's read correctly.

Related

Laravel Localized Routes

I want to create laravel(5.6) localized routs for example : mysite.com/about - mysite.com/fr/sur
Route -> Web.php
foreach (config('app.locales') as $locale){ //config('app.locales') = ['en','fr']
$pref = ($locale != 'fr') ? ['prefix'=>$locale,'middleware'=>'LanguageCheck'] : ['middleware'=>'LanguageCheck'];
Route::group($pref,function (){
Route::get('/','HomeController#index');
Route::get('/'.__('urlabout').'','HomeController#about');
});
}
Middleware -> LanguageCheck
public function handle($request, Closure $next)
{
if($request->segment(1)){
session(['locale'=>$request->segment(1)]);
app()->setLocale($request->segment(1));
}else{
session(['locale'=>'fr']);
app()->setLocale('fr');
}
return $next($request);
}
This way working on mysite.com/about, mysite.com/fr/about but when i try access mysite.com/fr/sur I'm getting the error that the page can not be found.
Any suggestion for localized routes without any package.
Thanks in advice.
If you do not necessarily transfer the localization via url, then the best solution is to transfer the localization using Headers Accept-Language. You can get headers in the middleware and display content from the controller depending on what you came up with

Set Locale when using Auth::loginUsingId for phpunit

I have several languages in my Laravel 5.2 app. Each locale is stored in DB in th User Model. So, each time a user log, the locale must update.
Thing is in my Test, I use a lot Auth::loginUsingId, because I need to test function with differents user profiles.
So, I don't want to append to each of those calls with a App::setLocale(Auth::user->locale), nor extract it to a function.
Any Idea how should I do it???
What I did to address this problem is creating a middleware with
public function handle($request, Closure $next)
{
if ($user = Auth::user()) {
App::setLocale($user->locale);
}
return $next($request);
}
By handling all routes through this middleware, you can have the locale set automatically at each request.

Laravel middleware one time authorization for route groups

I am designing some part of system in Laravel 5. It is expected to behavior as described below.
User gets unique url. It could be provided in email, but that will not matter.
He clicks it, and gets logged in with some temporary token (for a session lifetime), that gives him possibility to access all the urls in allowed route group, ex. account/*, but if he wants to reach other restricted urls, then he is asked to authorize with his username/password.
If he is already authorized, token login makes no effect for him.
My question is about possibility to do something like that in Laravel out of box. I know there are some middleware services, but I'm not sure if default Guard behavior will not need to be changed to work as I expect.
I used to work with Symfony before, and there it is solved by firewalls by default, so maybe also in Laravel there is prebuilt solution?
you can absolutely doing this use laravel, here is an example code not tested,
public function handle($request, Closure $next)
{
if ($this->auth->guest()) {
if (preg_match('account', $request->route()->getName()) { //if url is under account, you can get route info from $request->route();
if (!session()->get($token)) { // if not have valid token
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->route('admin.login.index',['referrer'=>urlencode($request->url())]);
}
}
} else {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->route('admin.login.index',['referrer'=>urlencode($request->url())]);
}
}
}
return $next($request);
}
then from your route just add middleware auth to your group, this is a way to define you request in on middleware, laravel 5.2 support mutiple middleware.

Laravel Except Token Mismatch Error

My URL
http://laravel/tr/order/fp1/success
VerifyCsrfToken Except .
protected $except = [
'order/*'
];
But i have Token Mismatch Error.
Update:
I'm posting data to external webpage (Bank Server) And They are posting to my site.
As per the Op's comment it seems that the request is coming from external site where we can't generate csrf tokens from our application.
So, there is two possible solutions
Method 1 :
The request should get the csrf token from the application in prior request and then send the request with token
Method 2 :
You should attach a parameter with incoming request and have this inside the app\Http\Middleware\VerifyCsrfToken.php
$paramExist= $request->yourSecretParam;
#return parent::handle($request, $next);
if(isset($paramExist))
{
$yourSpecialkey ='a2$%$'; #This to check whether the param has the value that you set
if($paramExist==$yourSpecialKey)
{
return $next($request);
}
else
{
return parent::handle($request, $next);
}
}
else
{
return parent::handle($request, $next);
}
By having this you can check whether the request matches not with the parameter value that the external application has.
Hope, this helps you
I solve the problem.
In Except Property we have to write URI. But i didn't write language path.
protected $except = [
'tr/order/*'
];
If i write language path. It is working. But hardcoding language path is not logical.
And i override shouldPassThrough of BaseVerifier in Laravel.
protected $except = [
'order/*',
];
protected function shouldPassThrough($request)
{
foreach ($this->except as $except) {
if ($request->is(trim(Lang::locale().'/'.$except, '/'))) {
return true;
}
}
return false;
}
We add Lang::locale().'/'
Now we can use except property without writing language path.

Form validation ignores language when changed during run-time

I'm using CodeIgniter to build a multilanguage web application. I have English and other languages under /system/languages/ folder and I've created a model responsible for changing the working language at run-time.
By default CodeIgniter is working in French as defined in /application/config/config.php
$config['language'] = 'french';
Later, according to a URI segment the model changes the language accordingly, simplified example bellow:
class multilang extends CI_Model {
public function __construct() {
parent::__construct();
if ($this->uri->segment(1) == 'en') {
$this->config->set_item('language', 'english');
}
}
}
This model is the first model listed under the auto load settings in /application/config/autoload.php and I can confirm that the language is indeed changed dynamically by calling:
echo $this->config->item('language');
However the built in form validation library does not take into account the changed language, instead only shows error messages from the language hard coded in the settings file /application/config/config.php in this case French.
At first I assumed this was because the form validation was loaded before the multilang model. To make sure the model was loaded first, I modified the form validation constructor to load the model before anything else like this:
public function __construct($rules = array())
{
$this->CI =& get_instance();
$this->CI->load->model('multilang');
// normal code after....
}
This made sure the model loaded before the form validation. Unfortunately this wasn't enough and the form validation still ignores the language when changed during run-time. Anyone knows why this happens?
Thank you.
The problem was that I was doing AJAX requests that didn't took into account the URI segment that contained the language abbreviation, because the URI for AJAX requests didn't needed the language segment in the first place, so I totally forgot about it.
Therefore I used the session cookie to store the language. Changing the multilang constructor to:
class multilang extends CI_Model {
public function __construct() {
parent::__construct();
# store lang between session
$data = $this->session->all_userdata();
if (isset($data['language'])) {
$lang = $data['language'];
# if lang was changed between sessions
if ($this->uri->segment(1) == 'fr'){
$lang = 'french';
} else if ($this->uri->segment(1) == 'en'){
$lang = 'english';
}
# if lang was changed using one of the lang abbreviations
# overule session setting
if ($this->uri->segment(1) == 'en') {
$lang = 'english';
} else if ($this->uri->segment(1) == 'fr') {
$lang = 'french';
}
$this->config->set_item('language', $lang);
$this->session->set_userdata('language', $lang);
} else {
if ($this->uri->segment(1) == 'en') {
$this->config->set_item('language', 'english');
$this->session->set_userdata('language', 'english');
} else if ($this->uri->segment(1) == 'fr') {
$this->config->set_item('language', 'french');
$this->session->set_userdata('language', 'french');
}
}
}
}
Note: The change to the form_validation constructor wasn't required.
Answer provided for future reference, and to remind people of little things we miss. It was so obvious right! Well this might help the next one who forgets.
Closing question.

Resources