Hi I am using laravel code to check the email is unique or not and at the front end i am using jquery as follows:
blade.php page
user_email: {
required: true,
email: true,
remote: {
url: base_url + "/validate_email",
type: "post"
}
},
and on post i used the following method validation_email in controller:
function validate_email(Request $request) {
if ($request->input('user_email') !== '') {
if ($request->input('user_email')) {
$rule = array('user_email' => 'Required|email|unique:users');
$validator = Validator::make($request->all(), $rule);
}
if (!$validator->fails()) {
die('true');
}
}
die('false');
}
But when I fill the email and it validate it shows an error as CsrftokenMismatch Exception. When i disable the csrf token then csrf token then code is working otherwise it throws an exception.
Please suggest me some solution for this.. Thank You
Pass the token along in your Request in your blade.
remote: {
url: base_url + "/validate_email",
type: "post"
data: {
_token: function() {
return "{{csrf_token()}}"
}
}
}
its easy you CSRF token is in a hide field in your form, i dont remember de id but you can get that value and send it with the email in your post request for example:
required: true,
email: true,
remote: {
url: base_url + "/validate_email",
**YOU CAN ADD THE PARAMS HERE ( _id=" +$("#_id").val() +"),**
type: "post"
}
bassically you have add the token who is in your form to your post request, that value is hidden in the form, i hope i explain myself well
Related
I have a project in Cakephp 3.6 in which 3 actions in MessageController are called by Ajax. I have a problem, however, when I send a request to one of the action, XHR returns to me this:
{
"message": "CSRF token mismatch.",
"url": "\/messages\/changepriority\/8",
"code": 403,
"file": "D:\\xampp\\htdocs\\myapp\\vendor\\cakephp\\cakephp\\src\\Http\\Middleware\\CsrfProtectionMiddleware.php",
"line": 195
}
This is one of the action what I try to call from Ajax:
public function changepriority($id=null)
{
$this->autoRender = false;
$message = $this->Messages->get($id);
$message->priority = ($message->priority === false) ? true : false;
if ($this->Messages->save($message)) {
echo json_encode($message);
}
}
And this is my ajax:
$(".email-star").click(function(){
var idmessage = this.id;
$.ajax({
headers : {
'X-CSRF-Token': $('[name="_csrfToken"]').val()
},
dataType: "json",
type: "POST",
evalScripts: true,
async:true,
url: '<?php echo Router::url(array('controller'=>'Messages','action'=>'changepriority'));?>' +'/'+idmessage,
success: function(data){
if(data['priority'] === false) {
$("#imp_" + idmessage).removeClass("fas").removeClass('full-star').addClass( "far" );
}
else {
$("#imp_" + idmessage).removeClass("far").addClass( "fas" ).addClass("full-star");
}
}
});
});
I have read the documentation about Cross Site Request Forgery, and I tried to turn off the Csrf for these action first with:
public function beforeFilter(Event $event)
{
$this->getEventManager()->off($this->Csrf);
}
and then with:
public function beforeFilter(Event $event)
{
$this->Security->setConfig('unlockedActions', ['index', 'changepriority']);
}
But nothing. The Xhr return always the CSRF token mismatch.
What can I do ?
Edit:
I change the action in this way:
public function changepriority($id=null)
{
$this->autoRender = false;
$message = $this->Messages->get($id);
$message->priority = ($message->priority === false) ? true : false;
if ($this->Messages->save($message)) {
$content = json_encode($message);
$this->response->getBody()->write($content);
$this->response = $this->response->withType('json');
return $this->response;
}
}
In that way the action works. Can it be like that?
First check your $('[name="_csrfToken"]').val() output.
If you didn't get any output, need to check csrfToken hidden field is exist or not. Just right click in your page and click View Page Source
If not exist, you don't follow proper way when you create Form. Basically, when forms are created with the Cake\View\Helper\FormHelper, a hidden field is added containing the CSRF token.
If everything is correct, add the following line inside your ajax call after header
beforeSend: function (xhr) {
xhr.setRequestHeader('X-CSRF-Token', $('[name="_csrfToken"]').val());
},
Ps. Disabling the CSRF is not recommended by cakePHP and most of the developer aware of this. Hope this help.
beforeSend: function (xhr) {
xhr.setRequestHeader('X-CSRF-Token', <?= json_encode($this->request->getAttribute('csrfToken')) ?>);
},
So, I've been looking on here for the better part of 3 hours as to why my code isn't working. I don't think my ajax request is detecting my CSRF token even though i've tried multiple ways to implement it. New to AJAX requests so go easy.
Goal:
Submit an ajax POST request to /email/subscribe/ and add the email address provided by the user to the email_subscribers table.
I've tried adding the following to my code to get the token to show up:
The meta tag and the Ajax Setup.
Top of the file
<meta name="csrf-token" content="{{ csrf_token() }}">
In the script tag INSIDE the jquery $(document).ready() function
// CSRF Ajax Token
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
Hidden input field
I've also added a hidden input field and tried to insert the token inside the data object inside the ajax post.
HTML
<input type="hidden" id="token" value="{{ csrf_token() }}">
Javascript tag
var token = $('#token').val();
// var token = $('meta[name="csrf-token"]').attr('content'); //Tried this way
$.ajax({
type: 'POST',
url: '/email/subscribe/',
dataType: 'json',
data: {
email: email,
'_token': token,
// "_token": "{{ csrf_token() }}", //Tried this way as well
"_method": 'POST',
},
success: function (data) {
// Check Server Side validation
if($.isEmptyObject(data.errors)){
console.log(data['success']);
}else{
// Validation Failed Display Error Message
console.log(data.errors);
}
},
error: function (data) {
console.log(data);
}
}); // End Ajax POST function
Here is my web.php file
// Email Routes
Route::prefix('email')->group(function() {
// Create Post Route for subscribing
Route::post('/subscribe', 'EmailSubscriptionsController#subscribe')->name('email.subscribe');
});
and my EmailSubscriptionsController
class EmailSubscriptionsController extends Controller
{
// Store the Email into the database
public function subscribe(Request $request) {
// Validate the request
$validator = Validator::make($request->all(), [
'email' => 'required|email',
]);
// If the validation fails
if($validator->fails()) {
return response()->json([
'errors' => $validator->errors()->all(),
]);
}
// New Section Object
$subscription = new EmailSubscription;
// Add Name into Section Object
$subscription->email = $request->email;
// Save the Section
$subscription->save();
// Return The Request
return response()->json([
'success' => 'Record has been saved successfully!'
]);
} // End Subscribe
} // End Controller
Whats really weird is the fact that when i submit the request with NOTHING but the following in my subscribe() function inside my controller:
// Return The Request
return response()->json([
'success' => 'Record has been saved successfully!'
]);
It doesn't return an error.... Just passes the success message to the console. I'm not sure what i'm doing wrong as I have this working (an ajax post request) in another portion of my site.
Start by looking in storage/logs/laravel.log for the exception stack trace. That should give a more clear indication of what is failing.
The web inspector also allows you to see the response which usually includes the trace.
A common cause of 500 ISEs is improperly importing classes via use.
Use It Like This:-
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
}
I get TokenMismatchException when using nested AJAX calls. The first AJAX call works fine but the second always goes to error instead of success.
What I'm trying to do is that when the user registers from the button in the nav bar I want him to go to the dashboard or /home - this works okay. But, when the user fills the form (to buy something) on the index page, I want him to:
Have his input checked for validity, then, check if he's logged in, if not then the registration modal pops up. After he's registered I want him to be redirected to the checkout page.
However, what happens is that when the user fills the buying form and hits submit, the first ajax checks if the input in the buying form is valid, if it is, then check if he's logged in if not return 401 error.
401 gets picked up by the first ajax and directs the flow to 401 handling where the registration modal pops up to register, that's when the 2nd ajax pop up. After he's registered the back-end keeps returning 500 because of CSRF token mismatch.
First, this is the nested ajax:
<script type="text/javascript">
$(document).ready(function(){
$('#topup-form').submit(function(e){
e.preventDefault();
var topup_info = $('form').serialize();
//FIRST AJAX
$.ajax({
url: $('form').attr('action'),
method: 'post',
data: topup_info,
type: 'json',
//if success show success message for user
success: function(result){
alert(result.responseJSON.code);
$('.alert.error').slideUp(200);
$('.alert.success').append("<p class='lead'>Thanks! To checkout we go!</p>").slideDown(200);
},
//for error check if it's 400 (validation) or 401(authentication)
error: function(errorData){
// alert(errorData.responseJSON.code);
if(errorData.responseJSON.code === 400){
var error = errorData.responseJSON.message;
$('.alert.error').text('');
$('.alert.success').slideUp(200);
for (var i in error){
for (var j in error[i]) {
var message = error[i][j];
$('.alert.error').append("<p class='lead'>" + message + "<p>");
}
}
$('.alert.error').slideDown(00);
}//end error 400
//for authentication failure, show registeration modal
else if (errorData.responseJSON.code === 401) {
//change somethings in registeration modal
$('#myModalLabel').html('Please Login First');
$('#register').trigger('click');
document.getElementById('formRegister').action = "{{ route('user.regtopup') }}";
//when registeration form is submitted..
$('#formRegister').submit(function(e){
e.preventDefault();
//fire 2nd ajax
$.ajax({
url: $('#formRegister').attr('action'),
method: 'post',
data: $('form').serialize(),
type: 'json',
success: function(result){
alert('success!!!');
},
//it keeps going to error! complaining about csrf token mismatch
error: function(result){
console.log(JSON.stringify(result));
},
})//end of 2nd ajax
});//end of 2nd submit
}//end of 401
}//end of error
});//end of first ajax
});//end of first submit
$.ajaxSetup({
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
}
})
});
</script>
Second, this is the controller that checks input validity and return 401 when not registered:
public function etiPost(Request $request) {
$validator = [
'topupAmount'=> 'required|integer|between:10,500',
'phonenumber'=> 'required|regex:/^05[602][0-9]{7}$/',
];
$inputs = $request->all();
Log::info($inputs);
$validator = Validator::make($inputs, $validator);
if($validator->fails()){
return Response::json([
'error' => true,
'message' => $validator->messages(),
'code' => 400
], 400);
}
elseif (Auth::check()) {
return view('pages.checkout', compact('inputs'));
}
else {
return Response::json([
'error' => true,
'message' => "Please login first",
'code' => 401
], 401);
}
}
This is the overloaded register method that returns JSON when registration is successful. Here is where 500 is returned! When I Log the returned JSON it comes out as normal 200 response but it arrives at the "Whoops" 500 error to the 2nd ajax! The user is registered successfully in the database but this method returns 500 which is caught by the error part of the ajax call.
/**
* Handle a registration request for the application (overloaded).
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function register(Request $request)
{
$validator = $this->validator($request->all());
if ($validator->fails()) {
$this->throwValidationException(
$request, $validator
);
}
$this->guard()->login($this->create($request->all()));
// return response()->json();
return response()->json(['msg' => 'Success! You have been registered!'], 200);
}
I won't include the forms for brevity but rest assured I added all the CSRF input tags and the meta tag in the head of the HTML.
What should I do differently to avoid this? The first ajax works but the second doesn't.
Set header token for each ajax call
headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') },
Also note that you have to add mete token in your template
you can add meta token like this in template
<meta name="csrf-token" content="{{ csrf_token() }}">
if you still want to disable csrf token then
Excluding URIs From CSRF Protection
Sometimes you may wish to exclude a set of URIs from CSRF protection. For example, if you are using Stripe to process payments and are utilizing their webhook system, you will need to exclude your Stripe webhook handler route from CSRF protection since Stripe will not know what CSRF token to send to your routes.
Typically, you should place these kinds of routes outside of the web middleware group that the RouteServiceProvider applies to all routes in the routes/web.php file. However, you may also exclude the routes by adding their URIs to the $except property of the VerifyCsrfToken middleware:
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
class VerifyCsrfToken extends BaseVerifier
{
/**
* The URIs that should be excluded from CSRF verification.
*
* #var array
*/
protected $except = [
'stripe/*',
];
}
Instead of 'stripe/*', if you give '/*' then it will disable token for all
For more detail :
https://laravel.com/docs/5.5/csrf#csrf-x-csrf-token
please follow code in your jquery before ajax call
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
it's not advisable to add CSRF token in meta because all pages are not contain form to submit value so use this solution so you can use CSRF only for your js perspective.
Thank you
I'm trying to send a form build with CodeIgniter via AJAX and trying to get the response with JSON. However, I only see the respond when I open my developer tab (I'm not even sure, if that's actually a respond since it's showing both of the json data's).
All it shows, is the loading spinner, and after that it vanishes.
Code have been tested without AJAX and it works, so there can't be errors in PHP.
Here's my controller for resetting the password:
<?php
Class Users extends CI_Controller {
public function forgot_pass()
{
if(!$this->input->post('to_email'))
{
exit("No data");
}
$this->load->model('user');
$email = $this->input->post('to_email');
$email_addr = $this->user->get_email_address($email);
if(empty($email_addr))
{
echo json_encode(array('pls'=>0, 'msg' => "E-mail address was not found. Try again"));
}
$this->load->helper('string');
$new_password = random_string('alnum', 8);
$this->load->library('phpass');
$update_password = array( 'password' => $this->phpass->hash($new_password));
$update_password = $this->user->update_password($email, $update_password);
$this->load->library('email');
$config['newline'] = '\r\n';
$this->email->initialize($config);
$this->email->from('your#example.com', 'Your Name');
$this->email->to($email);
$this->email->subject('New password');
$this->email->message("Hey, " .$email_addr['name']. ". Your new password is: " .$new_password);
if($this->email->send())
{
echo json_encode(array('pls'=>1, 'msg' => "Password has been sent to given e-mail address"));
}
}
}
?>
And here's my AJAX call written with jQuery:
$(document).ready(function() {
$("form#forget_pass_form").on('submit', function(e){
e.preventDefault();
$("#loading_spinner").show();
var from = $(this);
$.ajax({
url: from.attr('action'),
type: from.attr('method'),
data: $(from).serialize(),
}).done(function(data) {
if(data.pls == 0) {
$("#forgot-pass-success").hide();
$("#forgot-pass-error").show();
$("#forgot-pass-error").fadeIn(1000).html(data.msg);
}
if(data.pls == 1) {
$("#forgot-pass-error").hide();
$("#forgot-pass-success").show();
$("#forgot-pass-success").fadeIn(1000).html(data.msg);
}
$("#loading_spinner").hide();
});
return false;
});
});
Firstly, can you try setting the correct header in the Controller?
header('Content-Type', 'application/json');
Or better yet:
$this->output->set_content_type('application/json');
As a side note, you should make sure you are always returning JSON data, so I would remove the exit() message and put a default JSON response at the bottom of the method.
Don't forget, when you echo your JSON, you can put return; afterwards to stop any more code running afterwards in that method.
Most of your code is ok. But you need to change some lines, both in your js, and controller.
Change 1(In Ajax function)
Change your ajax function and add dataType: "json" option
$.ajax({
url: from.attr('action'),
type: from.attr('method'),
dataType: "json",
data: $(from).serialize(),
}).done(function(data) {
....
});
Change 2 (In controller)
exit("No data");
to
exit(json_encode(array('pls'=>0, 'msg' => "No data")));
Change 3 (In controller)
echo json_encode(array('pls'=>0, 'msg' => "E-mail address was not found. Try again"));
to
exit(json_encode(array('pls'=>0, 'msg' => "E-mail address was not found. Try again")));
explanation
First change tell your script to handle the response data as Json
Second change is to keep all your return type same, if not when you sending only the no data response you are not handling this option from youe js.
And the last change make sure you stop further processing when sending email fails, and stop from showing both json.
I would like to suggest you about json return.
First in your ajax you have to use dataType: 'json'
$.ajax ({
url: from.attr('action'),
type: from.attr('method'),
data: $(from).serialize(),
dataType: 'json',
}).done(function(data) {
..your code..
});
CodeIgniter have output class, why don't you use output class to respond to ajax from CI.
$output = array('pls' => 1,
'msg' => "Password has been sent to given e-mail address"
);
$this->output->set_content_type('application/json')
->set_output(json_encode($output));
Use output class, this is more efficient then echo
I hope it will helps you for better code style.
I am currently using jQuery validation plugin with cakephp in my new project.
It's working perfectly untill I need to make unique check to email field through ajax to check with the database..
I didn't know how to make the plugin make a unique validation to email from db.
thanx
I reckon you are refering to using an AJAX call (via the plugin) to check for unique email with the server, yea?
I would suggest using the addMethod of the validation plugin to create a custom validation in which you can make an AJAX call (which will be part of the jQuery core).
There's an SO post on this topic which you can explore:
JQuery Validate Plugin - How to create a simple, custom rule?
Do note that you will have to implement the server-side script yourself.
Here's another article which should be useful (using jQuery and PHP):
Check email already exist – Ajax – Jquery
The syntax is simple
$.validator.addMethod("eventName",
function(value, element) {
// condition returns true or false
}, "Error message to display");
});
Event name is called in the form
<input type="text" name="name" class="eventName" />
Refer this link if any more doubts
jQuery Validate Plugin - How to create a simple custom rule?
If you want to check if the email is unique you can use remote rule.
It is from: http://jqueryvalidation.org/remote-method
Example: Makes the email field required, an email and does a remote request to check if the given address is already taken.
$( "#myform" ).validate({
rules: {
email: {
required: true,
email: true,
remote: "check-email.php"
}
}
});
Example: Makes the email field required, an email and does a remote request to check if the given address is already taken. In addition, the http method is set to “post” and the username is sent alongside the email address.
$( "#myform" ).validate({
rules: {
email: {
required: true,
email: true,
remote: {
url: "check-email.php",
type: "post",
data: {
username: function() {
return $( "#username" ).val();
}
}
}
}
}
});
Try something like
$.validator.addMethod("unique",
function(value, element, params) {
var isUnique = false;
if(value == '')
return isUnique;
id_send= '';
if(params[1] !='')
id_send ='id='+params[1]+'&';
$.ajax({
url: "path"+params[2],
type : 'GET',
async: false,
data: id_send+'field=' + params[0] + "&value=" + value,
dataType: 'json',
cache: true,
success: function(data){
isUnique = data;
}
});
return isUnique;
},
jQuery.validator.format("Value already in use")
);
In the above code:
path is the root path of your application;
params[0] is the name of attribute to check unique;
params[1] is the id of the object, if you want to check in edit too, so exclude himself;
params[2] is the path to the php file that gonna check.
Resulting in something like:
rules:
{
email: {
required: true,
unique:['email', $('#user_id').val(),'uniqueemail.php'],
email: true
},
The PHP uniqueemail.php, search for the value in field email, if return empty or the user with id equals $('#user_id').val() so return true, else return false.
Note that the async attribute is set false, this is a set back but is gonna do the job.