Laravel ajax 422 Unprocessable Entity even when token is matching - ajax

I'm getting 422 Unprocessable Entity error even when I'm submitting my form via Ajax.
My javascript file
$.ajaxSetup({
headers: {
'X-XSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$('.keywords-plan-form').submit(function(event) {
event.preventDefault();
$.ajax({
url: '/laravel/public/keywordsplans',
type: 'POST',
data: $(this).serialize(),
success: function(data){
alert(data);
// success logic
},
error: function(data){
// Error...
var errors = $.parseJSON(data.responseText);
console.log(errors);
$.each(errors, function(index, value) {
});
}
});
});
as you can see I added X-XSRF-TOKEN****strong text to ajax header.
This is my '' tag
<meta name="csrf-token" content="{{ csrf_token() }}">
my Form Data in chrome debuger
_token:5j6DGhhTytbIRB1GrW9Wml9XrOxmKjgE9RiGa4Gf
date:
keyword[0]:Lorem ipsum
keyword[1]:Is dolor amet
keyword[2]:plumber tampa
Request Headers
X-XSRF-TOKEN:5j6DGhhTytbIRB1GrW9Wml9XrOxmKjgE9RiGa4Gf
.....
am I doing something wrong or forgetting something?

I don't think that csrf token is the issue here. If it were you would get TokenMissmatchException and not Unprocessable Entity.
Do you happen to have a request validator in your Controller like this?
$validator = Validator::make($request->all(), [
'username' => 'required|max:30|min:6|unique:users',
'email' => 'required|email|max:50|unique:users',
'password' => 'required|confirmed|min:6',
]);
If so maybe you can do something like this:
if ($validator->fails()) {
if($request->ajax())
{
return response()->json(array(
'success' => false,
'message' => 'There are incorect values in the form!',
'errors' => $validator->getMessageBag()->toArray()
), 422);
}
$this->throwValidationException(
$request, $validator
);
}
After that you can catch validation errors in your ajax error handler like this:
$('.keywords-plan-form').submit(function(event) {
event.preventDefault();
$.ajax({
url: '/laravel/public/keywordsplans',
type: 'POST',
data: $(this).serialize(),
success: function(data){
alert(data);
// success logic
},
error: function(jqXhr, json, errorThrown){// this are default for ajax errors
var errors = jqXhr.responseJSON;
var errorsHtml = '';
$.each(errors['errors'], function (index, value) {
errorsHtml += '<ul class="list-group"><li class="list-group-item alert alert-danger">' + value + '</li></ul>';
});
//I use SweetAlert2 for this
swal({
title: "Error " + jqXhr.status + ': ' + errorThrown,// this will output "Error 422: Unprocessable Entity"
html: errorsHtml,
width: 'auto',
confirmButtonText: 'Try again',
cancelButtonText: 'Cancel',
confirmButtonClass: 'btn',
cancelButtonClass: 'cancel-class',
showCancelButton: true,
closeOnConfirm: true,
closeOnCancel: true,
type: 'error'
}, function(isConfirm) {
if (isConfirm) {
$('#openModal').click();//this is when the form is in a modal
}
});
}
});
});
And see the messages in the
modal message

Maybe someone will come in handy.
422 Unprocessable Entity
is default error by validator laravel
vendor/laravel/framework/src/Illuminate/Validation/Validator.php
If fails validate params, then throught Exception ValidationException
vendor/laravel/framework/src/Illuminate/Validation/ValidationException.php
where default status = 422
And therethore all your ajax responses with non validate forms will be with status = 422

I have solved this issue :
public function register(\Illuminate\Http\Request $request) {
if ($this->validator($request->all())->fails()) {
$errors = $this->validator($request->all())->errors()->getMessages();
$clientErrors = array();
foreach ($errors as $key => $value) {
$clientErrors[$key] = $value[0];
}
$response = array(
'status' => 'error',
'response_code' => 201,
'errors' => $clientErrors
);
} else {
$this->validator($request->all())->validate();
$user = $this->create($request->all());
$response = array(
'status' => 'success',
'response_code' => 200
);
}
echo json_encode($response);
}

Whoever is still looking for the answer, if you are using Lumen make sure the Request object is a type of Illuminate\Http\Request and not the default one from Lumen.
```function create(Request $request){

Related

Internal server error 500 when sending ajax post request in laravel 9

I am using laravel 9. I am trying to make a ajax crud operation using alax. It respond well in get request. but when I sending the post request it shows:
http://127.0.0.1:8000/add/teacher 500 (Internal Server Error) in the console. I used meta in the head and ajax csrf header according to documentation. Still showing error. here my ajax code example bellow:
<script>
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$(document).ready(function() {
$(".add_teacher").on('click', function(event) {
event.preventDefault();
var name = $("#name").val();
var email = $("#email").val();
var position = $("#position").val();
var phone = $("#phone").val();
var password = $("#password").val();
$.ajax({
method: "post",
url: "{{route('store')}}",
data: {
name: name,
email: email,
position: position,
phone: phone,
password: password
},
success: function(res) {
if (res.status == 'success') {
$("#exampleModal").modal('hide');
$("#modalform")[0].reset();
$(".table").load(location.href + ' .table');
}
},
error: function(err) {
let error = err.responseJSON;
$.each(error.errors, function(index, value) {
$(".errorMessage").append('<span class="text-
danger">' + value +'</span><br>');
});
}
});
});
});
</script>
Here is my route:
Route::post('/add/teacher', [TeacherController::class,'store'])->name('store');
and my controller code is:
public function store(Request $request)
{
$request->validate(
[
"name" => "required",
"email" => "requied|unique:teachers",
"position" => "requied",
"phone" => "requied|unique:tachers",
"password" => "requied",
],
[
"name.required" => "Name is required",
"email.required" => "Email is required",
"email.unique" => "Email already exists",
"position.required" => "Postion is required",
"phone.required" => "Phone is required",
"phone.unique" => "Phone already exixts",
"password.required" => "password is required",
]
);
$teacher = new Teacher();
$teacher->name = $request->name;
$teacher->email = $request->email;
$teacher->position = $request->position;
$teacher->phone = $request->phone;
$teacher->password = $request->password;
$teacher->save();
return response()->json([
'status' => 'success',
]);
}
Now I need an exact solution to go farther. Thank you.

Codeigniter 3 multiple forms with ajax and csrf tokens working on one form only

I have admin page with multiple settings, each setting have different form in different tab.
I am using ajax and to save data, and i didn't had any problems so far with csrf token when i had only one form on a page, or when i disable csrf token.
On each ajax request new token is generated in controller and sent back to ajax which is updating hidden field with name="csrf_token" but with different id's.
After first form is submitted all is good, but when i try to submit other form csrf token doesn't work anymore i am getting message "The action you have requested is not allowed." with page 403 in console output even after i reload page and try to submit other form that didn't worked.
Is there way to have multiple forms with csrf protection on same page and how to handle that ?
Here is code examples
Forms with ajax
<form id="upload-icon" method="POST" enctype="multipart/form-data">
<input type="hidden" name="csrf_token" id="csrf_token_1" value="<?php echo $this->security->get_csrf_hash(); ?>">
<input type="file" id="favicon_image" name="favicon_image" accept=".ico">
<button type="button" id="upload-icon-btn">Upload</button>
</form>
<form id="update-settings" method="POST">
<input type="hidden" name="csrf_token" id="csrf_token_2" value="<?php echo $this->security->get_csrf_hash(); ?>">
<input type="text" name="settings_one">
<input type="text" name="settings_two">
<input type="text" name="settings_three">
<button type="button" id="update-settings-btn">Update settings</button>
</form>
<script>
$(document).ready(function() {
var csrf_token = '';
// upload favicon form
$('#upload-favicon-form-btn').on('click', function(e) {
e.preventDefault();
var fd = new FormData();
var files = $('#favicon_image')[0].files[0];
fd.append('favicon_image', files);
var favicon = $('#favicon_image').val();
if (favicon == '') {
loadModal('Warning', 'Please select <strong>favicon.ico</strong> icon file.');
} else {
$.ajax({
type: 'POST',
url: '<?php echo base_url('admin/settings/upload_ico'); ?>',
data: fd,
contentType: false,
cache: false,
processData: false,
dataType: 'json',
success: function(response) {
csrf_token = response.csrf_token;
$('#csrf_token_1').val(csrf_token);
// messages output
},
error: function() {
// error message output
}
});
}
});
// update settings form
$('#update-settings-btn').on('click', function(e) {
e.preventDefault();
$.ajax({
type: 'POST',
url: '<?php echo base_url('admin/settings/update_settings'); ?>',
data: $('#update-settings').serialize(),
dataType: 'json',
success: function(response) {
csrf_token = response.csrf_token;
$('#csrf_token_2').val(csrf_token);
// messages output
},
error: function() {
// error message output
}
});
});
});
</script>
Settings controller
public function update_settings()
{
$csrf_token = $this->security->get_csrf_hash();
$this->form_validation->set_rules('settings_one', 'Setting one', 'trim|required|xss_clean');
$this->form_validation->set_rules('settings_two', 'Setting two', 'trim|required|xss_clean');
$this->form_validation->set_rules('settings_three', 'Setting three', 'trim|required|xss_clean');
if ($this->form_validation->run()) {
if ($this->Settings_model->UpdateSettings($this->input->post('settings_one'), $this->input->post('settings_two'), $this->input->post('settings_three'))) {
$data = array(
'success' => true,
'message' => 'Settings updated.',
'csrf_token' => $csrf_token
);
} else {
$data = array(
'error' => true,
'message' => 'Settings was not updated.',
'csrf_token' => $csrf_token
);
}
} else {
$data = array(
'error' => true,
'settings_one_error' => form_error('settings_one'),
'settings_two_error' => form_error('settings_two'),
'settings_three_error' => form_error('settings_three'),
'csrf_token' => $csrf_token
);
}
echo json_encode($data);
}
public function upload_ico()
{
$csrf_token = $this->security->get_csrf_hash();
$favicon_upload_path = './upload/';
if (isset($_FILES['favicon_image']['name'])) {
$config['upload_path'] = $favicon_upload_path;
$config['allowed_types'] = 'ico';
$this->load->library('upload', $config);
if (!$this->upload->do_upload('favicon_image')) {
$data = array(
'error' => true,
'message' => $this->upload->display_errors(),
'csrf_token' => $csrf_token
);
} else {
$data = array(
'success' => true,
'message' => 'Favicon uploaded.',
'csrf_token' => $csrf_token
);
}
} else {
$data = array(
'error' => true,
'message' => 'No file selected.',
'csrf_token' => $csrf_token
);
}
echo json_encode($data);
}
Config.php
$config['csrf_protection'] = TRUE;
$config['csrf_token_name'] = 'csrf_token';
$config['csrf_cookie_name'] = 'csrf_cookie_name';
$config['csrf_expire'] = 7200;
$config['csrf_regenerate'] = TRUE;
$config['csrf_exclude_uris'] = array(
'admin/settings'
);
I found issue.
I forgot to send token on first form, those 2 lines fix it
var token = $('#csrf_token_1').val(); // read token value from input
fd.append('csrf_token', token);
Then in script
<script>
$(document).ready(function() {
var csrf_token = '';
// upload favicon form
$('#upload-favicon-form-btn').on('click', function(e) {
e.preventDefault();
var fd = new FormData();
var files = $('#favicon_image')[0].files[0];
fd.append('favicon_image', files);
// fix for token that should be sent to controller over ajax
var token = $('#csrf_token_1').val(); // read token value from input
fd.append('csrf_token', token); // append token value to data that need to be send to controller
and on each success in ajax it should update all forms id's with token returned from controller because i use $config['csrf_regenerate'] = TRUE; that is make new token on each request, so i made js function that updates token for all id's on all forms
// function that updates token on all forms
function updateToken(token) {
$('#csrf_token_1, #csrf_token_2').val(token);
}
function in usage
success: function(response) {
csrf_token = response.csrf_token;
updateToken(csrf_token);
}
Maybe it's not best solution but works for me. If anyone have better one please feel free to post it.

Why jquery ajax post request get error in yii2?

js:
$.ajax({
url: '/site/updateuserdata',
method: 'POST',
//async: true,
//cache:false,
data: {
'type': 'sort'
//val: val
//csrfParam: csrfToken
},
dataType: 'text',
error: function(jqXHR, textStatus, errorThrown) {
alert('error by ajax');
},
success: function(data, status, jqXHR) {
alert('success by ajax');
}
});
Controller:
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'actions' => ['updateuserdata'],
'allow' => true,
// 'roles' => ['*'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'updateuserdata' => ['post'],
],
],
];
}
public function actionUpdateuserdata()
{
/*if (Yii::$app->request->isAjax) {
$message = 'Ваше сообщение успешно отправлено';
Yii::$app->response->format = Response::FORMAT_JSON;
$response = [
'success' => true,
'message' => $message
];
return $response;
}*/
$f = fopen('testajax.txt','a+');
fwrite($f, 'ajax: '.(isset($_POST['type'])?$_POST['type']:'error'));
fclose($f);
if(isset($_POST['type']))
return $_POST['type'];
else return 'error1';
// return Yii::$app->getResponse()->redirect(Yii::$app->request->referrer, 302, FALSE);
}
yii.js:
function initRedirectHandler() {
// handle AJAX redirection
$(document).ajaxComplete(function (event, xhr) {
var url = xhr && xhr.getResponseHeader('X-Redirect');
alert(url); //my code
if (url) {
window.location.assign(url);
}
});
}
I see first alert(ajax error) "error by ajax" and then alert(yii.js) "..../site/updateuserdata...", why ajax error? File testajax.txt not create.
I tried comment 'updateuserdata' => ['post'], and get error too.
Updated.
Also, tried:
public function beforeAction($action)
{
if ($action->id == 'updateuserdata') {
$this->enableCsrfValidation = false;
}
return parent::beforeAction($action);
}
and uncomment csrf parameters in ajax.
And 'error' return status 302(jqXHR.status).
dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
I find problem, it's stupid problem:
url: '/mag/updateuserdata/',
i have in 'urlManager':
'suffix' => '/',
i think this added for all, but not.....
Cause you commented
//csrfParam: csrfToken
from your ajax js file you have 400 http status code in your ajax.
So you can solve it in two way:
one: disable csrf validation by adding
$this->enableCsrfValidation = false;
in your actionUpdateuserdata method.
two: add csrf token and csrf param to your ajax.
print this code in your js, where you commented it.
Yii::$app->request->csrfParam . ':' . Yii::$app->request->csrfToken
then your request sent successfully and if you have other error you must check your code.

Laravel - How to call a controller function via AJAX (jQuery)

I have a number of working controller functions, however, for usability I want to switch some of them over to be called via AJAX.
Here is my jQuery code:
$.ajax({
method: 'GET',
url: $(this).data('url'),
data: {},
success: function( response ){
console.log( response );
},
error: function( e ) {
console.log(e);
}
});
And here is my controller function:
public function add( $user_id, $project_id )
{
$project = Project::findOrFail( $project_id );
if( empty( $project ) ) {
return view( 'home' )->with('message', 'Sorry, user not found');
}
if ( $project->user_id != $user_id ) {
$scrapbook = Scrapbook::firstOrNew(['user_id' => $user_id]);
$scrapbook->save();
$scrapbook->projects()->attach($project_id);
return true;
} else {
return false;
}
}
As it stands, the controller function actually does what it is supposed to (adds a project to a scrapbook). But what it returns is causing the AJAX request to class as an error so I am unable to handle this correctly. I assume I am supposed to return some kind of response object but I don't know what this is or what it needs to include.
You can simply return an array containing whether it is success or it is failed.
$output_data = ['response' => true, 'message' => 'request is successful.' ];
$output_data = ['response' => false, 'message' => 'error message for user.' ];
return $output_data;
This will return control in success block of ajax.
You can check there is the response is true or false and execute the code accordingly.
You may return a json response on success:
public function add( $user_id, $project_id )
{
// Other code ...
$isSuccess = false;
if ($project->user_id != $user_id) {
$scrapbook = Scrapbook::firstOrNew(['user_id' => $user_id]);
if ($isSuccess = $scrapbook->save()) {
// only attach it if successfully saved
$scrapbook->projects()->attach($project_id);
}
}
return response()->json([
'success' => $isSuccess
]);
}
So in your ajax response you can check:
success: function( response ){
console.log( response.success ); // true or false
}
You need to return a json response using json() fucntion
return response()->json(true);
or if want to send additional data back
return response()->json([
'message' => 'successfull',
'items' =>$insertedItems
],200);
or on fail
return response()->json(['error'=>'error text'],$statusCode)
In Routes:
Route::get('/url', 'controller_name#controller_function');
Ajax:
$.ajax({
method: 'GET',
url: 'url',
data: {},
success: function( response ){
console.log( response );
},
error: function( e ) {
console.log(e);
}
});
In response , send json:
return response()->json(['message' => 'successfull'],200);

Laravel form validation in image upload with ajax

I am working in laravel 5. and using blade and ajax for upload image.
Every thing was working fine unless I inserted validation code in store function inside controller. Getting server error:
POST http://localhost:8000/imgC 500 (Internal Server Error)
I guess there is something wrong with url inside ajax or in routes, I am using Restfull Controller.
image.blade.php
{{Form::open(array('url' => 'imgC', 'method' => 'post','files'=>true, 'id'=>'upload_form'))}}
Title: {{Form::text('title')}}
Image: {{Form::file('image')}}
{{Form::submit('submit',['id' => 'btnAddProduct'])}}
{{Form::close()}}
ImageController.php:
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required|max:255',
]);
if ($validator->fails()) {
return "error";
}
$destinationpath = public_path() . '/img/';
$image=$request->input('image');
$filename=$request->file('image')->getClientOriginalName();
$request->file('image')->move( $destinationpath,$filename );
$img= new Image;
$img->name= $request->input('title');
$img->picture_path=$filename;
$saveflag=$img->save();
if($saveflag){
return Response::json(['success' => $saveflag, 'file' => asset($destinationpath.$filename)]);
}
}
AJAX function:
$(document).ready(function() {
$('#upload_form').submit(function (event) {
event.preventDefault();
$.ajax({
url: '/imgC',
data: new FormData($(this)[0]),
type: "POST",
processData: false,
contentType: false
}).done(function (response) {
console.log(response);
$("#success").show();
setTimeout(function() { $("#success").hide(); }, 5000);
});
});
});
route.php:
Route::resource('imgC', 'ImageController');
What am I doing wrong here?
I looked into the server log files and figured it out.
There was error with validation after adding Use Validator; in Image controller, problem solved

Resources