Entering recaptcha only once on form validation fail? - php

I have a form which has a few fields and a recaptcha code at the end.
When the user submits the form, the recaptcha field is validated along with the other fields on server side (PHP). If the any of the fields are invalid, the user is redirected to the same form with errors.
However, the problem is : The user has to enter the recatpcha again.
Is there any way I can NOT ask the user to enter the recaptcha again if the form validation fails but captcha validation is successful ?

Sure there is. You could store the validation success of the recaptcha into the session (or a cookie, or a database) and then hide the recaptcha if the indication is there. On the serverside you simply have to check if either the recaptcha is correct or the indication is valid.
You also have to make sure that a valid recaptcha cookie can only be used once, because if not the spammer can simply sent the cookie information over and over again and work around the recaptcha.
My idea is to store a timestamp within the session under a key like "recaptcha_success" and then check if the timestamp is not older than a few minutes (whatever fits your needs). If it's not, work around the recaptcha by not validating it again. If the form is valid, remove the key so the next time the user wants to use the form he has to enter the recaptcha again.

Without seeing your code or how it's set up exactly the simplest thing I can think of is to use a PHP session:
File that receives form data (assumed POST)
session_start();
foreach($_POST as $key=>$val)
{
if($key == "captcha" || $_SESSION['captcha_valid'] != 1)
{
//validate captcha
if(captcha is valid)
{
$_SESSION['captcha_valid'] = 1;
}
}
}
File that contains the form
session_start();
echo "<form method='yourphpfile.php' method='post'>"
if(!isset($_SESSION['captcha_valid']) || $_SESSION['captcha_valid'] != 1)
{
//add captcha code
}
</form>

Yes - set the session variable that captcha was entered successfully and don't display recaptcha form.

you can verify by setting session var like this
<?php
// captcha is already submitted so no need to verify again,
if(!isset($_SESSION['human_signup']) || (time() - $_SESSION['human_signup'] > 300)){
require_once('admin/recaptcha/recaptchalib.php');
// Get a key from https://www.google.com/recaptcha/admin/create
$publickey = 'your publickey';
$privatekey = 'your privatekey';
# the response from reCAPTCHA
$resp = null;
$resp = recaptcha_check_answer ($privatekey,
$_SERVER["REMOTE_ADDR"],
$_POST["recaptcha_challenge_field"],
$_POST["recaptcha_response_field"]);
if (!$resp->is_valid) {
// What happens when the CAPTCHA was entered incorrectly
$errors[] = 'The CAPTCHA wasn\'t entered correctly, please try again';
}else{
$_SESSION['human_signup'] = time();
$_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
}
}
and then on html form do something like this to show captcha form.
<?php
if (!isset($_SESSION['human_signup']) || (time() - $_SESSION['human_signup'] > 300)){ ?>
<label class="control-label">CAPTCHA</label>
<script type="text/javascript"> var RecaptchaOptions = {theme : 'white' }; </script>
<script type="text/javascript" src="http://www.google.com/recaptcha/api/challenge?k=your key"></script>
<noscript>
<iframe src="http://www.google.com/recaptcha/api/noscript?k=your key"
height="300" width="500" frameborder="0"></iframe><br>
<textarea name="recaptcha_challenge_field" rows="3" cols="40">
</textarea>
<input type="hidden" name="recaptcha_response_field"
value="manual_challenge">
</noscript>
<? } ?>
Make sure you remove the session once user registration is complete. like this.
<?php
//insert registration data in db i.e. registration is complete.
//unset the session used to hide the captcha.
unset($_SESSION['human_signup']);
?>
One less important feature to block user to input captcha manually and then using some script to automatically create accounts.
/* if user tries to register automatically by manually entering captcha and using scrpt to create accoutns */
<?php
if(isset($_SESSION['human_signup']) && ($_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT'])) {
unset($_SESSION['human_signup']);
unset($_SESSION['user_agent']);
#session_destroy();
#session_unset();
}
?>
hope this helps., if i missed something , please feel free to edit answer.

Related

How can I implement Google Recaptcha v3 in a PHP form?

I would like to insert a contact form the new version (V3) of Recaptcha.
I have looked for different solutions, but they only show part of the code, they are incomplete or I get an error, and most of the solutions found are very complicated for something so simple and I do not understand the code.
I have searched this and other forums to implement the new version of ReCaptcha (V3) in my forms.
I needed to know how to:
Insert it with JS
How to validate it with PHP
What new fields were needed in my form.
I did not find any simple solution, which would show me all these points, or it was too complicated for somebody who just wanted to insert a contact form on their website.
At the end, taking some code portions of multiple solutions, I use a simple and reusable code, in which you only have to insert the corresponding keys.
Here it is.
The basic JS code
<script src="https://www.google.com/recaptcha/api.js?render=your reCAPTCHA site key here"></script>
<script>
grecaptcha.ready(function() {
// do request for recaptcha token
// response is promise with passed token
grecaptcha.execute('your reCAPTCHA site key here', {action:'validate_captcha'})
.then(function(token) {
// add token value to form
document.getElementById('g-recaptcha-response').value = token;
});
});
</script>
The basic HTML code
<form id="form_id" method="post" action="your_action.php">
<input type="hidden" id="g-recaptcha-response" name="g-recaptcha-response">
<input type="hidden" name="action" value="validate_captcha">
.... your fields
</form>
The basic PHP code
if(isset($_POST['g-recaptcha-response'])){
$captcha=$_POST['g-recaptcha-response'];
}
else
$captcha = false;
if(!$captcha){
//Do something with error
}
else{
$secret = 'Your secret key here';
$response = json_decode(file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=".$secret."&response=".$captcha."&remoteip=".$_SERVER['REMOTE_ADDR']));
if($response->{'success'}==false)
{
//Do something with error
}
}
//... The Captcha is valid you can continue with the rest of your code
//... Add code to filter access using $response . score
if ($response->{'success'}==true && $response->{'score'} <= 0.5) {
//Do something to denied access
}
You have to filter access using the value of $response->{'score'}. It can takes values from 0.0 to 1.0, where 1.0 means the best user interaction with your site and 0.0 the worst interaction (like a bot). You can see some examples of use in ReCaptcha documentation.
You only have to add your keys, no more changes needed:
src="https://www.google.com/recaptcha/api.js?render=your reCAPTCHA site key here"
grecaptcha.execute('your reCAPTCHA site key here'
and
$secret = 'Your secret key here';
Obviously you also have to change the action of the form, in this example:
action = "your_action.php"
In the answer above, these lines need to be updated in order to be able to read the response values in PHP:
$response = json_decode(file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=".$secret."&response=".$captcha."&remoteip=".$_SERVER['REMOTE_ADDR']));
$response->{'success'}
$response->{'score'}
Looks like Google improved their docs since the first answers. Here is how I do it.
Client side integration in form:
The docs for this are here: https://developers.google.com/recaptcha/docs/v3
According to Google you should include the Recaptcha API on every page so that it can observe the user's behavior. So I added this line to the end of my footer which is included in every page (no parameters needed):
<script src="https://www.google.com/recaptcha/api.js"></script>
On the form you use a submit button like so:
<button class="g-recaptcha" data-sitekey="PASTE-YOUR-RECAPTCHA-SITE-KEY-HERE" data-callback="onSubmit" data-action="submit">Submit Form</button>
And add the following JavaScript function that submits the form:
function onSubmit() {
var form = document.forms[0]; // change this if you have multiple forms
if (/* possible client-side form validation code here */) {
form.submit();
}
}
Server side validating code:
The docs for this are here: https://developers.google.com/recaptcha/docs/verify
For this I created a helper function:
/**
* Checks if the current script has a valid Google Captcha response token.
* #returns True, if the script has a valid repsonse token, otherwise false.
*/
function isCaptchaValid()
{
$captcha = isset($_POST['g-recaptcha-response']) ? $_POST['g-recaptcha-response'] : false;
if (!$captcha) {
return false;
}
$postdata = http_build_query(
array(
"secret" => "PASTE-YOUR-RECAPTCHA-SECRET-KEY-HERE",
"response" => $captcha,
"remoteip" => $_SERVER["REMOTE_ADDR"]
)
);
$opts = array(
'http' =>
array(
"method" => "POST",
"header" => "Content-Type: application/x-www-form-urlencoded",
"content" => $postdata
)
);
$context = stream_context_create($opts);
$googleApiResponse = file_get_contents("https://www.google.com/recaptcha/api/siteverify", false, $context);
if ($googleApiResponse === false) {
return false;
}
$googleApiResponseObject = json_decode($googleApiResponse);
return $googleApiResponseObject->success;
}
No need to check any score value as done in the other answers. According to the docs there isn't even a score property in the response object. I checked it and there is one, but I don't use it.
You should call it at the beginning of the PHP script that handles your form submit like so:
if (!isCaptchaValid()) {
die("STOP! You are a bot."); // or do something else
}

Invisible reCaptcha PHP vs JS verification

I have a simple question.
I added a custom form with Google Invisible Captcha to avoid spam.
Currently I have a something like this (just works fine):
<script>
function onSubmit(token) {
document.getElementById("demo-form").submit();
}
</script>
<form id='demo-form' action="" method="POST">
<button class="g-recaptcha" data-sitekey="your_site_key" data-callback='onSubmit'>Submit</button>
<br/>
</form>
But to make it more "secure" I can add extra layer of verification via $_POST response as described below.
if( isset($_POST['g-recaptcha-response']) && !empty($_POST['g-recaptcha-response']) ) {
// verify response
$verifyResponse = file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret='.$secret_key.'&response='.$_POST['g-recaptcha-response']);
$responseData = json_decode($verifyResponse);
// if all good => proceed registration
if ($responseData->success) {
Do you think it worth adding this extra verification via PHP or it's fine to leave it as is ?

On form submit redirects to same page -Jquery validation engine

I have implemented jquery validation engine plugin for form validations. The problem is with ajax validation for input. Whenever the form is submitted or submit button is clicked before the ajax success message is shown, it is redirecting to same page, which means the php script on form submit is not calling.
eg:
I have a email field
<input class="validate[required,ajax[EmailCallPhp]]" type="text" name="email" />
When we enter the email and click submit button immediately before and any success/error if the ajax returns false form is not submitted but if its successful, it submits the form but the php script on form submit does not work and redirects to same page..
$(document).ready(function(){
$("#RegFb").validationEngine();
});
code calls ajax:
"EmailCallPhp": {
"url": "valEmail.php", //register email validation
// you may want to pass extra data on the ajax call
"extraData": "name=eric",
// if you provide an "alertTextOk", it will show as a green prompt when the field validates
"alertTextOk": "* OK",
"alertText": "* Email Already Exist",
"alertTextLoad": "* Validating, please wait"
}
valEmail.php code
$email=$_REQUEST['fieldValue'];
$emailId=$_REQUEST['fieldId'];
$validateError= "This username is already taken";
$validateSuccess= "This username is available";
/* RETURN VALUE */
$arrayToJs = array();
$arrayToJs[0] = $emailId;
$stmt = $db->prepare("SELECT email FROM table WHERE email = :email");
$stmt->execute(array(':email'=>$email));
if($stmt->rowCount() == 0){ // validate??
$arrayToJs[1] = true; // RETURN TRUE
echo json_encode($arrayToJs); // RETURN ARRAY WITH success
}else{
for($x=0;$x<1000000;$x++){
if($x == 990000){
$arrayToJs[1] = false;
echo json_encode($arrayToJs); // RETURN ARRAY WITH ERROR
}
}
}
Thanks!

PHP form validation alerts without redirecting page

Basically whats happening is I have a php form to send an email. There are several different validation steps all along the way, which all work great. What i'd like to do is have a javascript alert pop up if there is a validation error when the form is submitted. I have this working with the following php:
// Validate email
if(!filter_var($EmailFrom, FILTER_VALIDATE_EMAIL))
{
echo "<script language=javascript>alert('Please Use a Valid Email Address')</script>";
exit;
}
The alert pops up but the page redirects to domain.com/sendemail.php which leaves the user with a blank page. I'd really like to have the alerts pop up without reloading the page. How would I do this?
You can use ajax to accomplish this. But if you don't want to use ajax, instead doing an exit on error, you could redirect back to the form page along with a query string parameter.
header("Location: http://www.example.com/form.php?error=1");
And on your form page you could put the script withing php if. Something like
<?php if(isset($_GET['error']) && $_GET['error']==1): ?>
<script>
....
</script>
<?php endif; ?>
That would achieve what you are looking for. In fact you can perform multiple checks and set error based on your checks. But I would still suggest Ajax will give a better user experience.
Edit: Super easy solution, use jQuery form plugin : http://jquery.malsup.com/form/
I do something similar in some of my web apps, you might find it useful.
I do my validation server side and if I encounter an error I do this :
json_die(array(
'status' => 'error',
'message'=> 'Your error message'
));
and for success :
json_die(array(
'status' => 'success',
'message'=> 'Your success message'
));
The json_die is function is :
function json_die($array) {
header("content-type: application/json");
die(json_encode($array, true));
}
Then on the front end I do something like this:
$.post('/your_url', {
'your': vars
}, function (r) {
if(r.status == 'success') {
alert(r.message);
} else if (r.status == 'error') {
alert(r.message);
//handle error
} else {
alert('server exploded / no connection');
}
},'json');
This is a script I used in some forms I created to validate them fast. It's very simple and effective, I hope it helps you.
<script type="text/javascript">
function validate(){
emailfilter = /^([a-zA-Z0-9_\.\-])+\#(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
condition = 1;
mensaje = "Complete: ";
//Validate 1st input (Check if empty)
if (document.formname.forminput1.value.length==0){
condition = 0;
msg = msg + "-Input 1 is empty "
}
//Validate 1nd input (Check email)
if (!emailfilter.test(document.formname.forminput1.value)) {
condition = 0;
msg = msg + "-Input 1 has a invalid email adresss "
}
if (condition == 0){
alert(msg)
document.formname.forminput1.focus()
return 0;
}
//send
alert("Form sended.");
document.formname.submit();
}
</script>

captcha with php session variables + jquery validation

i'm working on a contact form.
i use this for form validation: http://plugins.jquery.com/project/form-validation-and-hints
and i use a captcha that stores the code in $_SESSION['captchacode'] variable.
what i'm trying to accomplish is to simply check using the jquery validator if user entered good captcha code.
that's how check function works:
function isTypeValid( type, value ) {
var cap = <?php echo $SESSION["captchacode"];?>;
if( type == classprefix + 'Text' ) {
return true;
}
if( type == classprefix + 'Captcha' ) {
if(value==cap){
return (true);
}else{
return false;
}
}
}
i searched a few threads here and elsewhere and that's where i got
var cap = <?php echo $SESSION["captchacode"];?>;
from.
i've also tried this:
var cap = "<%= Session['captchacode'] %>";
and it didn't help...
any ideas?
Don't use jquery for captcha validation.
Validate it on the server side.
also, the way you choose (with writing captcha value in the body of the script) is quite funny but it's merely a gift to possible spammer.
You can use remote method of jquery validation plugin to check captcha. You can see example here -
http://jquery.bassistance.de/validate/demo/captcha

Categories