I'm using Laravel version 5.2.37. I have a simple HTML form in the blade view with the following line:
<input type="hidden" name="_token" id="token" value="{{ csrf_token() }}">
When I upload the code to client's shared hosting (Cpanel, PHP 5.5.36), without submitting the form, I hit the refresh and the csrf token value keeps changing.
However, on my local machine (MacOS/Apache2/5.6.16), the csrf token persists for at least 2 minutes (per config/session.php settings). Could it be the older 5.5.36 version of PHP that's causing this?
Try to define 'domain' in config/session.php to the right path. By default, it's set to null but on server, you should clear that.
Well, I finally figured it out. Stupid me made a custom helper with a function that looked something like this:
<?php
function doSomething($arg)
{
?><p>When this function is called,
display <b><?php echo $arg; ?> value.</b></p>
<?php
}
?>
You've probably seen a lot of functions written like this inside WordPress. Although it's not the artisan code, in most cases it will work fine, however Laravel will not tolerate this type of nonsense when dealing with helpers. So everything came back to normal after I wrote my function to return the string instead:
<?php
function doSomething($arg)
{
return '<p>When this function is invoked,
display <b>' . $arg . '</b> value.</p>';
}
?>
Moral of the story - don't write ugly code. Make sure your function returns and never directly echos/prints strings, especially with helper functions.
Related
I have a blade component for password fields and this is how I pass my information:
<x-store.password-field
label="Password"
name="password"
placeholder="••••••••"
error="Error message"
/>
As you can see, I have a variabile called error in order to display an error message if available. Now, I know how to display it in the page:
#error('password')
{{ $message }}
#enderror
Is there a way to add this logic directly in the component so it should be something like if $error then add error="$message" to the component? The example below will not work but it's just for illustration to show you what I mean:
<x-store.password-field
label="Password"
name="password"
placeholder="••••••••"
#error('password') error="{{ $message }}" #enderror
/>
Without going too much into details I wold like to describe who Laravel validation works. So this way I believe everything makes more sense.
So when Laravel validates a form based on the rules you have set, it knows what kind of data it is expecting and if there are invalid data provided an ValidationException will be thrown. This
Illuminate\Validation\ValidationException.php
class has all these methods and properties. But I will mention the errorBag property that holds the error messages. So the exception obj($e) have access to all the error messages. If you do not take the responsibility to handle this exception, Laravel will do the handling as well. There is an
Illuminate\Foundation\Exceptions\Handler.php
class and you can see how it is handled in details. But shortly this is where the exception is converted to http response, by default it redirects back, and there are two other method called withInput and withErrors. Both of these flash the data to the request session. So this way form input data and error messages are stored in the session and they can be retrieved anywhere from the application. As you may know retrieving data from the session can be performed using session() helper or Session facade or any other way. But for convenience Laravel provides helper method old() and in the other hand shares the $errors attribute to all the views. So old() is used to retrieve old from input data and $errors is an
Illuminate\Support\MessageBag.php
obj that provides some useful methods to retrieve validation errors. Well $errors is shared to all the views something we would do inside the AppServiceProvider like View::share('errors', session()->get('errors')); but instead of ServiceProvider Laravel has done it using middleware:
Illuminate\View\Middleware\ShareErrorsFromSession
. And that's because no matter if there are errors or not you don't have to test if $errors isSet etc.
Inside of any view file the $errors attribute is available as well as the old() method. So it's all set for you to use. Anyway how you decide to retrieve data from the session is is your choice, but since there are all these things provided as well as Laravel blade instead of:
<?php
if($errors){
?>
//do something
<?php
}
?>
// Blade offers:
#if($errors->has('password'))
//do something
#endif
// Or even more cleaner like:
#error('password')
//do something
#enderror
Since $errors or MessageBag instance is shared to all the views, I don't think you would ever want to pass it like a prop. And that because you can access it directly from the component.
However if you want to send it as a component prop you could do it. But don't forget the $errors is a MessageBag object. As well every single input field can have more than one error message for example name can contain both 'Min length is two characters' and 'Name should contain only letters'. For this reason $errors->get('name') will return an array. Since $errors is an MessageBag instance there are useful methods like $errors->first('name'); that will return the first element on the array and that is the error message, in this case 'Min length is two characters'. I want to mention that the error messages may not be identically to the one Laravel provides. But just to show the point. So in your case try something like this:
<x-store.password-field
label="Password"
name="password"
placeholder="••••••••"
:error="$errors->first('password')"
/>
Notice that when the data you want to provide is not just a simple string, you should add : in front of the attribute name. Otherwise the content it will be considered as a string.
What you can try is take a look inside your blade input component (components/input.blade.php). There you should be able to condition the variable $error with session.
As the title suggests, I am resurrecting an old Laravel project (from v5) and upgrading to v8.
In my blade template I referred to $request->q which would get the q=somevalue part of my url, in laravel 8 however this doesn't work.
I have tried a number of methods found in this SO post but none of them work.
Have you tried request() helper function with one of these
request('q')
request()->get('q')
request()->query('q')
I had this issue too but Still, it will works, when it in this way
Controller
in here this should have use Illuminate\Http\Request;
public function func1(Request $request){
$aid=$request->id;
}
Route
Route::get('/url_name/{id}',[
'as'=>'url_name',
'uses'=>'ControllerName#func1'
]);
Blade
<form id="form_1" action="{{'/url_name',$id)}}" method="POST" enctype="multipart/form-data">
OR
You can try with,
$request['q'];
Not entirely confident I have understood security in Laravel forms enough. For example, if a form contains
<input type="hidden" name="user_id">
then obviously a hacker could change the value before submitting an update.
While I have looked here at CSRF, I've not fully understood if this is enough protection?
E.g. Taking the above, if I go to a site and open a form to edit a record I'm permitted to view but not change, and maliciously alter the "user_id", is it enough that the form is protected with {{ csrf_field() }} or must I employ some further security such as Crypt::encrypt($id) to hide the user_id (held in a database) and Crypt::decrypt($id)?
Is it considered a bad practice to expose a row id (like a user id) in a client browser (even though everything is sent over https)?
Many Thanks
No, it's not enough to use just CSRF token in this case. You also need to use policies, guards, middleware to protect your app.
In this case, someone can alter the user_id if you read it from the form and use after that, so you need to use a policy like this one to protect data (this example is from the docs):
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
Also, when you need to use user ID, always use auth()->id() or auth()->user() if you need whole object. Never read user ID from the form.
The Laravel framework stores the value of this CSRF field like a session variable and matches it when you submit it.
When you submit the form Laravel checks that value from the session value stored. if there is a mismatch an error is thrown !
:)
CSRF token protect the site from cross-site requests, means an external user can't duplicate the form and send a post request. Laravel create a random session token which we place in the hidden field using csrf_field() or Session::token() function. Laravel checks the session with hidden field value from the form before processing the form.
Try removing the form action. It should work.
this ones a head ache! From my understanding of laravel's flash method for sessions, once it has been set then called, it will be destroyed...
Session::flash( 'key', $data );
somewhere down the line
{{ Session::get( 'key' ) }}
I am using this for form validation. Now when the form does not validate, the application displayed the error, if I amend the form and post again, the database updates, the details are displayed correctly, but the error appears again! This is the same for if I post the form that doesn't validate, it displays the error, but if I then click the navigation link for the same page, it displays again!
Anyone come across this?
regards
Luke
I had this problem once when I did a return view() / return View::Make when it should be a return redirect()->route() in my Controller#update method.
Since Laravel 5.1, you can use the now() method which will only affect the current request :
Session::now('key', 'message');
or
session()->now('key', 'message');
Out of the laravel docs:
The flash method stores an item in the session that will expire after the next request. It's useful for storing temporary data like status or error messages.
This means, it's available at the current and also the next request. It does not get flushed automatically if you access it. To do so, use Session::flush('key');.
Session Flash preserves the session data for 2 requests because it was meant to be used during redirection.
However, I've came across a use case where I do want to use flash for just 1 request in the next view and found an easy way to do it, which is to pull from the session rather than get it. The Session::pull() gets the session data and removes from the session.
#if (Session::has('message'))
<div class="alert alert-message">{{Session::pull('message'}}</div>
#endif
Hope this helps!
It's probably some other issue with your code, if you could share your code it would help us get a better insight into this issue.
You can use the below code snippet to Flash Error messages to your laravel blade template.
#if (Session::has('message'))
<div class="alert alert-success">{{Session::get('message')}}</div>
#endif
I once had similar issue because i used Session::reflash() in my controller.
Ensure you don't have Session::reflash() somewhere in your controller or anywhere in your application, as it flashes whole session... use example: Session::keep(array('username', 'email')); to reflashing only A Subset Of Flash Data
An easy way to flash a message once when you are creating a view (and not redirecting) is:
Session::flash($key, $value);
Session::push('flash.old', $key);
Refer here.
The flash method is meant for storing the data for the next request. Ideally after flashing the data to the session you should be redirecting to a new route. (This is what the accepted answer suggests.)
But if you are not redirecting you can call the forget method after displaying the session in your blade template:
{{ session()->flash('key') }}
#php
session()->forget('flash-info');
#endphp
I made a module named Gallery which works fine on my localhost with version 2.0.3, but when using version 2.1.0 on a remote site I can not submit a form and I get the error:
The action you have requested is not allowed.
Why is this?
I agree with #Jhourlad Estrella on fixing the problems instead of disabling a security feature, however I feel that the real problem is with the hidden input field that holds the token.
Instead of using plain HTML to create a form element use the the form_open() and form_close() helper functions. The reason why is because when you use the helper function it automatically inserts the csrf token as a hidden field in the form.
You could do this manually as well by adding the token as a hidden input field in the form
<input type="hidden" name="csrf_hash_name" value="your-hash-value-here">
Doing it this way will allow you to stay protected from CSRF attacks and fix the problem you are having.
Hope this helps someone else out there as this was driving me nuts the first time figuring this out.
It is a Codeigniter error related to the CSRF protection. You can cancel it in cms/config/config.php
On matters of programming, you don't go around problems, you fix it. What I mean to say is, this feature won't be here if it is unusable: 'coz it is and it works for me. You just have a problem on the implementation.
My answer: Remove all dashes, periods and any other non-alphanumeric characters from the values of following entries on application/config/config.php as seen below:
$config['sess_cookie_name'] = 'mycookiename'; //instead of "my_cookie_name"
$config['csrf_token_name'] = 'mycsrftoken'; //instead of "my.csrf.token"
$config['csrf_cookie_name'] = 'mycsrfcookie'; //instead of "my/csrf/cookie"
BTW, dashes sometimes work but I suggest using single words whenever possible when naming config values. Not unless you have the time and skills to study Codeigniter's core files related to what ever you are working on just to make sure it's safe to do so.
Anyways, I hope this help somebody out there even though my answer is more than a year late.
I have a form that was built outside of CI (in Joomla), but that I wanted to process with CI. My fix was to selectively disable csrf for specific referrers. I added this to config, directly after the default config options for csrf:
/* Set csrf off for specific referrers */
$csrf_off = array(
"http://yourdomain.com/your-form-url",
"http://yourdomain.com/some-other-url"
);
if (isset($_SERVER["HTTP_REFERER"])) {
if (in_array($_SERVER["HTTP_REFERER"],$csrf_off)) {
$config['csrf_protection'] = false;
}
}
This disables csrf protection for specific URLs in the $csrf_off array, but leaves it intact for all other requests.
I have found using the form helper functions
Example
<?php echo form_open('controller/function');?>
<?php echo form_input('username', 'Username');?>
<?php echo form_close();?>
Using the helper functions like above should stop the CSRF error message showing.
If I don't use echo form_input() if I place just normal input will trigger the CSRF error when reload.
<?php echo form_open('controller/function');?>
<input type="text" name="username" />
<?php echo form_close();?>
So I recommend using all form helper functions now.
It is an old question but this same problem did cost me so much time that I wanted to share what the problem was in my case. It may help someone.
I am using Codeigniter 3.0.6 and CommunityAuth 3 together with it and I was getting this error after a login.
It was confusing since the problem would sometimes happen and would not other times.
My 'base_url' in CI's config.php was set to something like 'www.mysite.com'
When you browse the site with 'mysite.com' (notice 'www' is not in the address) and you do a form submission that uses CI's 'base_url' setting, like CommunityAuth's login does, then CSRF check fails and you get 'The action you have requested is not allowed.' error.
This error is thrown by the function csrf_show_error() in system/core/Security.php when the CSRF token in $_COOKIE doesn't match your $_POST['csrf_token_name'].
Inside config.php, I had to ensure that $config['cookie_domain'] matched $config['base_url'], without the protocol (i.e. http(s)://).
Otherwise, the cookie wasn't being passed which meant the match couldn't be made.
Use the codeigniter form opener like this:
<php echo form_open(url,method,attributes);?>
see codeigniter form documentation for more.
This is probably a rare case, but I didn't see my issue since my server has many different domain names that are very similar. The problem was that I was landing on a domain that was completely wrong, but since "The action you have requested is not allowed." error takes precedence over " 404 Not Found Error" I couldn't see it. My problem was that I didn't change my base_url to the correct domain. So if none of the above solutions work for you, you might check your settings for $config['base_url'] in application/config.
For me the problem was that I was loading the view in the index, than I changed as follow and it worked:
public function index()
{
// Load Login Page
redirect('login/login_page','refresh');
}
public function login_page()
{
$data['title'] = 'Login Page';
$this->load->view('templates/header', $data);
$this->load->view('users/login_view', $data);
$this->load->view('templates/footer');
}
Im Using Codeigniter 3 same problem with
The action you have requested is not allowed.
Based on Isaac Pak's point, i changed my base_url to what i usally typed at the address bar. like this...
instead of putting
http://www.domain.org
i write it this way..
http://domain.org
since my base_url() is just..
$config['base_url'] = 'http://domain.org/';
the fix works for my site...