CodeIgniter4: Resubmitting form using Ajax giving 403 Forbidden - php

I'm working on a project in CodeIgniter4. I'm trying to make an Ajax call to an endpoint (/adjustments/store). I'm validating the form using CodeIgniter and showing the validation errors in my view. The issue is when the first time, i submit the form, it works and shows some validation errors. But when i fill the form correclty (to get not validation errors) and resubmit it again it gives me 403 forbidden error in the console.
Ajax call
$.ajax({
type: 'post',
url: '/adjustments/store',
dataType: 'html',
data: {
number,
date,
type,
account,
description,
adjData,
csrf_test_name
},
success: function (res) {
if (IsJsonString(res)) {
const response = JSON.parse(res);
if (response.hasOwnProperty('validation_errors')) {
const errors = response.validation_errors;
for (err in errors) {
$(`input[name=${ err }]`)
.parent()
.append(`<small class="text-danger">${ errors[err] }</small>`)
}
}
}
function IsJsonString(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
console.log(res);
}
CodeIgniter Controller
public function store () {
$data = $this->request->getPost(NULL);
// Validate
if (! $this->validate([
'number' => 'required',
'date' => 'required',
'type' => 'required',
'adjData' => 'required',
]))
{
echo json_encode(['validation_errors' => $this->validator->getErrors()]);
return;
}
echo json_encode($data);
}
Any solution to this?

If you are resubmitting a form then you have update csrf token on every request with ajax.
Whenever validation fails pass csrf token and update it every time.
In your controller -
public function store () {
$data = $this->request->getPost(NULL);
// Validate
if (! $this->validate([
'number' => 'required',
'date' => 'required',
'type' => 'required',
'adjData' => 'required',
]))
{
echo json_encode(['validation_errors' => $this->validator->getErrors(), 'csrf' => csrf_hash()]);
return;
}
echo json_encode($data);
}
In you ajax -
$.ajax({
type: 'post',
url: '/adjustments/store',
dataType: 'html',
data: {
number,
date,
type,
account,
description,
adjData,
csrf_test_name
},
success: function (res) {
if (IsJsonString(res)) {
const response = JSON.parse(res);
$("input[name='csrf_test_name']").val(response ["csrf"]);
if (response.hasOwnProperty('validation_errors')) {
const errors = response.validation_errors;
for (err in errors) {
$(`input[name=${ err }]`)
.parent()
.append(`<small class="text-danger">${ errors[err] }</small>`)
}
}
}
function IsJsonString(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
So once you update csrf then it will work fine.
Thanks.

Related

I am getting a POST 500 (Internal Server Error) "Too few arguments to function" in Laravel

I do not know what I am missing, but I cant make this work. It's throwing an error, POST 500 (Internal Server Error) "Too few arguments to function" in Laravel.
$(document).on('click', '.btnUpdateStudent', function (e) {
e.preventDefault();
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$td=$(this).closest('td');
$tr=$(this).closest('tr');
var id=$td.attr("data-studId");
var inputEditName="<input type='text' class='inputEditName form-control'>";
$tr.find('td:eq(1)').val(inputEditName);
$tr.find('td:eq(1)').find("input.inputEditName").val();
var inputEditEmail="<input type='text' class='inputEditEmail form-control'>";
$tr.find('td:eq(2)').val(inputEditEmail);
$tr.find('td:eq(2)').find("input.inputEditEmail").val();
var options = $('#selectDepartment option');
var optionValues = $.map(options ,function(option){
return "<option value='"+option.value+"'>"+option.text+"</option>";});
var selectDepartment ="<select class='selectDepartment form-select form-control'></select>";
var updateDept=$('.selectDepartment').val();
$tr.find('td:eq(3)').val(selectDepartment);
$tr.find('td:eq(3)').find("select.selectDepartment").html(optionValues);
$tr.find('td:eq(3)').find("selectDepartment").val();
$tr.find('td:eq(3)').find("select.selectDepartment").val(updateDept);
var editname=$tr.find('td:eq(1)').find("input.inputEditName").val();
var editemail=$tr.find('td:eq(2)').find("input.inputEditEmail").val();
var editdepartment=$tr.find('td:eq(3)').find("select.selectDepartment").val();
var data = {
'id' : id,
'name' : editname,
'email': editemail,
'department_id': editdepartment
}
console.log(data);
$.ajax({
type: "POST",
url: "/update-student",
data: data,
dataType: "json",
success: function (response) {
console.log(response);
if (response.status == 400) {
$('#saveform_errList').html("");
$('#saveform_errList').addClass('alert alert-danger');
$.each(response.errors, function (key, err_values){
$('#saveform_errList').append('<li>'+err_values+'</li>');
});
}else {
$('#saveform_errList').html("");
$('#success_message').addClass('alert alert-success')
$('#success_message').text(response.message)
$("#inputForm").find('input').val("");
}
}
});
});
this is my controller. did i missed something? or is there part that should be there?
public function update(Request $request)
{
$validator = Validator::make($request->all(), [
'name'=> 'required|max:100',
'email'=>'required|email|max:100',
'department_id'=>'required'
]);
if($validator->fails())
{
return response()->json([
'status'=>400,
'errors'=>$validator->messages()
]);
}
else
{
$student = Student::find();
if($student)
{
$student->id = $request->input('id');
$student->name = $request->input('name');
$student->email = $request->input('email');
$student->department_id = $request->input('department_id');
$student->update();
return response()->json([
'status'=>200,
'message'=>'Student Updated Successfully.'
]);
}
else
{
return response()->json([
'status'=>404,
'message'=> 'No Student Found.'
]);
}
}
}
I tried reviewing my code but I really can't distinguish the problem. I need help
$student = Student::find() is where your issue is. The find() method requires one parameter which is the primary key id gotten from your database.
Now, since you already passed the id via your ajax just change your code to this:
public function update(Request $request)
{
$validator = Validator::make($request->all(), [
'name'=> 'required|max:100',
'email'=>'required|email|max:100',
'department_id'=>'required'
]);
if($validator->fails())
{
return response()->json([
'status'=>400,
'errors'=>$validator->messages()
]);
}
else
{
$student = Student::find($request->id); // here I have added the required parameter
if($student)
{
$student->id = $request->input('id');
$student->name = $request->input('name');
$student->email = $request->input('email');
$student->department_id = $request->input('department_id');
$student->update();
return response()->json([
'status'=>200,
'message'=>'Student Updated Successfully.'
]);
}
else
{
return response()->json([
'status'=>404,
'message'=> 'No Student Found.'
]);
}
}
}
UPDATE:
To refresh the page automatically after the Ajax request is successful, do this:
Add this directly above where you have if (response.status == 400) {:
if (response.status == 200) {
location.reload();
}
This will reload the page automatically.

Jquery and Ajax Error Message cannot Display in Laravel Blade

I Insert Ledger Record using Ajax and Jquery in Laravel. Success Message has been Displayed Correctly but Error Custom Message Cannot Display in blade View. Whats My Mistake Please Mention.
Jquery :
$("#add").click(function(event) {
event.preventDefault();
$.ajax({
type: 'post',
url: $("#add").attr('data-url'),
data: {
'_token': $("input[name=_token]").val(),
'form_data': $('#Form').serialize(),
},
success: function(data) {
$('#ledger_name').val('');
$('#openning_balance').val('');
$('#ob_type').val('');
$('#under').val('');
$('#ledger_address').val('');
$("#newLedger .close").click();
$(".result").html(data.success).css({
'color': 'green',
'text-align': 'center'
}).delay(5000).fadeOut();
},
error: function(data) {
$('#response').show().html(data.error).css({
'color': 'red',
'text-align': 'center'
}).delay(5000).fadeOut();
}
});
});
Controller :
$values = array();
parse_str($_POST['form_data'], $values);
$validation = $this->validator($values,true );
if($validation->fails()){
$errors = $validation->errors();
return response()->json(['error' => 'Please Fill all Mandatory Fields',],500);
}
$insertledgers=Ledger::create(['ledger_name'=>$values['ledger_name'],'openning_balance'=>$values['openning_balance'],'ob_type'=>$values['ob_type'],'under'=>$values['under'],'ledger_address'=>$values['ledger_address'],'company_id'=>$companyids,'user_id'=>$usersid,'created_by'=>$usersid]);
$ledgerinsertids=$insertledgers->id;
if($values['ob_type'] == 'Cr'){
$creditamts=$values['openning_balance'];
$debitamts= 0;
} else {
$creditamts=0;
$debitamts= $values['openning_balance'];
}
$insertledgeropenningbalance=Openningbalance::create(['ledgerid'=>$ledgerinsertids,'opening_credit'=>$creditamts,'opening_debit'=>$debitamts,'company_id' => $companyids,'user_id' => $usersid,'created_by' => $usersid,]);
return response()->json(['success' => 'Ledger Details Added Successfully',],200);
Try this:
<?php
use Validator;
class SomeController extends Controller {
public function SomeFunction(Request $request) {
$values = array();
parse_str($_POST['form_data'], $values);
$validation = Validator::make($values, true);
if($validation->fails()){
$errors = $validation->errors();
return response()->json(['error' => 'Please Fill all Mandatory Fields'], 500);
}
$insertledgers=Ledger::create(['ledger_name'=>$values['ledger_name'],'openning_balance'=>$values['openning_balance'],'ob_type'=>$values['ob_type'],'under'=>$values['under'],'ledger_address'=>$values['ledger_address'],'company_id'=>$companyids,'user_id'=>$usersid,'created_by'=>$usersid]);
$ledgerinsertids=$insertledgers->id;
if($values['ob_type'] == 'Cr'){
$creditamts=$values['openning_balance'];
$debitamts= 0;
} else {
$creditamts=0;
$debitamts= $values['openning_balance'];
}
$insertledgeropenningbalance=Openningbalance::create(['ledgerid'=>$ledgerinsertids,'opening_credit'=>$creditamts,'opening_debit'=>$debitamts,'company_id'
=> $companyids,'user_id' => $usersid,'created_by' => $usersid,]);
return response()->json(['success' => 'Ledger Details Added Successfully',],200);
And in view:
error: function(data)
{
$('#response').html(data.error).css({'color': 'red', 'text-align': 'center'})
$('#response').show().delay(5000).fadeOut();
}
You just need to modify your error callback function as below:
error : function (data) {
$('#response').show().html(data.responseJSON.error).css({
'color': 'red',
'text-align': 'center'
}).delay(5000).fadeOut();
}
Thanks #voodoo417

Yii2 run JS-script on error ajax-validation

There is my form:
$form = ActiveForm::begin([
'id' => 'user-create-form',
'enableAjaxValidation' => true,
'enableClientValidation' => false,
'validationUrl' => Url::toRoute(Yii::$app->controller->id . '/validation'),
'validateOnType' => true,
]);
JS-script is registered on this form and performed Russian to English transliteration according to some rules on .keyup() event. Transliteration result is added to samname field.
There is validation rule in UserCreateForm model:
public function rules()
{
return [
[['samname'], 'validateUserExist'],
];
}
public function validateUserExist()
{
$check = Yii::$app->CustomComponents->checkUserExist($this->samname);
if ($check) {
$errorMessage = 'User exists: ' . $check;
$this->addError('samname', $errorMessage);
}
}
Function checkUserExist() checks existing of created name and returns an error in matching case.
There is action on controller:
public function actionValidation()
{
$model = new UserCreateForm();
if (\Yii::$app->request->isAjax && $model->load(\Yii::$app->request->post())) {
\Yii::$app->response->format = Response::FORMAT_JSON;
echo json_encode(ActiveForm::validate($model));
\Yii::$app->end();
}
}
It works great, validation is performed, matching case returns an error...
But!
It's required that JS-script is run again and added next letter to the name on error (JS-script provides this functionality). How to run JS-script again after validator was return an error?
#yafater Thanks for help! I find solution.
$('form').on('afterValidateAttribute', function (event, attribute, message) {
if (attribute.name === 'samname')
{
$.ajax({
url: "url-to-action",
type: "POST",
dataType: "json",
data: $(this).serialize(),
success: function(response) {
if ( typeof(response["form-samname"]) != "undefined" && response["form-samname"] !== null ) {
// code here
}
},
});
return false;
}
});

Codeigniter always return error message

I tried to convert the codeigniter form handling using ajax then display validation error if validation is false but in my current state, it always throw an error. Check the code below for reference.
PHP:
public function add () {
$post_data = $this->input->post('formdata');
$data = array (
'identity' => $post_data ['email'],
'password' => $post_data ['password'],
'email' => $post_data ['email'],
'group' => array($post_data['group_id']),
'additional_data' => array (
'first_name' => $post_data['first_name'],
'last_name' => $post_data['last_name'],
'active' => $post_data['active'],
'date_registered' => date('Y/m/d h:i:sa')
)
);
// custom error message
$this->form_validation->set_message('alpha_dash_space', '%s appears to be invalid. Must contain only alphabets.');
$this->form_validation->set_message('matches', '%s does not match the Confirm Password field. ');
if ($this->form_validation->run() == TRUE) {
$result['data'] = $this->ion_auth->register($data['identity'], $data['password'], $data['email'], $data['additional_data'], $data['group']);
} else {
$result['message'] = validation_errors();
}
echo json_encode($result);
}
JS:
function submit_form (form_id) {
var url = $(form_id).attr("action");
var formData = {};
$(form_id).find("input[name]").each(function (index, node) {
formData[node.name] = node.value;
});
$(form_id).find('select[name]').each(function (index, node) {
formData[node.name] = node.value;
});
$(form_id).find('textarea[name]').each(function (index, node) {
formData[node.name] = node.value;
});
$.ajax({
type: "POST",
data: {
'formdata': formData
},
url: url,
dataType: 'json',
success: function(result) {
if (result.data) {
console.log(success);
swal({
title: "Success!",
text: "You've done it great!",
type: "success"
},
function(){
location.reload();
});
} else {
$('#error-msg').html(result.message);
}
},
error: function(data) {
swal({
title: "Error!",
text: "Oops, something went wrong. Check and try again.",
type: "error"
});
}
});
}
Note: Form validation are set in config directory. So no issues in form rules. All are running good except I think the jquery that handles the condition.
Edit like below:
if ($this->form_validation->run() == FALSE) {
$result['message'] = validation_errors();
} else {
$result['data'] = $this->ion_auth->register($data['identity'],
$data['password'], $data['email'], $data['additional_data'],
$data['group']);
}
Also you have set_message but not set_rules. If you want to use form_validation library, you should set some rules.

PatchEntity ignore data from an ajax request in Cakephp 3.0

I often use the patchEntity function to hydrate my entity with form data, and it works fine, even with an ajax request.
But when I tried to insert data from an an ajax request with JSON data, patchEntity failed to retrieve the data.
My ajax request is very simple:
var rate = function (user, rate, success, error) {
$.ajax({
type: "POST",
url: baseUrl + 'rate/add',
data: {
id: this.id,
user: user.id
rate: rate
},
dataType: 'json',
success: success,
error: error
});
});
In my Rate controller, my add function looks like:
public function add()
{
if ($this->request->isAjax()) {
$this->layout = 'ajax';
$rate = $this->Rate->newEntity();
if ($this->request->is('post')) {
$rate = $this->Rate->patchEntity($rate, $this->request->data);
if ($rate->errors()) {
$this->set([
'status' => 500,
'message' => $rate->errors()
]);
} else {
if ($this->rate->save($rate)) {
$this->set([
'status' => 200
]);
} else {
$this->set([
'status' => 500,
'message' => $rate->errors()
]);
}
}
return $this->render('/Ajax/result');
}
}
This throw an exception:
Cannot insert row, some of the primary key values are missing. Got (,
, ), expecting (id, user)
I can save my data using this instead of $this->Rate->patchEntity($rate, $this->request->data);
$rate['id'] = $this->request->data['id'];
$rate['user'] = $this->request->data['user'];
$rate['rate'] = $this->request->data['rate'];
What sort of array do I have to pass to patchEntity function to makes this works?
Thanks to ndm's comment, I've checked the Rate Entity and just removed this part which was automatically generated by bake:
protected $_accessible = [
'rate' => true,
];

Categories