Laravel 419 on post requests after upgrade from 5.4 - laravel

Did an upgrade from 5.4 to 5.7, after that every ajax post request is 419 with:
{message: "", exception: "Symfony\Component\HttpKernel\Exception\HttpException",…}
exception: "Symfony\Component\HttpKernel\Exception\HttpException"
file: "pathto/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php"
line: 204
message: ""
trace: [{,…}, {file: "pathto/public_html/app/Exceptions/Handler.php", line: 47, function: "render",…},…]
0: {,…}
class: "Illuminate\Foundation\Exceptions\Handler"
file: "pathto/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php"
function: "prepareException"
line: 176
type: "->"
Followed the upgrade instructions which especially mentioned about Cookie Serialization:
protected static $serialize = true;
Cleared cache, checked the file permissions are ok. Went down to 5.6, then to 5.5 laravel versions but no help. Changed the cookie name, tried incognito. Tried to even bypass all:
protected $except = [
"*"
];
But no change. What on earth could go wrong here?
Edit:
Ajax call:
var $_token = $('#token').val();
var url = '/delete';
$.ajax({
headers: {'X-XSRF-TOKEN': $_token},
type: "POST",
url: url,
data: ({data: data}), // set up earlier
success: function (data) {
}
});
Controller:
public function delete(Request $request)
{
$id = $request->input('data);
Post::where('id', $id)->delete();
}
Also tried with $('meta[name="csrf-token"]').attr('content')
This gave me:
payload is invalid
id token is taken from:
<?php
$encrypter = app('Illuminate\Encryption\Encrypter');
$encrypted_token = $encrypter->encrypt(csrf_token());
?>
<input id="token" type="hidden" value="{{$encrypted_token}}">

just add
{{ csrf_field() }}
to your blade template
something like
<form method="POST" action="/projects">
{{ csrf_field() }}
<div class="form-group">
<label for="title">Title</label>
<input id="title" class="form-control" type="text" name="title" placeholder="Project Title" required />
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">
Create Project
</button>
</div>
</form>

Hard to tell without your controller and the actual ajax call... but I've had similar problems with this 419 error. There were two causes for me:
1) Failed token verification. To check, add this to your ajax call:
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
Though... your having tried to except everything should have allowed this through (assuming you had that line in the right place).
EDIT: If you are passing your X-XSRF-TOKEN from JavaScript, decode it using decodeURIComponent()
2) It's possible that your controller is trying to render the view without all the information it needs. Any chance you need to send a variable through to the view in the ajax controller function and it is missing? I realize this worked before, but there were some big changes to 5.5 (including the way CSRF was handled as above).
3) Just a general error that I've had, but it might be possible that the data is not transferring in the same way as it did with 5.4. Just check to see if the way the data is coming in to the controller is not error-ing out. IE do a dump from the controller before it gets back to the view and see what your browser reports is transferring

Old topic but I just got back to it now and figured it out.
Reason was that I was passing: XSRF-Token in older Laravel instead of CSRF-Token, the never versions don't seem to work with XSRF anymore. Switched to CSRF and that fixed it.

Related

Why is record not deleting and response is 303 in Laravel 9, Inertia and Vue3?

I have following code in route web.php file.
Route::resource('dailyrevenue', DailyRevenueController::class)->middleware('auth');
Then in my DailyRevenueController.php
public function destroy(DailyRevenue $revenue)
{
$revenue->delete();
return redirect()->back();
}
And in my vue3 code:
const submit = function (id) {
const check = confirm("Are you sure to delete ?")
if (check) {
Inertia.delete(route('dailyrevenue.destroy',id), {
id: id,
method: 'delete',
forceFormData: true
})
}
}
Finally in the template:
<template #cell(actions)="{item: tax}">
<form method="delete" #submit.prevent="submit(tax.id)">
<input type="hidden" name="_method" value="delete"/>
<button type="submit">Delete</button>
</form>
</template>
Now request reaches to the method. But nothing is deleted. The request sent is DELETE request. Instead of 302 response it sends back 303 (See others).
Community help is appreciated.
Thanks.
I found the solution. The reson behind it was the variable name. In url endpoint the variable name was decleared as dailyrevenue and in the method as $revenue.
You can find your url variable by typing php artisan route:list.
I found that the url variable name must match with variable name in method.
Hope this helps others too.

I have an error with logout in the stack laravel 8 / jetstream / inertiajs

I'm trying to set a logout route.
I found a lot of blade syntax (like that) but none with vuejs. So I tried to replicate the result of the blade syntax by inserting an input with the csrf token in value and the name set to "_token". (the csrf variable contains the string located in the XSRF-TOKEN cookie).
When I post, I have this error in console:
POST http: // localhost: 3000 / logout 419 (unknown status)
Can you tell me where my mistake is? How can I logout properly and be redirected to the page of my choice?
<form method="POST" :action="$route('logout')">
<input type="hidden" name="_token" :value="csrf">
<button type="submit">Logout</button>
</form>
I think there is a better way to do it. I will share an idea with you.
About the token
Share the token by the back-end to the front-end, as you did, isn't necessary.
About the code in the Vue Component
The logout wasn't working because of your form.
Your form POST
<form method="POST" :action="$route('logout')">
<input type="hidden" name="_token" :value="csrf">
<button type="submit">Logout</button>
</form>
The best way of form POST
<form #submit.prevent="logout()">
<button as="button" type="submit">
Logout
</button>
</form>
As you can see, when you submit the form it will call a method of the vue component called "logout". The method:
export default{
// Some code...
methods:{
logout() {
this.$inertia.post(route('logout'));
},
}
}
Doing the logout process in this way, all the logical logout will be taken care of by the server-side. You will not have to worry about the token.
I hope it be useful for you. I also thank you because I just found this solution because of your answer.
I found the solution.
My error was on the recovery of the csrf token which was not good.
I would retrieve the long string contained in the XSRF-TOKEN cookie, while I had to receive the token from my backend. These 2 strings are strictly different, for some reason that I don't know yet.
I just needed to send the csrf token to my front-end with the csrf_token() method
return Inertia::render('Dashboard', [
'publications' => $publications,
'users' => $users,
'csrf_token' => csrf_token()
]);
I didn't need to do the form manually either
Finally, I was able to grab the token as a prop and include it in my post request like this:
this.$inertia.post('/logout', {
_token: this.$props.csrf_token
})
This link helped me

my delete query is not working in laravel

I am trying delete database data in Laravel. but this is not working my way.
my view page is
{{url('/deleteReview/'.$Review->id)}}
my web is
Route::post('/deleteReview/{id}','adminController#deleteReview');
my controller delete function is
public function deleteReview($id){
$deleteReview = Review::find($id);
$deleteReview->delete();
return redirect('/manageReview');
}
Are you trying to delete the review by opening the page /deleteReview/<id> in your browser? If so, this would be a GET request, so change the route to a get route:
Route::get('/deleteReview/{id}','adminController#deleteReview');
Please note as per the comments that a GET request should never change data server side. If data is changed using a GET request then there is a risk that spiders or browser prefetch will delete the data.
The correct way to do this in Laravel is using a POST request and use Form Method Spoofing to simulate a DELETE request. Your route entry would then look like this:
Route::delete('/deleteReview/{id}','adminController#deleteReview');
And your form would look like this:
<form action="/deleteReview/{{ $Review->id }}" method="POST">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>
At Controller you should first set Validation for ID that you have to Delete. Create your own customize request handler such as DeleteRequest.
Once you get ID at Controller then used this code
public function deleteReview(DeleteRequest $id){
DB::table('reviews')->where('id', $id)->delete();
return redirect('/manageReview');
}
I hope it will work.

Form submission fails via Ajax due to parsing error, but passes during normal POST

I'm quite puzzled as to why the ajax form submission isn't working. Can you guys have a look and tell me if you can spot something wrong.
WORKING
<form id="advancedSearchForm" name="advancedSearchForm" action="" method="POST">
....
<input type="submit" value="Search">
It's Ajax equivalent for form submission isn't working.
<form id="advancedSearchForm" name="advancedSearchForm" action="" method="POST" onsubmit="return sumbitForm();">
where I have defined the function as
function submitForm()
{
$.ajax({type: 'POST', url: '', data: $('#advancedSearchForm').serialize(),dateType:'script',error: alert ("Error in ajax submission"),success: alert ("success")});
}
Update, I just added the alert error function, which does pop up. But so does the success pop up
In the second one, I am getting a Parsing JSON request failed. In the body, when DOM is loaded, I have a $.ajaxSetup({error:function(x,e){......if(e == "parsererror") errortext = "Parsing JSON request failed".
The controller seems to be sending and receiving the correct data in both instances from the log. If you have any ideas, pitch in.

Submit form on select change via AJAX

Let's say I have this form :
<form action="Change-status.php" method="post">
<select class="changeStatus" name="changeStatus">
<option value="0">Starting</option>
<option value="1">Ongoing</option>
<option value="2">Over</option>
</select>
<input class="projectId" type="hidden" name="projectId" value="<?php echo $data['id'];?>"/>
</form>
I am currently using this script to submit the form, but it implies refreshing :
$('select').change(function ()
{
$(this).closest('form').submit();
});
What I want to do is to send the form on select change without refreshing the page. I know I have to use AJAX to do so but I couldn't exactly figure out how to implement it.
Could you orient me on how to do this?
Thanks for your help.
EDIT :
After taking comments into consideration, I ended up with the following code :
Html :
<form action="" method="post">
<select class="changeStatus" name="changeStatus">
<option value="0">Starting</option>
<option value="1">Ongoing</option>
<option value="2">Over</option>
</select>
<input class="projectId" type="hidden" name="projectId" value="<?php echo $data['id'];?>"/>
</form>
JS :
$(document).ready(function() {
$('select.changeStatus').change(function(){
$.ajax({
type: 'POST',
url: 'Change-status.php',
data: {selectFieldValue: $('select.changeStatus').val(), projectId: $('input[name$="projectId"]').val()},
dataType: 'html'
});
});
});
PHP :
<?php
include('../Include/Connect.php');
$changeStatus=$_POST['selectFieldValue'];
$id=$_POST['projectId'];
$sql='UPDATE project SET progress="'.$changeStatus.'" WHERE id="'.$id.'"';
mysql_query($sql) or die("Erreur: ".mysql_error());
?>
Getting cross browser onchange events and AJAX requests working isn't trivial. I'm recommend you use a javascript framework of some kind, which abstracts away all of the cross browser issues so you don't have to worry about them.
Try a js framework
Jquery is just one such framework which has methods such as .change() which attaches a handler to the change event for elements like <select> and .get() which performs a GET request.
Here's a little bit of code to get you started:-
// The $ is the shorthand for a jquery function, you can then use jquery
// selectors which are essentially the same as css selectors, so here
// we select your select field and then bind a function to
// it's change event handler
$('select.changeStatus').change(function(){
// You can access the value of your select field using the .val() method
alert('Select field value has changed to' + $('select.changeStatus').val());
// You can perform an ajax request using the .ajax() method
$.ajax({
type: 'GET',
url: 'changeStatus.php', // This is the url that will be requested
// This is an object of values that will be passed as GET variables and
// available inside changeStatus.php as $_GET['selectFieldValue'] etc...
data: {selectFieldValue: $('select.changeStatus').val()},
// This is what to do once a successful request has been completed - if
// you want to do nothing then simply don't include it. But I suggest you
// add something so that your use knows the db has been updated
success: function(html){ Do something with the response },
dataType: 'html'
});
});
Some references that will be better than my explanations
Please note for this code to work you will need to include the jquery library on you page with a <script> tag.
See here for a quick start guide on using jquery
And here for a beginners tutorial on how to use jquery's ajax() method

Resources