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
}
Related
I tried implementing Recaptcha V3 on one of our websites forms recently, but ran in to an error where it wouldn't let some users submit the form as it coming back with the error message "You have been detected as a bot..." in the code below.
I printed all the form submissions to a log file and every time it failed, the $recaptcha->success, $recaptcha->action and $recaptcha->score are always empty.
I found that quite often it would work for a user and send the message.
I tested the form myself and most of the time it worked ok, but I noticed if I kept trying the submit the form several times, it would occassionally fail and return the error. When it fails the $recaptcha->success, $recaptcha->action and $recaptcha->score are always empty.
I also noticed $_POST['recaptcha_response'] seems to be empty in these instances even though it passes the first isset if statement.
//verify google captcha v3
if(isset($_POST['recaptcha_response'])){
//build request
$recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify';
$recaptcha_secret = 'MY_SECRET_KEY';
$recaptcha_response = $_POST['recaptcha_response'];
//get verify response data
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://www.google.com/recaptcha/api/siteverify',
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => [
'secret' => $recaptcha_secret,
'response' => $recaptcha_response
],
CURLOPT_RETURNTRANSFER => true
]);
$output = curl_exec($ch);
curl_close($ch);
$recaptcha = json_decode($output);
// Take action based on the score returned:
if ($recaptcha->success && $recaptcha->action == 'reportadvert' && $recaptcha->score > 0.1){
// Verified - success
$save['captcha'] = "1";
} else {
// Not verified - show form error
$errors['captcha'] = "You have been detected as a bot and blocked from sending this report for security reasons, please try again shortly or Contact us if you are still having issues.";
}
} else {
$errors['captcha'] = "You have been detected as a bot and blocked from sending this report for security reasons, please try again shortly or Contact us if you are still having issues.";
}
Here is My Form (with some of my other fields removed). Please note that my form/page is contained in one php script, and I post the form to the same php script :
<form method="post">
<input type="hidden" name="recaptcha_response" id="recaptchaResponse">
<button type="submit" name="SendEm">Report Advert</button>
<input type="hidden" name="submitted" value="TRUE" />
</form>
I include the javascrit on the top of the page, I have removed my site key when posting this :
<script src="https://www.google.com/recaptcha/api.js?render=MY_SITE_RECAPTCHA_KEY"></script>
grecaptcha.ready(function() {
grecaptcha.execute('MY_SITE_RECAPTCHA_KEY', {action: 'reportadvert'}).then(function(token) {
var recaptchaResponse = document.getElementById('recaptchaResponse');
recaptchaResponse.value = token;
});
});
I would check error-codes in siteverify response. If there is an error, you will not get action and score params in response.
Site Verify Response, Error code reference
I am working on an extension to integrate a third party API into Magento. The steps included are to fill out a form on our site. When the user clicks submit the API pre-fills a form on their site which the user then approves. A few get string variables are sent over to the page on our site, which trigger a second API call (behind the scenes) that retrieves a token. Once the token is created I am then saving the token to a second hidden form and submitting it via this function:
function submitAccount() {
var formId = 'form-payment-submit';
var myForm = new VarienForm(formId, true);
var postUrl = '<?php echo $this->getUrl('marketplacepayment/marketplaceaccount/paymentsetup/') ?>';
if (myForm.validator.validate()) {
new Ajax.Updater(
{ success:console.log("form success") }, postUrl, {
method:'post',
asynchronous:false,
evalScripts:false,
onComplete:function(request, json) {
//submitButtonOn();
alert('success!');
},
parameters: $(formId).serialize(true),
}
);
}
}
The function in my module then handles saving the values to the database:
public function paymentsetupAction(){
if(!(empty($_POST['access']))){
// save tokens to db
$collection = Mage::getModel('marketplace/userprofile')->getCollection();
$collection->addFieldToFilter('mageuserid',array('eq'=>$_POST['userid']));
foreach($collection as $row){
$id=$row->getAutoid();
}
$collectionload = Mage::getModel('marketplace/userprofile')->load($id);
$collectionload->setaccesstoken($_POST['access']);
$collectionload->setrefreshtoken($_POST['refresh']);
$collectionload->setstripekey($_POST['key']);
$collectionload->save();
Mage::getSingleton('core/session')->addSuccess( Mage::helper('marketplace')->__('Your payment information has been sucessfully saved.'));
$this->_redirect('marketplacepayment/marketplaceaccount/payment');
}
}
The problem is that the tokens are not being saved but no errors are appearing. I can't write any of the info to the page since the submit is via AJAX so I am at a loss as to how to debug. Do you see anything immediately wrong with the paymentsetupAction? Or is there an easier way for me to see why it is not working?
The problem was with the $collection section - I was using the wrong database column names:
$collectionload = Mage::getModel('marketplace/userprofile')->load($id);
$collectionload->setaccess_token($_POST['access']);
$collectionload->setrefresh_token($_POST['refresh']);
$collectionload->setstripe_key($_POST['key']);
$collectionload->save();
Sorry for the random non important question.
I have a simple sign up mailing list form. It sends the user's email address to a store-address.php file. I use jQuery's ajax object to send a request to the php file and then receive a response.
The problem is I am not getting a response from the php file. I tried setting the cache to false in the request. I also tried send the information through the URL like so:
http://www.fifthtribe.com/inc/store-address.php?ajax=true&cache=false&email=test4%40gmail.com
When I do it that way it works and gives me a reponse. But when I do it through ajax it doesn't give me a response. This is from Firebug:
And here's snippets from my code:
HTML:
<div id="mlist">
<form id="mlist_form" method="POST" action="">
<input type="text" id="email" name="email" placeholder="Email" />
<input type="submit" id="submit_btn" value="Join" />
</form>
<div id="response"></div>
</div>
JQuery:
/* Add to mailing list */
$("#mlist_form").submit( function(e){
//$('#response').append('<div id="thanks-mce"><div id="mce-arrow"></div>Thanks for signing up!</div>');
var email = escape( $('#email').val() );
e.preventDefault();
data = {
"ajax" : "true",
"email" : email,
"cache" : "false"
}
$.ajax({
type: "POST",
url: 'inc/store-address.php',
data: data,
success: function( msg ){
// successfully signed up
$('#response').html( msg );
$('#email').val('');
},
error: function( err ){
// error while signing up
$('#response').html('Error: Is your email correct?');
}
});
return false;
});
PHP:
function storeAddress(){
// Validation
if(!$_GET['email']){ return "No email address provided"; }
if(!preg_match("/^[_a-z0-9-]+(\.[_a-z0-9-]+)*#[a-z0-9-]+(\.[a-z0-9-]+)*$/i", $_GET['email'])) {
return "Email address is invalid";
}
require_once('MCAPI.class.php');
// grab an API Key from http://admin.mailchimp.com/account/api/
$api = new MCAPI('xxxxxxxxxxxxxxxxxxxxxxxxxxxxx-us4');
// grab your List's Unique Id by going to http://admin.mailchimp.com/lists/
// Click the "settings" link for the list - the Unique Id is at the bottom of that page.
$list_id = "xxxxxxxx";
if($api->listSubscribe($list_id, $_GET['email'], '') === true) {
// It worked!
return 'Success! Check your email to confirm sign up.';
}else{
// An error ocurred, return error message
return 'Error: ' . $api->errorMessage;
}
}
// If being called via ajax, autorun the function
if($_GET['ajax']){ echo storeAddress(); }
?>
You realize that your PHP script is using GET method but your jQuery code is using the POST method right?
If the information is being posted to PHP, PHP will need to use $_POST to retrieve it. This explains why the URL method using $_GET works but the jQuery POST doesn't.
Good luck!
It looks like you're using $_GET instead of $_POST. Try echoing out the contents of $_REQUEST to see what that holds.
Debug your script!
Place an alert in the success and error parts of your script and then you will know whether the AJAX is working.
If not, you can then work your way up the document and see where the problem is.
In addition, the error here is quite simple. You are using $_GET in PHP and you are POSTING your data using AJAX, this will not show an error. Although the PHP document will not process your request because it is not being fed any parameters.
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
This question already has answers here:
PHP Redirection with Post Parameters
(8 answers)
Closed 9 years ago.
I'm working with PHP, and I'm making an action page which a form posts to. The page checks for errors, then if everything is fine, it redirects them to the page where the data has been posted. If not, I need to to redirect them back to the page they were at with an error and the POST variables. Here is the gist of how it works.
The HTML would look like this...
<form name="example" action="action.php" method="POST">
<input type="text" name="one">
<input type="text" name="two">
<input type="text" name="three">
<input type="submit" value="Submit!">
</form>
action.php would look like this...
if(error_check($_POST['one']) == true){
header('Location: form.php');
// Here is where I need the data to POST back to the form page.
} else {
// function to insert data into database
header('Location: posted.php');
}
In the case of an error, I need it to POST back to the first page.
I can't use GET, because the input will be too large.
I don't want to use SESSION, if possible.
Is this possible?
// from http://wezfurlong.org/blog/2006/nov/http-post-from-php-without-curl
function do_post_request($url, $data, $optional_headers = null)
{
$params = array('http' => array(
'method' => 'POST',
'content' => $data
));
if ($optional_headers !== null) {
$params['http']['header'] = $optional_headers;
}
$ctx = stream_context_create($params);
$fp = #fopen($url, 'rb', false, $ctx);
if (!$fp) {
throw new Exception("Problem with $url, $php_errormsg");
}
$response = #stream_get_contents($fp);
if ($response === false) {
throw new Exception("Problem reading data from $url, $php_errormsg");
}
return $response;
}
If you don't want to use sessions, the only thing you can do is POST to the same page. Which IMO is the best solution anyway.
// form.php
<?php
if (!empty($_POST['submit'])) {
// validate
if ($allGood) {
// put data into database or whatever needs to be done
header('Location: nextpage.php');
exit;
}
}
?>
<form action="form.php">
<input name="foo" value="<?php if (!empty($_POST['foo'])) echo htmlentities($_POST['foo']); ?>">
...
</form>
This can be made more elegant, but you get the idea...
It is not possible to redirect a POST somewhere else. When you have POSTED the request, the browser will get a response from the server and then the POST is done. Everything after that is a new request. When you specify a location header in there the browser will always use the GET method to fetch the next page.
You could use some Ajax to submit the form in background. That way your form values stay intact. If the server accepts, you can still redirect to some other page. If the server does not accept, then you can display an error message, let the user correct the input and send it again.
It would be beneficial to verify the form's data before sending it via POST. You should create a JavaScript function to check the form for errors and then send the form. This would prevent the data from being sent over and over again, possibly slowing the browser and using transfer volume on the server.
Edit:
If security is a concern, performing an AJAX request to verify the data would be the best way. The response from the AJAX request would determine whether the form should be submitted.
Use a smarty template for your stuff then just set the POST array as a smarty array and open the template. In the template just echo out the array so if it passes:
if(correct){
header("Location: passed.php");
} else {
$smarty->assign("variables", $_POST);
$smarty->display("register_error.php");
exit;
}
I have not tried this yet but I am going to try it as a solution and will let you know what I find. But of course this method assumes that you are using smarty.
If not you can just recreate your form there on the error page and echo info into the form or you could send back non important data in a get from and get it
ex.
register.php?name=mr_jones&address==......
echo $_GET[name];