Create ajax cross domain request to rest laravel api - php

I create an mobile app with phonegap and I dont know how smart it is but I want to user to reg. on my app with their phone number and PIN. Users will download app, type phone number and get PIN via text message (SMS) (twillio api)... Now I have basic problem how to run an laravel php code with ajax cross domain.
I do:
HTML+JS+ajax:
<body class='bg-blue'>
</br>
<h1 class="text-center">AgroAgro</h1>
</br>
<h4 class="text-center">Register manager account and add workers.</h4>
</br>
<div class="col-xs-12"><p>Your Phone Number</p></div>
<div class="col-xs-12">
<input class="form-control" placeholder="Your Phone Number"/>
</div>
<div class="col-xs-12"></br></div>
<div class="col-xs-12 text-center">
<button id="createPin" class="btn btn-success btn-lg">FREE sign up</button>
</div>
<footer>We will send you a PIN code via text message immediately to login and get started. We will never share or span your phone number.</footer>
<script>
$(function() {
$('#createPin').click(function(e) {
e.preventDefault();
$.ajax({
url: "localhost:8000/createPin",
type: "POST",
async: true,
data: { phoneNumber:$("#createPin").val()},
dataType: "json",
success: function(data) {
console.log(data);
//do something
},
error: function (data) {
console.log(data);
}
});
});
});
</script>
on backend side I write php with laravel framework:
Route::put('createPin', function()
{
$phoneNumber = Input::get('phoneNumber');
$pin = rand(1000,9999);
$user = new User;
$user->phoneNumber = $phoneNumber;
$user->pin = $pin;
// this line loads the library
require('/path/to/twilio-php/Services/Twilio.php');
$account_sid = 'AC6333333911376fghhbced190522da587';
$auth_token = '[AuthToken]';
$client = new Services_Twilio($account_sid, $auth_token);
$client->account->messages->create(array(
'To' => $phoneNumber,
'From' => "+18702802244",
'Body' => "PIN code",
'MediaUrl' => "Your pin code is ".$pin,
));
$user->save();
return $users;
});
When I click on button with IDcreatPin I get this error:
XMLHttpRequest cannot load localhost:8000/createPin. Cross origin requests are only supported for protocol schemes: http, data, chrome-extension, https, chrome-extension-resource.
How I can solve this problem? Also what you think about idea of PIN instead password?

Related

Ajax jquery(post) doesn't pass data to php [duplicate]

This question already has answers here:
Receive JSON POST with PHP
(12 answers)
Closed 9 months ago.
I am trying to pass data to my php page:
<?php
var_dump($_POST);
if (isset($_POST['goal']) && isset($_POST['amount'])){
$goal = $_POST['goal'];
$amount = $_POST['amount'];
$array = array(
"goal" => $goal,
"amount" => $amount
);
echo json_encode($array);
}
However as a result of var_dump $_POST I keep getting an empty array, for some reason my ajax doesn't pass the neccessary data. I tried console.logging the value of fields that I am using and their value is correct it's just that data doesn't pass on the php page.
ajax:
<script type="text/javascript">
$(document).ready(function () {
//use button click event
$("#goalBTN").click(function (e){
e.preventDefault();
let amount = $("#amount").val();
let goal = $("#goal_name").val();
$.ajax({
method: "post",
url: "target-modal-code.php",
data:JSON.stringify( {
amount: amount,
goal: goal
}),
contentType:"application/json",
success: function (response){
$("#response").text(response);
console.log(amount);
console.log(goal);
},
error: function(response) {
alert(JSON.stringify(response));
}
})
});
});
</script>
And my form is inside a modal :
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="enrollLabel">Change your goal</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="target-modal-code.php" name="target-form" id="target-form">
<div class="modal-body">
<form action="">
<div class="mb-3 input-control">
<label for="amount">Cost</label>
<input type="number" class="form-control" id="amount" name="amount"
placeholder="Amount">
<small class="message" id="message-password"></small>
<br>
</div>
<div class="mb-3 input-control">
<label for="goal_name">Goal</label>
<input type="text" class="form-control" id="goal_name" name="goal_name"
placeholder="Goal">
<small class="message" id="message-password"></small>
<br>
</div>
</form>
</div>
<p class="response" id="response"></p>
<div class="modal-footer">
<div class="response">
</div>
<button type="button" id="goalBTN" class="btn btn-warning">Save changes</button>
</div>
</form>
</div>
</div>
Updated answer after some live testing with Network tab in firefox web dev tools
The problem is that the current ajax code is not sending any of the elements because of wrong content-type. Let it detect content-type automatically. For jq ajax, default seems to be contentType: application/x-www-form-urlencoded even if you don't provide it specifically.
So, this worked:
<script type="text/javascript">
$(document).ready(function () {
//use button click event
$("#goalBTN").click(function (e){
e.preventDefault();
// let amount = $("#amount").val();
// let goal = $("#goal_name").val();
var formData = {
amount: $("#amount").val(),
goal_name: $("#goal_name").val(),
};
$.ajax({
method: "post",
url: "target-modal-code.php",
// datatype:"json",
//data:JSON.stringify(formData),
data: formData,
//contentType:"application/json",
//encode: true,
success: function (response){
$("#response").text(response);
// console.log(amount);
// console.log(goal);
console.log(formData);
},
error: function(response) {
alert(JSON.stringify(response));
}
})
});
});
</script>
After little bit of fiddling, I noticed that it works if you DON'T provide it contentType at all. Otherwise, AJAX won't send GET or POST params to the server.... dont know why. I know it's weird but that's how it is in jquery ajax.
I have intentionally kept the comments for you to see what all I have tried.
So to summarize,
Don't stringify the form data,
Don't provide contentType to ajax
request.
Cheers.!
format send ajax:
$.ajax({
...
data : {
foo : 'bar',
bar : 'foo'
},
...
});
in your case: change data send format like:
data: {
amount: amount,
goal: goal
}

Codeigniter 4 reuse of CSRF token in AJAX modal

Scenario:
I am developing CMS system and I wan to add some categories to the objects (pages, posts, media etc.). In my view, to save a new category I use HTML form placed in Bootstrap modal which is sent via AJAX to my controller. The CSRF protection is enabled on the entire site.
While sending the data for the first time, I pass the CSRF token name and hash via form. Once being processed by PHP code in controller, I want to pass CSRF values in the response so I will be able to "re-use" the form in the modal (e.g. display error messages or/and create another category).
Yet, I am not able to access the get_csrf_token_name() and get_csrf_hash() methods to pass values back to the view.
In my view admmin/category/create.php:
...
<!-- CREATE CATEGORY MODAL MODAL -->
<div class="modal" id="createCategory" tabindex="-1">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Nová kategorie</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Zavřít"></button>
</div>
<div class="modal-body">
<form action="" method="post" id="createCategoryForm">
<input type="hidden" value="<?= csrf_hash(); ?>" name="<?= csrf_token(); ?>" id="csrf">
<div class="form-group mb-3">
<label for="title" class="form-label">Název kategorie</label>
<input type="text" class="form-control" name="title" id="title" value="">
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" id="createCategoryConfirm">Vytvořit novou kategorii</button>
</form>
</div>
</div>
</div>
</div>
...
<script>
$('#head').on('click', '.create', function() {
$('#createCategory').modal('show');
$('#createCategoryForm').attr('action', '<?= base_url(); ?>/admin/category/create');
$('#createCategoryConfirm').click(function(e) {
e.preventDefault();
var url = $('#createCategoryForm').attr('action');
var csrfElement = $('#csrf');
var csrfName = csrfElement.attr('name');
var csrfHash = csrfElement.attr('value');
var categoryTitle = $('input[name=title]').val();
var data = {
[csrfName]: csrfHash,
'title': categoryTitle
};
console.log(data);
$.ajax({
type: 'ajax',
method: 'POST',
url: url,
data: data,
dataType: 'json',
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
headers: {'X-Requested-With': 'XMLHttpRequest'},
success: function(result) {
console.log(result);
},
error: function(result) {
console.log(result);
},
});
});
});
</script>
In my controller Category.php:
<?php
namespace App\Controllers\Admin;
use App\Controllers\BaseController;
use App\Models\CategoryModel;
use CodeIgniter\I18n\Time;
class Category extends BaseController {
protected $model;
protected $validator;
protected $security;
public function __construct() {
$this->model = new CategoryModel();
$this->validation = \Config\Services::validation();
$this->security = \Config\Services::security();
helper(['form', 'date', 'url']);
}
...
public function create() {
$response = [];
// This part of code returns error
//
// $response['csrf'] = array(
// 'name' => $this->security->get_csrf_token_name(),
// 'hash' => $this->security->get_csrf_hash()
// );
$response['security'] = $this->security;
if ($this->request->isAJAX()) {
$newCategory = [
'title' => $this->request->getVar('title'),
'slug' => url_title($this->request->getVar('title')),
'author' => session()->get('id'),
'created_at' => Time::now('Europe/Prague')->toDateTimeString(),
'updated_at' => Time::now('Europe/Prague')->toDateTimeString(),
'parent' => '0'
];
$this->validation->run($newCategory, 'categoryRules');
if (!empty($this->validation->getErrors())) {
$this->model->save($newCategory);
$response['errors'] = $this->validation->getErrors();
echo json_encode($response);
} else {
$this->model->save($newCategory);
$response['success'] = 'New category was created';
echo json_encode($response);
}
}
}
...
In the browser console, the AJAX response is POST http://localhost/admin/category/create 500 (Internal Server Error) with full response:
code: 500
file: "D:\Web\XAMPP\htdocs\lenka\app\Controllers\Admin\Category.php"
line: 38
message: "Call to undefined method CodeIgniter\Security\Security::get_csrf_token_name()"
title: "Error"
Could anyone please see the issue here? Is there any good solution on how to reuse CSRF tokens in CI4? I tried set config values of CSRF regenerate both to true and false, with no effect.
update this line cod in .ENV
or
app/config/security
CSRF Regenerate = false

redirect page after jquery submit using header() function on another page using php

i have this login form
<form autocomplete="off" id="login_form">
<div class="login-wrapper">
<input required type="text" class="login-input" name="email" id="email" placeholder="email">
<span class="fas fa-envelope mail_name-email"></span>
<span class="err_output err_email"></span>
</div>
<div class="login-wrapper">
<input required type="password" class="login-input" name="pwd" id="pwd" placeholder="password">
<span class="fas fa-lock pwd_password"></span>
<span class="err_output err_pwd"></span>
</div>
<input type="submit" class="login_btn" id="login_btn" name="login" value="log in">
</form>
the submission is handled using jquery, like so
$(document).ready(function() {
$(document).on("submit", "#login_form", function() {
Login();
//send values to post
const mail = document.getElementById("email").value;
const pwd = document.getElementById("pwd").value;
$.ajax({
type: "POST",
url: "./inc/login.php",
data: {
email: mail,
password: pwd
}
});
return false;
});
});
so it works well but i wanted to do all the validation on the serverside particluarly in the login.php file included in the url within the jquery code because the data entered is sensitive and i cannot just redirect usin javascript. So even before i started the validation i tried a redirect to another page after the form was submitted but it wouldn't work, i tried header("Location: ../main.php") and echo "<script>location='../dashboard.php'</script>"; but on the console all i saw was this
jquery.js:9837 XHR finished loading: POST "http://localhost/My%20portfolio/admin/inc/login".
i have even included an action attribute on my form pointing to the action page but it doesn't work, this is the only way i can proceed with validation otherwise i am stuck, i dont know what's wrong
You can't use a redirect in PHP on an ajax call. You need to return something to the JS page and redirect from there. For example, your PHP can return a json object with the status and the URL to forward to.
You can output something like this:
{
"status" : "success",
"url" : "http://www.example.com/url-to-redirect"
}
Or if it fails
{
"status" : "error",
"message" : "Error message to show"
}
Then in your javascript, check for the answer and validate the status
$.ajax({
type: "POST",
url: "./inc/login.php",
data: {
email: mail,
password: pwd
},
dataType: "json"
}).done(function( data ) {
if (data.status === "success") {
window.location.href = data.url;
}
else if (data.status === "error") {
alert(data.message);
}
});
In your PHP script you need to output something like an array.
So in your PHP validation, if everything is validated, you can simply do
echo json_encode(array('status' => 'success', 'url' => 'http://www.example.com/url-to-redirect'));
But if it fails:
echo json_encode(array('status' => 'error', 'message' => 'Error message to show'));
I suggest you read more on json_encode and ajax calls with PHP.

I got "timeout-or-duplicate" error using ReCaptcha v3

I got a contact form on my website on Laravel and I'd like to place a ReCaptcha v3 but for now the result I got from the verification is the error "timeout-or-duplicate".
Can you help me from A to Z ? I don't know where to go...
My head :
<script src="https://www.google.com/recaptcha/api.js?render=My_Site_Key"></script>
<script>
grecaptcha.ready(function () {
grecaptcha.execute('My_Site_Key', { action: 'contact' }).then(function (token) {
var recaptchaResponse = document.getElementById('recaptchaResponse');
recaptchaResponse.value = token;
});
});
</script>
The contact form :
<form action="{{ route('contact.post') }}" id="contact-form" method="post" name="contactForm">
<input type="hidden" name="_token" id="token" value="{{ csrf_token() }}">
<input type="hidden" name="recaptcha_response" id="recaptchaResponse">
<fieldset>
<div class="col-sm-12">
<input id="name" name="name" placeholder="Nom*" type="text">
</div>
<div class="col-sm-12">
<input id="email" name="email" placeholder="Email*" type="text">
</div>
<div class="col-sm-12">
<input id="object" name="object" placeholder="Objet*" type="text" autocomplete="off">
</div>
<div class="col-xs-12">
<textarea cols="5" id="message" name="message" placeholder="Votre message...*"></textarea>
</div>
<div class="col-xs-12">
<button class="submit active" id="contact-submit">ENVOYER</button>
</div>
<div class="error col-xs-12">
<h3></h3>
</div>
<div class="success col-xs-12">
<h3>Merci ! Votre message a été envoyé !</h3>
</div>
</fieldset>
</form>
Route:
Route::post('/contact', array('as' => 'contact.post', 'uses' => 'ContactController#send'));
The Contact Controller :
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Mail;
class ContactController extends Controller
{
public function send() {
$info = array(
'name' => Input::get('name'),
'email' => Input::get('email'),
'object' => Input::get('object'),
'message' => Input::get('message')
);
if($info['name'] == "" || $info['email'] == "" || $info['object'] == "" || $info['message'] == "") {
return json_encode(['response' => 'Tous les champs doivent être remplis !']);
}
if(!filter_var($info['email'], FILTER_VALIDATE_EMAIL)) {
return json_encode(['response' => 'Vous devez rentrer une adresse e-mail valide !']);
}
$ip = Request()->ip();
// Build POST request:
$recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify';
$recaptcha_secret = 'My_Secret_Key';
$recaptcha_response = $_POST['recaptcha_response'];
// Make and decode POST request:
$recaptcha = file_get_contents($recaptcha_url . '?secret=' . $recaptcha_secret . '&response=' . $recaptcha_response);
$recaptcha = json_decode($recaptcha);
// Take action based on the score returned:
if ($recaptcha->score < 0.5) {
return json_encode(['response' => 'Vous êtes considéré comme Bot/Spammer !', 'score' => $recaptcha->score]);
}
Mail::send(['email.html.contact', 'email.text.contact'], ['info' => $info, 'ip' => $ip], function($message) use ($info) {
$message->to('contact#bryangossuin.be')->subject('Bryan Gossuin | Formulaire de contact');
$message->replyTo($info['email'], $info['name']);
});
return json_encode(['response' => 'success','']);
}
}
Finaly the javascript
$('#contact-form').on('submit', function(e) {
e.preventDefault();
swal({
title: "Souhaitez-vous vraiment envoyer ce mail ?",
icon: "warning",
buttons: {
cancel: {
text: "Annuler",
value: false,
visible: true,
closeModal: true,
},
confirm: "Envoyer",
}
})
.then((value) => {
if (value) {
$.ajax({
method: "POST",
url: "contact",
cache: false,
data: $(this).serialize(),
dataType: 'json',
success: function(json) {
console.log(json.score);
if (json.response == 'success') {
$('#contact-form').trigger("reset");
swal("E-mail envoyé", "Merci de votre demande !", "success");
} else {
swal("Erreur !", json.response, "error");
}
}
}
)
}
});
});
The output I got from google is
{
"success": false,
"error-codes": [
"timeout-or-duplicate"
]
}
and I expect it to be
{
"success": true,
"score" : x,
"error-codes": '',
}
I guess the problem is because the « method post » is used two times because when I Check directly
On the API Google to verify the user token it show le thé code but right after I refresh the page it show me « timeout or duplicate » but I dont know how to fix this
I got this from people double clicking the submit button on the form.
As stated in the documentation this error is caused by:
Validity time of the token expired (After you get the response token, you need to verify it within two minutes)
Token has been used previously. To confirm that, log the token value before is used (error log, local file, whatever)
My resolution for 1, set an interval that calls the set token function, so it is refreshed every 2 minutes.
$(document).ready(function() {
SetCaptchaToken();
setInterval(function () { SetCaptchaToken(); }, 2 * 60 * 1000);
});
Resolution for 2, fix your code :)
The problem is this piece of code:
<script src="https://www.google.com/recaptcha/api.js?render=My_Site_Key"></script>
<script>
grecaptcha.ready(function () {
grecaptcha.execute('My_Site_Key', { action: 'contact' }).then(function (token) {
var recaptchaResponse = document.getElementById('recaptchaResponse');
recaptchaResponse.value = token;
});
});
</script>
The token is only valid for 2 minutes after you execute is called as stated in the docs:
Note: reCAPTCHA tokens expire after two minutes. If you're protecting an action with reCAPTCHA, make sure to call execute when the user takes the action.
Thus, if you spend more then 2 minutes on the contact-form, you get the timout error,. Thats why its recommended in the docs to only call execute if the user actually submits your form / takes action. In vanilla JS it would look like this:
<script src="https://www.google.com/recaptcha/api.js?render=My_Site_Key"></script>
<script>
grecaptcha.ready(function() {
document.getElementById('contact-form').addEventListener("submit", function(event) {
event.preventDefault();
grecaptcha.execute('My_Site_Key', {action: 'contact'}).then(function(token) {
document.getElementById("recaptchaResponse").value= token;
document.getElementById('contact-form').submit();
});
}, false);
});
</script>
Every time the page reloads you get a new token from google . You can use that token only once . Somehow if you are using that token more than once to get the response from google Api , you will get that error . Check this error reference https://developers.google.com/recaptcha/docs/verify?hl=en
I been googling looking for answers specifically similar to your use case.
reCaptcha V3 does not have reset API.
I solve the problem by when Password or Email authentication failed on your side, execute this again on your AJAX if failed. So that the value get replace with new g-token without reloading the site again, since following Google Documentation like me, the script execute on ready at your "signin page"
grecaptcha.ready(function() {
grecaptcha.execute('abhkdfhlasdfhldafhlashflasdhl', {action: 'submit'}).then(function(token) {
document.getElementById('g-token').value = token;
});
});
The issue is likely caused because the script is running more than once.
Is there anywhere else in the code that could be submitting the form more than once?
I had a similar issue and a simple console log in the results part of the JS showed that it was being printed twice i.e. the form was submitting twice.
If it is not a code issue, a user may be double clicking the button. You could do a simple on click event to disable the button and this would remove the error.

When using ajax POST for form in codeigniter, not passing through data

I am trying to post data through my website via ajax, however for some reason it seems to echo the success message but does not get the mobile field data. it's just blank. When i inspect with firebug, it gives the response, but the POST tab is empty.
My controller contains the following :
function submit()
{
//set validation rule
// get post data
$emailid = $this->input->post('mobile');
// write your database insert code here
echo "<div class='alert'>Thanks for Subscribing! Please stay tuned to get awesome tips...</div> here is $emailid";
}
And my view contains :
<label>Mobile</label>
<input type="number" name="mobile" id="mobile" class=" form-control" />
<button type ="submit" id="submit" name="submit" class="btn btn-info btn-block" /> NEXT </button>
The JS
<script type="text/javascript">
$("#submit").click(function(e) {
e.preventDefault();
var mobile = $("mobile").val();
$.ajax({
url: "https://cheddarplatform.com/complete/submit",
method: "POST",
data: {mobile: mobile},
success: function(data) {
$("#message").html(data);
},
error: function() {
alert("Please enter valid email id!");
}
});
});
</script>
$("mobile") is not a proper selector, as you do not have a HTML element of that type anywhere. Probably you want to use $("#mobile") and have a look at your browser's network tab to find this error easier the next time

Categories