I'm use reCaptcha v2 but in dev console response Uncaught (in promise) null in in any case (and moving the .reset() function)
console:
my code for recaptcha:
<div class="text-xs-center" style="text-align: center; height:150px;">
<p style="color: black;"> Complete the verification: </p>
<div style="display: inline-block;" class="g-recaptcha" data-sitekey="xxxxxxxxxxx" data-callback="callback"></div>
</div>
my callback function:
function callback() {
if (grecaptcha === undefined) {
alert('Recaptcha non definito');
return;
}
var response = grecaptcha.getResponse();
console.log(response);
if (!response) {
alert('Coud not get recaptcha response');
return;
}
$.ajax({
'url' : 'validate-recaptcha.php',
'type' : 'POST',
'data' : {
'response' : response
},
'success' : function(data) {
alert('Data: '+data);
},
'error' : function(request,error)
{
alert("Request: "+JSON.stringify(request));
}
});
grecaptcha.reset();
}
and my validate-recaptcha.php:
<?php
//debug
$fp = fopen('debug.txt', 'a');
fwrite($fp, print_r($_POST, TRUE));
fclose($fp);
//enddebug
if (empty($_POST['recaptcha'])) {
exit('Please set recaptcha variable');
}
// validate recaptcha
$response = $_POST['recaptcha'];
$post = http_build_query(
array (
'response' => $response,
'secret' => 'yoursecretkey',
'remoteip' => $_SERVER['REMOTE_ADDR']
)
);
$opts = array('http' =>
array (
'method' => 'POST',
'header' => 'application/x-www-form-urlencoded',
'content' => $post
)
);
$context = stream_context_create($opts);
$serverResponse = #file_get_contents('https://www.google.com/recaptcha/api/siteverify', false, $context);
if (!$serverResponse) {
exit('Failed to validate Recaptcha');
}
$result = json_decode($serverResponse);
if (!$result -> success) {
exit('Invalid Recaptcha');
}
exit('Recaptcha Validated');
Searching on the internet, probably the problem is the .reset() function, but I do not understand the solution.
Turns out it also occurs when a site is not "registered" in the Google recaptcha/admin Domains area.
Solution: Add the domain in the recaptcha admin area:
Sign into your Google account where your recaptcha keys are registered
Type into Google "google recpatcha admin console"
Go to your settings for your (production) key
In "Domains", add these two entries:
localhost
127.0.0.1
Save it and test your recaptcha.
I made this error when I switched from a development key to a production key. The production key did not have any entries for localhost.
I configured the API response to sit behind a proxy-redirect. Therefore the verification was working in a localhost environment which was not configured in the Google Admin console which caused this generic error.
Credit to #Christian Žagarskas who pointed it out in his comment.
I had this error too and I found is related with the recaptcha callback (in your case data-callback="callback"). If you remove your data-callback attribute the error won't come up.
The console error Uncaught (in promise) null indicates the callback is waiting for a promise. Here's a basic callback function for recaptcha using promises:
function callback() {
return new Promise(function(resolve, reject) {
//Your code logic goes here
//Instead of using 'return false', use reject()
//Instead of using 'return' / 'return true', use resolve()
resolve();
}); //end promise
};
In your case you need to adjust your code to something like this:
function callback() {
return new Promise(function(resolve, reject) {
if (grecaptcha === undefined) {
alert('Recaptcha non definito');
//return;
reject();
}
var response = grecaptcha.getResponse();
console.log(response);
if (!response) {
alert('Coud not get recaptcha response');
//return;
reject();
}
$.ajax({
'url' : 'validate-recaptcha.php',
'type' : 'POST',
'data' : {
'response' : response
},
'success' : function(data) {
alert('Data: '+data);
resolve();
},
'error' : function(request,error)
{
alert("Request: "+JSON.stringify(request));
reject();
}
});
grecaptcha.reset();
}); //end promise
}
This is my first answer in SO, so please be patient and let me know if I forgot or missed something :)
Another trigger for this error that plagued me was having a button in the form with a name attribute of 'submit'. If using the automatic binding example code from the reCaptcha documentation, this will trip it up, since 'form.submit' will refer to the button rather than the submit() function of the form itself. Doh!
<html>
<head>
<title>reCAPTCHA demo: Simple page</title>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<script>
function onSubmit(token) {
document.getElementById("demo-form").submit();
}
</script>
</head>
<body>
<form id='demo-form' action="?" method="POST">
<!-- Oops.... avoid the name="submit" below -->
<button name="submit" class="g-recaptcha" data-sitekey="your_site_key" data-callback='onSubmit'>Submit</button>
<br/>
</form>
</body>
</html>
This can happen when your callback code causes an error. In my case, my callback just referenced some variable that didn't exist and I saw the same error. Very weird error for something so simple!
I also saw the same error when I left a . after a variable name on accident. Seems like this is a super generic error that means fix the code in your callback!.
I feel I should add an answer here with my specific experience. I give credit to the top answer, which will be part of my answer.
I was getting: Uncaught (in promise) null. When I expanded the error in the console it was empty.
I changed my code from this:
function onSubmit(token) {
if (grecaptcha.getResponse() !== "") {
$('#request-form').submit();
}
grecaptcha.reset();
}
To this:
function onSubmit(token) {
return new Promise(function (resolve, reject) {
if (grecaptcha.getResponse() !== "") {
$('#request-form').submit();
}
grecaptcha.reset();
});
}
What this change does is allows you to receive a specific error message in your console. You can then proceed to fix your specific problem.
Similar to John Rix issue/solution. I also got the error when the id of the submit element was 'submit'.
<!-- Avoid id="submit" below -->
<input type="submit" id="submit" value="submit">```
In my case I was using jquery.3.4.1.slim.js then I changed to jquery.3.4.1.min.js and the error disappeared. I'm on ASP.NET WebForms .
I had this issue. It was because in my callback function jquery code was there and for some reason, I had forgotten to include the jquery script. So if you are having this issue, I suggest you to carefully go through each line of your call back code. May be reduce the complexity line by line and you will get the solution. The error handling should have been done in a better way.
I was using ASP.NET Core 3.1 Identity, I had this issue and solved it by updating jquery.validate.min.js and jquery.validate.unobtrusive.min.js to the latest version in _ValidationScriptsPartial.cshtml.
I had the same issue and the problem was that I didn't add localhost to the list of supported domains.
I hit this error because I had:
const onChange = e => {
e.preventDefault();
console.log('success')
}
<ReCAPTCHA sitekey="yeet" onChange={onChange} />
Removing e.preventDefault() removed the error.
Related
I have a registration form, the user is being redirected to home.php after success (works)
But also all the 'alerts/errors' which are echos in PHP, after submit, will redirect to register.php and show the error in blank white page.
(How do i display them to <div class="msg"> position?)
<script>
document.querySelector(".register form").addEventListener("submit", async (e) => {
e.preventDefault()
const form = e.target
const body = new FormData(form)
// fetch is much easier to use than XHR
const res = await fetch(form.action, {
method: "POST",
headers: {accept: "application/json", // let PHP know what type of response we want},
body})
const data = await res.json()
if (res.ok) {
location.href = data.location
} else if (res.status === 400) {
document.querySelector('.msg').textContent = data.message
// also do something with data.errors maybe
}
})
</script>
<body>
<div class="msg"></div> <!--position for error/ wrong pass etc-->
register.php
Based off that, please provide a correct code snippet in order to mark this as resolved.
It would probably make your life quite a bit easier if you always returned JSON from your PHP, rather than sometimes HTML as well.
For examples, when checking the errors at the top of register.php, you should return JSON objects --- e.g.
{error: "Email is not valid!"}
rather than their HTML equivilents.
This means that in your fetch, you'll now always be able to get the JSON content (currently, you'd probably get an error in your browser's debug console if one of those messages came back, as it's not valid JSON). Then, in your JavaScript, you can just detect this and switch however you want:
if (data.error) { // If there is an error
document.querySelector(".msg").textContent = data.error;
}
else if (data.location) { // If we want to redirect the user somewhere
window.location.href = "./" + data.location;
}
I am trying to set up reCaptcha v3 and it sort of works. For some reason the first time I submit the form it fails but from the second submit onwards it is fine. I can't figure out why this is happening?
<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('captcha-response');
recaptchaResponse.value = token;
});
});
</script>
<input type="hidden" name="captcha-response" id="captcha-response">
PHP
$verifyResponse = file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret='.$secretKey.'&response='.$_POST['captcha-response']);
$responseData = json_decode($verifyResponse);
if(!$responseData->score < 0.5) {
$message .= "Verification failed " . $responseData->score;
}
When I submit the form the first time, I get the validation error but my score is 0.9.
Why you have added "!" with "$responseData->score"? you may need to replace your condition with the following:
Replace this:
if(!$responseData->score < 0.5) {
$message .= "Verification failed " . $responseData->score;
}
With this one:
if($responseData->score < 0.5) {
$message .= "Verification failed " . $responseData->score;
}
P.S: Following code takes few seconds to properly load and get a "captcha-reponse" code, so you may need to disable all submit button and wait till you got a "captcha-reponse" to enable the submit button in form or you needs to implementent another way to delay the submit to execute only once you got a "captcha-response" code otherwise you will keep getting "missing-input-response" error message
<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('captcha-response');
recaptchaResponse.value = token;
});
});
</script>
You should re-generate the reCaptcha token after error form validation occured.
The token reCaptcha only valid for ONE TIME.
So, you have two options to fixes this issue.
1. Reload the page when error occured
This is the easiest way. You only need to reload the page whenever form validation error occured.
Of course, this will trigger the reCaptcha to generate new token.
2. Handle with AJAX (Non-reload page)
This is the best approach, since this will helps the user not losing the form data and continue to fill the form.
So, here's what you should do.
<!-- Put this hidden input inside of your form tag -->
<input name="_recaptcha" type="hidden">
<script src="https://www.google.com/recaptcha/api.js?render=YOUR_SITEKEY_HERE"></script>
<script>
// This will generate reCaptcha token and set to input hidden
const generateRecaptcha = function() {
grecaptcha.execute(
"YOUR_SITEKEY_HERE", {
action: "YOUR_ACTION_NAME"
}).then(function(token) {
if (token) {
document.querySelector("input[name='_recaptcha']").value = token;
}
});
}
// Call it when page successfully loaded
grecaptcha.ready(function() {
generateRecaptcha();
});
// Do your AJAX code here
$.ajax({
url: "https://example.com",
success: function(response) {
console.log(response);
},
error: function(error) {
// Call again the generator token reCaptcha whenever error occured
generateRecaptcha();
}
</script>
Don't forget to put your Site key and your action name. Make sure the action name matches with your Backend action name.
Medium Article
I am using the Yammer REST API to pull user information which works perfectly when I hard code the Yammer API.
I am trying to use an input box so that the script will be more flexible, but I keep getting problems when passing the user id variable to the Yammer API.
Because I was passing from function to function it would not work, I was advised to use localStorage, but that seems to have the same problem as a variable.
I wonder what I am doing wrong?
<html>
<head>
</head>
<body>
<form id="frm1" action="#" method="post">
Yammer ID: <input type="text" name="y_id"><br><br>
<input type="submit" onclick="yam_inp()" value="Submit">
</form>
<span id="yammer-login"></span>
<script type="text/javascript" data-app-id="bdlZbJHCm1RY8pMUbuoBlQ" src="https://c64.assets-yammer.com/assets/platform_js_sdk.js"></script>
<script>
function yam_inp() {
frm_i=document.getElementById("frm1");
//result=frm_i.elements[0].value; //unable to pass from funtion to function so using local storage
localStorage.yammer_id=frm_i.elements[0].value; // line 23, Unable to set property 'yammer_id' of undefined or null reference
//localStorage.setItem("yammer_id", frm_i.elements[0].value);
alert (result);
}
yam.getLoginStatus(
function (response) {
if (response.authResponse) {
console.log("logged in");
yam.platform.request({
url: "users/"+localStorage.yammer_id+".json", //line 32, Unable to get property 'yammer_id' of undefined or null reference
method: "GET",
data: {
"User_Id": localStorage.yammer_id,
},
success: function (user) { //print message response information to the console
// alert("The request was successful.");
//str = JSON.stringify(user);
str = JSON.stringify(user, null, 4); // (Optional) beautiful indented output.
document.write(str);
//console.dir(user);
},
error: function (user) {
alert("There was an error with the request.");
}
});
}
else {
alert("not logged in")
}
}
);
</script>
I keep getting line 32: Unable to get property 'yammer_id' of undefined or null reference, which is what I was getting with the result variable before localStorage, so this defeats the objective of localStorage unless I am not using it correctly.
So allow me to first say I have looked at previous questions, and none of them have helped me out. My problem is as follows, I have an html file with a form which calls a javascript function to load a php file.
The form looks as following:
<form method="GET" id="submission" >
<div class="form-group">
<label for="q">Search Term:</label>
<input type="text" class="form-control" id="q" name="q" placeholder="enter a keyword">
</div>
<div class="form-group">
<label for="location">location</label>
<input type="text" class="form-control" id="location" name="location" placeholder="lat,long">
</div>
<div class="form-group">
<label for="locationRadius">Location Radius:</label>
<input type="text" class="form-control" id="locationRadius" name="locationRadius" placeholder="25km">
</div>
<div class="form-group">
<label for="maxResults">Max Results:</label>
<input type="number" class="form-control" id="maxResults" name="maxResults" placeholder="0 to 50">
</div>
<button type="submit" id="submitButton" >Submit</button>
</form>
The JS function responsible for sending is the following:
function sendData() {
var keyword = document.getElementById("q").value;
var location = $('#location').value;
var locationRadius = $('#locationRadius').value;
var maxResult = $('#maxResults').value;
alert("keyword is: " + locationRadius);
$.get(
{
type: 'GET',
url: '../php/geolocation.php',
data : {q: keyword, location: location, locationRadius: locationRadius, maxResults: maxResult}
},
function (data) {
//alert("Data loaded " + data);
document.getElementById("geolocation-results").innerHTML = data;
}
);
}
$(document).ready(function() {
$("#submission").submit(function() {
sendData();
return false;
});
});
SO my problem is two fold, how to call it in an ajax like manner as the above format worked for my old code, but for some reason refuses to function correctly for this one. And how should I fetch the php data? The php code is below:
It is a modified version of youtube's geolocation example code.
<?php
/**
* This sample lists videos that are associated with a particular keyword and are in the radius of
* particular geographic coordinates by:
*
* 1. Searching videos with "youtube.search.list" method and setting "type", "q", "location" and
* "locationRadius" parameters.
* 2. Retrieving location details for each video with "youtube.videos.list" method and setting
* "id" parameter to comma separated list of video IDs in search result.
*
* #author Ibrahim Ulukaya
*/
/**
* Library Requirements
*
* 1. Install composer (https://getcomposer.org)
* 2. On the command line, change to this directory (api-samples/php)
* 3. Require the google/apiclient library
* $ composer require google/apiclient:~2.0
*/
if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
throw new \Exception('please run "composer require google/apiclient:~2.0" in "' . __DIR__ .'"');
}
require_once __DIR__ . '/vendor/autoload.php';
$htmlBody = null;
// This code executes if the user enters a search query in the form
// and submits the form. Otherwise, the page displays the form above.
if (isset($_GET['q'])
&& isset($_GET['maxResults'])
&& isset($_GET['locationRadius'])
&& isset($_GET['location'])) {
/*
* Set $DEVELOPER_KEY to the "API key" value from the "Access" tab of the
* {{ Google Cloud Console }} <{{ https://cloud.google.com/console }}>
* Please ensure that you have enabled the YouTube Data API for your project.
*/
$DEVELOPER_KEY = 'AIzaSyC6q-84bJv9HWCUDT4_SQ5Bp9WFJW2Z-e4';
$client = new Google_Client();
$client->setDeveloperKey($DEVELOPER_KEY);
// Define an object that will be used to make all API requests.
$youtube = new Google_Service_YouTube($client);
try {
// Call the search.list method to retrieve results matching the specified
// query term.
$searchResponse = $youtube->search->listSearch('id,snippet', array(
'type' => 'video',
'q' => $_GET['q'],
'location' => $_GET['location'],
'locationRadius' => $_GET['locationRadius'],
'maxResults' => $_GET['maxResults'],
));
$videoResults = array();
# Merge video ids
foreach ($searchResponse['items'] as $searchResult) {
array_push($videoResults, $searchResult['id']['videoId']);
}
$videoIds = join(',', $videoResults);
# Call the videos.list method to retrieve location details for each video.
$videosResponse = $youtube->videos->listVideos('snippet, recordingDetails', array(
'id' => $videoIds,
));
$videos = '';
// Display the list of matching videos.
foreach ($videosResponse['items'] as $videoResult) {
$videos .= sprintf('<li>%s,%s (%s,%s)</li>',
$videoResult['id'],
$videoResult['snippet']['title'],
$videoResult['recordingDetails']['location']['latitude'],
$videoResult['recordingDetails']['location']['longitude']);
echo $videos;
}
//$htmlBody = <<<END
// <h3>Videos</h3>
// <ul>$videos</ul>
//END;
} catch (Google_Service_Exception $e) {
$htmlBody .= sprintf('<p>A service error occurred: <code>%s</code></p>',
htmlspecialchars($e->getMessage()));
} catch (Google_Exception $e) {
$htmlBody .= sprintf('<p>An client error occurred: <code>%s</code></p>',
htmlspecialchars($e->getMessage()));
}
}
?>
It appears that the problem is your attempt to specify an non asynchronous request. I believe these are blocked by current/modern browsers. If you check your javascript console, you will probably see an error like this:
Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
If you remove that, I believe it will work as before (if it worked earlier, as you indicated). jQuery ajax requests are asynchronous by default, so if you remove that line, it will operate asynchronously.
(This wasn't part of your question, but you might consider leaving your input field's value="" blank, and put your helper text in placeholder="" attributes instead. These will provide the clue to your users without the risk of having that information passed in your request.)
As for displaying the result of the call, having your call return HTML and simply displaying that HTML on your calling page should work. Since you're using jQuery you could simplify your code like so: $('#geolocation-results').html(data); You may need/want to specify dataType: 'html' in your call as well. (https://api.jquery.com/jquery.get/)
Oh my. So obvious now. I believe your structure of the .get call is wrong. Should be like this:
$.get(
"../php/geolocation.php",
{
q: keyword,
location: location,
locationRadius: r,
maxResults: maxResult
},
function (data) {
$('#geolocation-results').html(data);
}
);
Checking that now... Okay, after rushing a bit too much I can confirm that the $.get() call was just structured wrong. Correct it as shown above and it will call the PHP file correctly and display the output in the geolocation-results element.
I think there are some mistakes in your code. You don't need to put async (and not asynch) as false because it's blocking the client browser for nothing. Be also careful to your url parameter which should not contains any quotes. Finally, you should put your trigger on the submit event more than on the onclick event because you can submit the form just by pressing Enter without clicking on your button.
You can try with this javascript :
function sendData() {
var keyword = document.getElementById("q").value;
var location = $('#location').value;
var locationRadius = $('#locationRadius').value;
var maxResult = $('#maxResults').value;
alert("keyword is: " + keyword);
$.get(
'../php/geolocation.php',
{q: keyword, location: location, locationRadius: locationRadius, maxResults: maxResult},
function (data) {
alert("Data loaded " + data);
document.getElementById("geolocation-results").innerHTML = data;
}
);
}
$(document).ready(function() {
$("#submission").submit(function() {
sendData();
return false;
}
});
On my forum-based website, I have a link below every post for reporting spam or abuse. Whenever this link is clicked, a web service is called on the server, when the call returns, the span containing the link (see the code below) is updated with something like 'Post reported' or if an error occurs it shows something like 'An error occurred while reporting the post', this is the javascript code:
<script src="/js/MicrosoftAjax.js" type="text/javascript" language="javascript"></script>
<script type="text/javascript" language="javascript">
var spanToUpdate;
function ReportPost(updateSpan, postID)
{
if (confirm("Are you sure you want to report this post as spam or abuse?"))
{
spanToUpdate = updateSpan;
var proxy = SiteWS.ReportPost(postID, onReportPostSuccess, onReportPostFailure);
}
}
function onReportPostSuccess(sender, e)
{
spanToUpdate.innerHTML = "Post reported";
}
function onReportPostFailure(sender, e)
{
spanToUpdate.innerHTML = "An error occurred while reporting the post";
}
</script>
And this is the reporting link:
<div class="post">
<p>post text here</p>
<span>Report Post</span>
</div>
Other posts ...
As you can see, I use a variable, spanToUpdate, to hold a reference to the span that contains the reporting link, which means that if the user reports another post (ie. clicks another reporting link) before the call returns, the span of the last post will be updated twice and the previous one won't be updated at all, is there any workaround for this?
Many thanks
You can use anonymous functions and closures for that.function ReportPost(updateSpan, postID) {
if (confirm("Are you sure you want to report this post as spam or abuse?")) {
var proxy = SiteWS.ReportPost(
postID,
function(sender,e) {updateSpan.innerHTML = "Post reported" },
function(sender,e) {updateSpan.innerHTML = "An error occurred while reporting the post" }
);
}
}
edit: hmm .. just wondering, will updateSpan be referring to the same span when the anonymous method is called? – Waleed Eissa
Yes, that's the magic of closures. Try this little example:
<head>
<script>
function foo()
{
bar(1, 100);
bar(2, 150);
bar(3, 200);
bar(4, 250);
bar(5, 300);
document.getElementById("div1").innerHTML += "foo() is done. ";
return;
}
function bar(val, timeout) {
window.setTimeout(
function() {
document.getElementById("div1").innerHTML += " " + val + " ";
},
timeout
);
}
</script>
</head>
<body>
<button onclick="foo()">click</button>
<div id="div1"></div>
</body>You will see that each time the anonymous function is called it has preserved "its own" value of val from the time/context when bar() was called.
Not a JavaScript developer so this might not work. Would it be possible to hold a reference to the post id and the spanToUpdate and then have the response from the server include the post id. Then you could retrieve the correct spanToUpdate.