Run php code on confirmation of javascript - javascript

An email is sent when I update the status. Issue is, it has many other fields and whenever I update anyone of them, it shoots the email again. All I want to ask for confirmation if you want to send an email or no. I did use ajax to do it but in console, it says email sent but I don't get anything in inbox.
Javascript code
<script type="text/javascript">
function send_email(){
var delete_confirmed=confirm("Are you sure you want to send email?");
if (delete_confirmed==true) {
$.ajax({
type: "POST",
url: 'email.php',
data:{action:'call_this'},
success:function() {
console.log('email sent');
}
});
}}
</script>
email.php
if(isset($_POST['status']) == 'completed' && $_POST['action'] == 'call_this'){
$cmail = new PHPMailer;
$cmail->isSMTP(); // Set mailer to use SMTP
$cmail->SMTPAuth = true; // Enable SMTP authentication
$cmail->Host = $smtp_server; // Specify main and backup SMTP servers
$cmail->Username = $username; // SMTP username
$cmail->Password = $password; // SMTP password
$cmail->SMTPSecure = "ssl"; // Enable TLS encryption, `ssl` also accepted
$cmail->Port = 465; // TCP port to connect to
$cmail->setFrom("example#example.com", "Example");
$q_mail = "SELECT * FROM order_details WHERE order_id = '$_GET[edit_id]'";
$r_mail = mysqli_query($conn, $q_mail);
while ($r_rows = mysqli_fetch_assoc($r_mail)) {
$cmail->addAddress($r_rows['email'], $r_rows['firstname']); // Add a recipient
$cmail->isHTML(true); // Set email format to HTML
$bodyContent = 'test message';
$cmail->Subject = "test subject" ;
$cmail->Body = $bodyContent;
if(!$cmail->send()) {
$error = $cmail->ErrorInfo;
} else {
$error = 'Message has been sent';
}
}
}
form HTML
<div class="col-md-2" style="padding-left:0px;" ></br>
<input type="submit" class="btn navbar-bar btn-xs btn-success" name="status" onclick="send_email();" value="Update">
</div>

In your PHP you're checking for isset($_POST['status']) == 'completed', which will always be false. isset will only return a boolean. Also, it will always be false as you're not passing in the status to email.php, only the action. You need to make a couple of changes to fix this. The first is to your javascript:
$.ajax({
type: "POST",
url: 'email.php',
data:{action:'call_this', status: 'completed'},
success:function() {
console.log('email sent');
}
});
The second is to the PHP script:
if( ( isset($_POST['status']) && $_POST['status'] == 'completed' ) && $_POST['action'] == 'call_this'){

The fact that you are receiving some sort of feedback from the ajax request suggests the problems lie elsewhere. The line below was incorrect - you were missing quotes from the edit_id - and when accessing $_GET / $_POST variables within a string I always surround with curly braces as below.
$q_mail = "SELECT * FROM `order_details` WHERE `order_id` = '{$_GET['edit_id']}';";
It could just be that this was misstyped when you posted the question but maybe not - check the error logs whenever things do not happen as expected.
And if you look at this thread there is a good example of using try/catch to deduce where things are going wrong.

Related

Google recaptcha v3 and still able to send spam request

I am using Google recaptcha v3 in my site by following official guideline.
but when i opened Browser Console and write the following code
function flood(){
var chars = 'abcdefghijklmnopqrstuvwxyz1234567890';
var string = '';
for(var ii=0; ii<15; ii++){
string += chars[Math.floor(Math.random() * chars.length)];
}
email = document.getElementById("email");
email.value = string+"#gmail.com";
$("#submitBtn").trigger("click");
}
setInterval(flood, 1000);
Here you can see in image preview about 37 spam requests sent to server successfully.
Image
Anyway to avoid this?
Thanks
Follwoing JavaScript code i use in frontend.
$('#newsletterForm').submit(function(event) {
$("#submitBtn").attr("disabled", true);
$("#ajax-response").fadeIn();
event.preventDefault();
var email = $('#email').val();
grecaptcha.ready(function() {
grecaptcha.execute('6LfX1N4bAAAAABRp1LK3Io5u8pq7xn9iYqiXioru', {action: 'process'}).then(function(token) {
$('#newsletterForm').prepend('<input type="hidden" id="token" name="token" value="' + token + '">');
$('#newsletterForm').prepend('<input type="hidden" id="action" name="action" value="process">');
//$('#newsletterForm').unbind('submit').submit();
$.post("./process.php", {
email: $("#email").val(),
token: $("#token").val(),
action: $("#action").val()
}, function (response) {
console.log(response);
$("#message").text(response);
$("#submitBtn").attr("disabled", false)
$("#ajax-response").fadeIn();
})
});;
});
});
and backend in php
// other code...
// use the reCAPTCHA PHP client library for validation
$recaptcha = new \ReCaptcha\ReCaptcha(RECAPTCHA_V3_SECRET_KEY);
$resp = $recaptcha->setExpectedAction($action)
->setScoreThreshold(0.5)
->verify($token, $_SERVER['REMOTE_ADDR']);
if ($resp->isSuccess()) { // success process }
else {// spam request}
I guess you misunderstood the concept... You can never prevent people to send requests to your server with javascript code... You have to always check on the server side too... That's why you are using reCaptcha like solutions. This makes sure that the request comes from your original site / frontend using reCaptcha with a valid token... If it's not valid you won't be doing any "source expensive" operations on the serverside.

PHP - redirect user from page meant for asynchronous JavaScript requests [duplicate]

I would like to check server-side if a request to my php page is an ajax request or not.
I saw two ways to do this:
First way: sending a GET parameter in the request which tells the page that this is an AJAX request (=mypage.php?ajax)
mypage.php:
if(isset($_GET['ajax'])) {
//this is an ajax request, process data here.
}
Second way: set a header to the xmlHttpRequest:
client-side js:
xmlHttpRequestObject.open(“GET”,url,true);
xmlHttpRequestObject.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
mypage.php:
if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest' ) {
//request is ajax
}
The fact is, those two ways of doing it can easily be hacked, so it's not secure to check if i get an AJAX request like this.
How can i check if i'm receiving an AJAX request?
Example from an archived tutorial:
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')
{
exit;
}
continue;
This checks if the HTTP_X_REQUESTED_WITH parameter is not empty and if it's equal to xmlhttprequest, then it will exit from the script.
There is no sure-fire way of knowing that a request was made via Ajax. You can never trust data coming from the client. You could use a couple of different methods but they can be easily overcome by spoofing.
From PHP 7 with null coalescing operator it will be shorter:
$is_ajax = 'xmlhttprequest' == strtolower( $_SERVER['HTTP_X_REQUESTED_WITH'] ?? '' );
Set a session variable for every page on your site (actual pages not includes or rpcs) that contains the current page name, then in your Ajax call pass a nonce salted with the $_SERVER['SCRIPT_NAME'];
<?php
function create_nonce($optional_salt='')
{
return hash_hmac('sha256', session_id().$optional_salt, date("YmdG").'someSalt'.$_SERVER['REMOTE_ADDR']);
}
$_SESSION['current_page'] = $_SERVER['SCRIPT_NAME'];
?>
<form>
<input name="formNonce" id="formNonce" type="hidden" value="<?=create_nonce($_SERVER['SCRIPT_NAME']);?>">
<label class="form-group">
Login<br />
<input name="userName" id="userName" type="text" />
</label>
<label class="form-group">
Password<br />
<input name="userPassword" id="userPassword" type="password" />
</label>
<button type="button" class="btnLogin">Sign in</button>
</form>
<script type="text/javascript">
$("form.login button").on("click", function() {
authorize($("#userName").val(),$("#userPassword").val(),$("#formNonce").val());
});
function authorize (authUser, authPassword, authNonce) {
$.ajax({
type: "POST",
url: "/inc/rpc.php",
dataType: "json",
data: "userID="+authUser+"&password="+authPassword+"&nonce="+authNonce
})
.success(function( msg ) {
//some successful stuff
});
}
</script>
Then in the rpc you are calling test the nonce you passed, if it is good then odds are pretty great that your rpc was legitimately called:
<?php
function check_nonce($nonce, $optional_salt='')
{
$lasthour = date("G")-1<0 ? date('Ymd').'23' : date("YmdG")-1;
if (hash_hmac('sha256', session_id().$optional_salt, date("YmdG").'someSalt'.$_SERVER['REMOTE_ADDR']) == $nonce ||
hash_hmac('sha256', session_id().$optional_salt, $lasthour.'someSalt'.$_SERVER['REMOTE_ADDR']) == $nonce)
{
return true;
} else {
return false;
}
}
$ret = array();
header('Content-Type: application/json');
if (check_nonce($_POST['nonce'], $_SESSION['current_page']))
{
$ret['nonce_check'] = 'passed';
} else {
$ret['nonce_check'] = 'failed';
}
echo json_encode($ret);
exit;
?>
edit: FYI the way I have it set the nonce is only good for an hour and change, so if they have not refreshed the page doing the ajax call in the last hour or 2 the ajax request will fail.
This function is used from the Yii PHP Framework to check for an AJAX call.
public function isAjax() {
return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest';
}
$headers = apache_request_headers();
$is_ajax = (isset($headers['X-Requested-With']) && $headers['X-Requested-With'] == 'XMLHttpRequest');
Try below code snippet
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH'])
&& strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')
{
/* This is one ajax call */
}
try to use HTTP_SEC
if (!array_key_exists("HTTP_SEC_FETCH_SITE",$_SERVER) || $_SERVER["HTTP_SEC_FETCH_SITE"] != "same-origin")
die(header("HTTP/1.1 404 Not Found"));
if (!array_key_exists("HTTP_SEC_FETCH_MODE",$_SERVER) || $_SERVER["HTTP_SEC_FETCH_MODE"] != "cors")
die(header("HTTP/1.1 404 Not Found"));
if (!array_key_exists("HTTP_SEC_FETCH_DEST",$_SERVER) || $_SERVER["HTTP_SEC_FETCH_DEST"] != "empty")
die(header("HTTP/1.1 404 Not Found"));
You could try using a $_SESSION variable to make sure that a request was made from a browser. Otherwise, you could have the request sent through a database or file [server-side].

How do I resend data from previous url after reCAPTCHA passed in the same page?

Data sent from this
www.example.com/modules/liaise/index.php?form_id=xxx
In normal condition, after submit, the page redirects to
www.example.com/modules/liaise/index.php
and sends mail.
Wantedly, I placed the reCAPTCHA in the same file (index.php).
Google captcha :
require_once "recaptchalib.php";
// your secret key
$secret = "secret key";
// empty response
$response = null;
// check secret key
$reCaptcha = new ReCaptcha($secret);
// if submitted check response
if ($_POST["g-recaptcha-response"]) {
$response = $reCaptcha->verifyResponse(
$_SERVER["REMOTE_ADDR"],
$_POST["g-recaptcha-response"]
);
}
if ($response != null && $response->success) {
//send mail
} else {
echo '
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>
<div id="html_element"></div>
<script>
var onloadCallback = function() {
grecaptcha.render("html_element", {
"sitekey" : "sitekey",
"callback" : correctCaptcha
});
};
var correctCaptcha = function(response) {
location.reload();
};
</script>';
}
Whenever I pass reCAPTCHA and page reloads, reCAPTCHA shows again.
I know data from previous page www.example.com/modules/liaise/index.php?form_id=xxx is still there by using
foreach($_POST as $key=>$value)
{
echo "$key=$value";
}
Is there any way by which I can resend data from previous url after reCAPTCHA is passed in the same page?
I am newbie in coding. Please be specific.
Thank you so much!
If your talking about re-sending your data as mail you can use something like this:
if (isset($_POST['form-input'])) {
// Send mail
}
and every time you reload the page and the Post data is not null or blank, it will run that code.
If you are wanting the reCAPTCHA to reload as success, I would say that's defeats the security of reCAPTCHA
Also I see that you have a typo esle should be else.

Email submit through Mailchimp returning error, Javascript and php

I am hoping this is a simple issue. I am using the Mailchimp API to submit a simple email signup form from my website. I am trying to learn javascript right now, so I am trying to do the httprequest and callback without jQuery. Basically, I am trying to convert this jQuery sample I found online to vanilla Javascript. But there is something (several things?) wrong with my javascript that I don't understand.
EDIT: When the form is submitted, I am taken to the email-validate.php page, and show the following error object returned by MailChimp.
{"type":"http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/","title":"Invalid Resource","status":400,"detail":"The resource submitted could not be validated. For field-specific details, see the 'errors' array.","instance":"","errors":[{"field":"","message":"Required fields were not provided: email_address"},{"field":"email_address","message":"Schema describes string, NULL found instead"}]}
jQuery
Found here (this actually throws an ajax(...).success is not a function error in the console but still submits the form, FWIW)
$('document').ready(function(){
$('.mc-form').submit(function(e){
//prevent the form from submitting via the browser redirect
e.preventDefault();
//grab attributes and values out of the form
var data = {email: $('#mc-email').val()};
var endpoint = $(this).attr('action');
//make the ajax request
$.ajax({
method: 'POST',
dataType: "json",
url: endpoint,
data: data
}).success(function(data){
if(data.id){
//successful adds will have an id attribute on the object
alert('thanks for signing up');
} else if (data.title == 'Member Exists') {
//MC wil send back an error object with "Member Exists" as the title
alert('thanks, but you are alredy signed up');
} else {
//something went wrong with the API call
alert('oh no, there has been a problem');
}
}).error(function(){
//the AJAX function returned a non-200, probably a server problem
alert('oh no, there has been a problem');
});
});
});
My Javascript (that doesn't work)
document.addEventListener("DOMContentLoaded", function() {
document.getElementById("mc-form", function submit(e){
e.preventDefault();
var data = {"email": document.getElementById("mc-email").value};
var endpoint = document.getElementById("mc-form").getAttribute('action');
function formSubmit(callback){
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState === 4) {
if (request.status === 200) {
//Parse returned string into an object, then pass the object to the callback function.
var response = JSON.parse(request.responseText);
callback(response);
} else {
console.log('JSON request error');
}
}
}
request.open("POST", endpoint , true);
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
request.send(data);
}
function formResponse(response){
if(response.id){
//successful adds will have an id attribute on the object
alert('Thank you for signing up for Launch Alerts!');
} else if (response.title == 'Member Exists') {
//MC wil send back an error object with "Member Exists" as the title
alert('You are already signed up for Launch Alerts!');
} else {
//something went wrong with the API call
alert('Something went wrong. Please resubmit the form!');
}
}
formSubmit(formResponse);
})
});
My html
<form class="mc-form" method="POST" action="./email-validate.php">
<h2 class="launch-alerts">Never miss a launch with Launch Alerts</h2>
<label for="mc-email">Email Address:</label>
<input type="email" id="mc-email" name="mc-email" autofocus="true" required/>
<input type="text" value="pending" id="status" name="status" hidden/>
<input type="submit" value="Submit">
</form>
It uses a php file to validate and submit the form, as can be seen on the link above. The html and php work to submit the form when using the jQuery script, but not my javascript, which means there is something wrong with my script, but I am too new with javascript to fully understand what it is I am trying to do, and what I am doing wrong.
Thanks!
EDIT 2:
The PHP code (copied directly from here
<?php
//fill in these values for with your own information
$api_key = 'xxxxxxxxxxxxxxxxxxxxxxxx';
$datacenter = 'xxxxx';
$list_id = 'xxxxxxxxx';
$email = $_POST['email'];
$status = 'pending';
if(!empty($_POST['status'])){
$status = $_POST['status'];
}
$url = 'https://'.$datacenter.'.api.mailchimp.com/3.0/lists/'.$list_id.'/members/';
$username = 'apikey';
$password = $api_key;
$data = array("email_address" => $email,"status" => $status);
$data_string = json_encode($data);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, "$username:$api_key");
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($data_string))
);
$result=curl_exec ($ch);
curl_close ($ch);
echo $result;
?>
The data argument to request.send() must be a URL-encoded string, you're passing an object. jQuery does this conversion automatically for you; when you do it yourself, you have to do that yourself as well.
var data = "email=" + encodeURIComponent(document.getElementById("mc-email").value);
You're also not adding your submission function to the form's submit event correctly. It should be:
document.getElementById("mc-form").addEventListener("submit", function submit(e){
You can add URL Parameters manually to the URL:
var endpoint = document.getElementById("mc-form").getAttribute('action') +
"?email=" + document.getElementById("mc-email").value;
And then only do
request.send();
without the data in it.

Secure ajax GET/POST request for server

suppose I work with some kind of API and my file server.php handles the connection to the API service. on my client side I use AJAX call like this:
$http({
url : 'server/server.php',
method : 'GET',
data : { getContent : true }
});
in my server.php I handle it like this:
if(isset($_GET['getContent'])){
$content = get_content();
}
function get_content(){...}
i just wonder what prevents any one send AJAX call with the same getContent parameter and get all my data? how can i secure it and make sure only calls from my application will get the relevant data back?
thank you!
I guess you are concerned about CSRF attacks. Read more about this here: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Prevention_Cheat_Sheet
One of the mostly used option to secure your request will be:
- Generate a token and send it with the request for a session. This token can be identified by your WebServer as originating from a specific client for a specific session
2022 Update
This is a 7 year old post and the link in the link-only "accepted" answer is broken.
So, I'm going to offer a basic walkthrough and a complete model.
Remember, the $_SESSION will be preserved even in the AJAX handler, if it's all from the same domain. So, you can use that to check things.
Use $_POST
I presume you're using $_POST and not $_GET since you're concerned about security. If not, then much of this might not be important anyway.
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$post_method = true;
}
Ensure the $_SERVER['HTTP_REFERER'] is from your own site
if ( (!empty($_SERVER['HTTP_REFERER']))
&& ($_SERVER['HTTP_REFERER'] === "https://example.tld/my_sending_page.php") ) {
$from_my_server = true;
}
If you're not sure what this should be, run a test on your own server to see what this should be:
echo $_SERVER['HTTP_REFERER'];
Verify XMLHTTP/AJAX request via $_SERVER array
if ( (!empty($_SERVER['HTTP_X_REQUESTED_WITH']))
&& ( strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') ) {
$ajax = true;
} else {
$ajax = false;
}
Use a token
This is the hard part, but not too hard.
Create the token
Set the token in $_SESSION
Put the token in the AJAX header
AJAX responder: confirm the AJAX header token with the $_SESSION token
send_from_me.php
// Create the token
//$token = md5(rand(10000,99999)); // Not recommended, but possible
$token = bin2hex(random_bytes(64));
// Store in SESSION
$_SESSION["token"] = $token;
// Assuming your AJAX is this
const AJAX = new XMLHttpRequest();
// This goes inside your AJAX function somewhere before AJAX.send
//
AJAX.setRequestHeader("ajax-token", "<?php echo $_SESSION["token"]; ?>");
//
// That creates $_SERVER['HTTP_AJAX_TOKEN'] which we can use later
ajax_responder.php
session_start(); // Must have
if ($_SERVER['HTTP_AJAX_TOKEN'] === $_SESSION["token"]) {
$token_match = true;
} else {
echo "No script kiddies!";
exit();
}
// Now it's safe for your AJAX responder to proceed
Let's put all of this into a working example
sending_from.php
<?php
session_start();
$token = bin2hex(random_bytes(64));
$_SESSION["token"] = $token;
?>
<!DOCTYPE html>
<html>
<head>
<title>My AJAX Sender</title>
</head>
<body>
<script>
function ajaxFormData(formID, postTo, ajaxUpdate) {
// Bind a new event listener every time the <form> is changed:
const FORM = document.getElementById(formID); // <form> by ID
const FD = new FormData(FORM); // Bind to-send data to form element
const AJAX = new XMLHttpRequest(); // AJAX handler
// This runs when AJAX responds
AJAX.addEventListener( "load", function(event) {
document.getElementById(ajaxUpdate).innerHTML = event.target.responseText;
} );
// This runs if AJAX fails
AJAX.addEventListener( "error", function(event) {
document.getElementById(ajaxUpdate).innerHTML = 'Oops! Something went wrong.';
} );
// Add your token header
AJAX.setRequestHeader("ajax-token", "<?php echo $_SESSION["token"]; ?>");
// Open the POST connection
AJAX.open("POST", postTo);
// Data sent is from the form
AJAX.send(FD);
}
</script>
<div id="ajax_changes">Replace me with AJAX</div>
<form id="ajaxForm">
<input type="text" name="the_simple_response">
<button type="button" onclick="ajaxFormData('ajaxForm', 'ajax_responder.php', 'ajax_changes');">Send my Secure AJAX</button>
</form>
</body>
</html>
ajaxcheck.inc.php
<?php
$mysite = 'https://example.tld';
// All in one test
if (($_SERVER['REQUEST_METHOD'] == 'POST')
&& ((!empty($_SERVER['HTTP_REFERER'])) && ($_SERVER['HTTP_REFERER'] === "$mysite/my_sending_page.php"))
&& ((!empty($_SERVER['HTTP_X_REQUESTED_WITH'])) && ( strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest'))
&& ($_SERVER['HTTP_AJAX_TOKEN'] === $_SESSION["token"])) {
$ajax_legit = true;
} else {
echo "No script kiddies!";
exit();
}
?>
ajax_responder.php
<?php
session_start();
// Do all that checking we're learning about by neatly including the file above
require_once('ajaxcheck.inc.php');
// Process your AJAX
echo $_POST['the_simple_response'];
?>
i just wonder what prevents any one send AJAX call with the same getContent parameter and get all my data?
Nothing. This URL is public thus anyone can make requests to it.
how can i secure it and make sure only calls from my application will get the relevant data back?
You can pass additional data (for example, some hashed value) that is verified on the server side.
$http({
url : 'server/server.php',
method : 'GET',
data : { getContent : true, hash : '0800fc577294c34e0b28ad2839435945' }
});
and
if(isset($_GET['getContent']))
{
if(isset($_GET['hash']) && validateHash($_GET['hash']))
{
$content = get_content();
}
}
function get_content(){...}
i just wonder what prevents any one send AJAX call with the same getContent parameter and get all my data?
The same way you would protect the data in any other request (e.g. with user authentication). There's nothing special about Ajax in regards to HTTP as far as the server is concerned.
how can i secure it and make sure only calls from my application will get the relevant data back?
You can't. The user can always inspect what their browser is asking the server for and replicate it.
Generally, people authenticate users rather than applications.

Categories