How to protect jquery button with Invisible reCaptcha? - javascript

I want to protect my jquery button from bots without annoying the users, so i thought of adding google's invisible recaptcha to it. However implementation isn't as easy as i though and i can't seem to do it. If anyone can show me how it's done it would be great. PS: I am doing this on a wordpress theme.
This is the documentation:
https://developers.google.com/recaptcha/docs/invisible
Create invisible recaptcha:
https://www.google.com/recaptcha/admin#beta
And this is what i have:
HTML:
<button class="acf-get-content-button">Show Link</button>
<div class="fa" id="acf-content-wrapper" data-id="<?php echo $post_id; ?>"></div>
JS:
<script>
(function($) {
$('.acf-get-content-button').click(function(e) {
e.preventDefault();
$('.fa').addClass('fa-cog fa-spin fa-4x');
var $contentWrapper = $('#acf-content-wrapper');
var postId = $contentWrapper.data('id');
$.ajax({
url: "/public/ajax.php",
type: "POST",
data: {
'post_id': postId
},
})
.done(function(data) {
$('.fa').removeClass('fa-cog fa-spin fa-4x');
$contentWrapper.append(data);
$('.acf-get-content-button').removeClass().addClass('.acf-get-content-button')
});
});
$('.acf-get-content-button').mouseup(function() {
if (event.which == 1) {
$(".acf-get-content-button").hide();
}
});
})(jQuery);
</script>
ajax.php
<?php
define('WP_USE_THEMES', false);
require_once( $_SERVER['DOCUMENT_ROOT'] . '/wp-load.php' );
global $post;
$post_id = $_REQUEST["post_id"];
$content = get_field( 'ebook_link_pdf', $post_id );
echo ($content);

You can use Invisible reCaptcha for WordPress plugin to do it easily if you think coding from scratch is complicated for you. You can also dig into the source code of the plugin to get an idea about the implementation.
This plugin has actions and filters for custom use and these are documented on plugin homepage.

I went ahead to experiment with reCaptcha.
Turns out according to the API, you could use the grecaptcha.getResponse method to submit to your AJAX call. (But Note that this reCaptcha API is still in beta and could change...) Here is a short example:
HTML:
<div id="test-captcha" class="g-recaptcha" data-sitekey=[Your site key]></div>
<button id="load" onclick="go();">Load something</button>
Javascript:
function go()
{
$.ajax({
url: "/captchatest.php",
type: "POST",
data: {
'g-recaptcha-response': grecaptcha.getResponse()
}
}).done(function(data) {
alert(data);
});
}
captchatest.php
<?php
//Used http://stackoverflow.com/a/6609181/7344257
function do_post_request($url, $data)
{
// use key 'http' even if you send the request to https://...
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */ }
return $result;
}
$error = "";
if ($_SERVER["REQUEST_METHOD"] === "POST")
{
if (!isset($_POST['g-recaptcha-response']))
{
echo "Please do reCaptcha";
exit(0);
}
$data = array("secret" => "6LeUGhYUAAAAABNS5OtOc9vonTlyrtgcQ5VdI7cV",
"response" => $_POST['g-recaptcha-response'],
"remoteip" => $_SERVER["REMOTE_ADDR"] //This is optional.
);
$resp = json_decode(do_post_request("https://www.google.com/recaptcha/api/siteverify", $data));
if (!$resp->success)
{
//use $resp->error-codes to debug error.
echo "Invalid reCaptcha";
exit(0);
}
echo "Received secret code.";
exit(0);
}
?>
I wasn't sure if you could use cURL. So I decided to just stick with the basic PHP code. You would also have to format the errors, but I think you should get the point.

Related

Can I send filtered data with Ajax back to PHP file and write them again on page?

I implemented my Custom Post Type and content is listed on my page in while loop in that way:
$args = array('post_type' => 'studien', 'order' => 'ASC', 'posts_per_page' => 4 );
$loop = new WP_Query($args);
if($loop->have_posts()):
while($loop->have_posts()) : $loop->the_post();?>
<div class="col-md-6">
// data are listed here
</div>
<?php endwhile;
endif;
?>
And on my submit I try to filter data according to some custom taxonomies:
$ = jQuery;
var search = $("#search-studien");
var searchForm = search.find("studien");
$(document).ready(function () {
$('#studien').submit(function (evt) {
event.preventDefault();
var data = {
action: "studien_search",
type: $("#taxonomy-market-type").val(),
};
var html;
$.ajax({
url: ajaxurl,
data: data,
success: function (response) {
if(response)
{
// probably here I need to send filtered data back to PHP file and write them again
}
}
});
})
});
I use custom shortcode and callback() function:
function search_callback()
{
header('Content-Type: application/json;charset=utf-8');
$type = "";
$type = $_GET['type'];
$args = array(
"post_type" => "studien",
"post_per_page" => -1,
"relation" => "AND"
);
if($type != "") {
$args['tax_query'][] = array(
'taxonomy' => 'market',
'field' => 'slug',
'terms' => $type
);
$search_query = new WP_Query($args);
// echo json_encode($search_query);
}
else{
$search_query = new WP_Query( $args );
}
if ( $search_query->have_posts() ) {
$result = array();
while ($search_query->have_posts()) {
$search_query->the_post();
$result[] = array(
"id" => get_the_ID(),
"title" => get_the_title(),
"permalink" => get_permalink(),
);
};
wp_reset_query();
echo json_encode($search_query);
}
else {
// nothing
}
wp_die(); global $argsAjaxFilter;
$argsAjaxFilter = $search_query;
}
As you can see, $search_query represents my filtered data. This is method according to tutorial, but I can`t use response array() ... and best way for me is to send $search_query in some way to PHP file, where I can write my new Custom Post Type data again. Please, someone has advice for me? Is that good proposal?
So the main problem is to be able to send the rendered html to the browser. For that, we're going to need a template so we can reuse it in various places.
// your-theme/studien.php
<div class="studien-wrapper">
<?php
if($wp_query->have_posts()):
while($wp_query->have_posts()) : $wp_query->the_post();
// Do the thing
endwhile;
endif;
?>
</div>
Next, we need to load it whenever is needed. We can do it by using get_template_part. This function will pass some global variables automatically (such as $wp_query) to the template, you can have a look at the source code to learn more. When using it in "ajax mode" we need to capture the output, not send it to the browser (although we could) so we use output buffering. For "normal pages" just omit those calls.
// Set up query args
global $wp_query = new WP_Query($args);
ob_start(); // Capture the output.
get_template_part('studien');
$html_result = ob_get_clean();
And now is a matter of composing the response:
$result['html'] = $html_result;
if (!is_array($type)) {
$type = array($type);
}
$result['query_terms'] = $type;
$json = wp_json_encode($result);
echo $json;
wp_die();
You could also keep track of the search terms on the client side and avoid the last part. Depends on what you need.
To update the page you can do the following in your ajax call:
$.ajax({
url: ajaxurl,
data: data,
success: function (response) {
$('.studien-wrapper').replaceWith(response.html);
// Update search terms, etc
}
});

Wordpress wp_signon() do not work in ajax call

I am trying to build an costum login to Wordpress in a AJAX call. I a remove the wp_signon() from the PHP function I do get the right echo. But then I add the wp_signon() it always return my whole login page in HTML. I can't see what I am doing wrong. And can't get the login to work.
Please help!
js
$.ajax({
method: 'POST',
url: '/wp-admin/admin-ajax.php',
dataType: 'json',
data: {
'action': 'getLoggedIn',
'user_name': user_name,
'user_password': user_password,
'user_remember': user_remember
},
success: function(response) {
if (response === 'ok') {
window.location = '/app/';
}
},
error: function(){}
});
PHP
function getLoggedIn() {
global $wpdb;
// Check if users is already logged in
if ( is_user_logged_in() ) {
echo 'You are already logged in';
die;
}
//We shall SQL escape all inputs
$username = $wpdb->escape($_REQUEST['user_name']);
$password = $wpdb->escape($_REQUEST['user_password']);
$remember = $wpdb->escape($_REQUEST['user_remember']);
$creds = array();
$creds['user_login'] = $username;
$creds['user_password'] = $password;
$creds['remember'] = $remember;
$user_signon = wp_signon( $creds, false );
// Check if error
if ( is_wp_error($user_signon)) {
echo $user_verify->get_error_code();
exit();
} else {
echo 'ok';
exit;
}
die();
}
add_action('wp_ajax_getLoggedIn', 'getLoggedIn');
add_action('wp_ajax_nopriv_getLoggedIn', 'getLoggedIn');
The problem was not the wp_signon() function. It was an other Wordpress action that redirects the page after user login has failed. This:
add_action( 'wp_login_failed', 'login_failed' );
I got caught up in the same situation. did you remove that wp_login_failed action or how did you work this out?

Uncaught SyntaxError: Invalid or unexpected token. Google API Translate

I am the beginner, so do not have much experience.
The task is to translate the blocks of text the user writes.
So html-file:
<script type="text/javascript">
$('#some_id').on('click', function(){
var text_var = JSON.stringify("{$text_without_adv}");
var own_script = 'gTApi.php';
$.ajax({
method: 'post',
url: own_script,
data: $.parseJSON(text_var)
}).done(function(data) {
console.log(data);
});
});
</script>
php-file "gTApi.php" (where the magic happens):
<?php
require_once "../../vendor/autoload.php";
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
$text = file_get_contents('php://input');
$apKey = '**************************';
$client = new Client(
array(
'headers' => array(
'Accept' => 'application/json'
)
)
);
try {
$response =$client->get('https://translation.googleapis.com/language/translate/v2?key='
. $apKey
. '&source=en&target=es&q=' . $text);
} catch (\Exception $e) {
echo $e->getMessage();
}
$response_body = json_decode($response->getBody(), true);
echo $response_body['data']['translations'][0]['translatedText'];
another php-file:
$smarty->assign('text_without_adv', htmlspecialchars((implode(' ', $text_array))));
after the page loads I get unexpected token after the first sentence in variable $text_without_adv and can't do the translation, nothing happens when I click the button.
For example:
var text_var = JSON.stringify ("
But she had a sweetheart, and he said he would go and get the ball. ///token/// So he went to the park gate, but 'twas shut; so he climbed the hedge, and when he got to the top of the hedge, an old woman rose up out of the dyke before him, and said, if he wanted to get the ball, he must sleep three nights in the house. He said he would.");
But the main question is that there can be no errors in other posted texts from other users. I can't understand, 3 different texts from 3 different users have unexpected token, then the next 2 have no error, then the next one has the error and so on. Where could be the problem?
In this case you don't need to pass a json instead just pass a post data
To do that
First change this line
// to stored your php variable in a js variable
var text_var = "<?php echo $text_without_adv; ?>";
then
in your ajax
$.ajax({
method: 'post',
url: own_script,
data: {
// just use the declared js variable above which contains your php variable at the first place
text: text_var
}
}).done(function(data) {
console.log(data);
});
and in your php
instead of
$text = file_get_contents('php://input');
change to
$text = $_POST['text'];
so your code would be like this
JS
<script type="text/javascript">
$('#some_id').on('click', function(){
var text_var = "<?php echo $text_without_adv; ?>";
var own_script = 'gTApi.php';
$.ajax({
method: 'post',
url: own_script,
data: {
text: text_var
}
}).done(function(data) {
console.log(data);
});
});
</script>
PHP
<?php
require_once "../../vendor/autoload.php";
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
$text = $_POST['text'];
$apKey = '**************************';
$client = new Client(
array(
'headers' => array(
'Accept' => 'application/json'
)
)
);
try {
$response =$client->get('https://translation.googleapis.com/language/translate/v2?key='
. $apKey
. '&source=en&target=es&q=' . $text);
} catch (\Exception $e) {
echo $e->getMessage();
}
$response_body = json_decode($response->getBody(), true);
echo $response_body['data']['translations'][0]['translatedText'];

Ajax call fails when using wp_remote_get in wordpress plugin

I am having issues with wp_remote_get in my Wordpress plugin.
What I want to do is call a method inside my main public class with ajax. But the thing is that the call fails when the wp_remote_get function is used in it. It is supposed to do an API call and return the data to the jQuery. When I comment out the wp_remote_get the call works fine and response is given back. Any ideas how can I make this work?
Method that processes the call:
public function countryLookupApiCall() {
if (isset($_POST['action']) && isset($_POST['country'])) {
$country = $_POST['country'];
$apiKey = $this->getApiKey();
$url = $this->url . $country . '/callCharges?apiKey=' . $apiKey . '&response=JSON';
$response = wp_remote_get($url);
echo $response;
die();
}
}
jQuery:
jQuery(document).ready(function() {
jQuery("#countryLookupForm").submit(function(e){
var country = jQuery("#selectCountry").val();
var action = 'countryLookupResponse';
jQuery.ajax ({
type: 'POST',
url: countryLookup.ajaxurl,
dataType: 'json',
data: {action: action, country: country},
success: function(data) {
//do something with this data later on
var result = jQuery.parseJSON(data);
}
});
});
});
Wordpress actions are all registered well because the call works when I don't use the wp_remote_get
EDIT:
The solution was more than simple, I just needed to add e.preventDefault();
You need to add errors checking into your code. This can help you to figure out what is causing the problem.
public function countryLookupApiCall() {
if (isset($_POST['action']) && isset($_POST['country'])) {
$country = $_POST['country'];
$apiKey = $this->getApiKey();
$url = $this->url . $country . '/callCharges?apiKey=' . $apiKey . '&response=JSON';
$response = wp_remote_get($url);
if (is_wp_error($response)) {
$error_code = $response->get_error_code();
$error_message = $response->get_error_message();
$error_data = $response->get_error_data($error_code);
// Process the error here....
}
echo $response;
die();
}
}
Also you are using echo on wp_remote_get result. As defined in documentation wp_remote_get returs WP_Error or array instance. So you should use something like this:
echo $response['body'];

My AJAX function works correctly, but sometimes I get a JSON object undefined

i am building the next interface:
as you can see, this interface has two links shown as buttons, one to add products and the other one to rest products.
when i click in the link "addProduct" then it calculates the new total which is shown in the following interface:
The code involved in this operation, involves 2 files:
JQuery Ajax File:
$.ajax({
async:true,
type:"POST",
url: "masProducto.php",
datatype:"JSON",
data: {
tecantidad: tecantidad.val(),
valorId:id
},
success:function (jsonStr) {
var cantidad=jsonStr.cantidad;
var fila=$("#ticket_"+jsonStr.id);
var tetotal=fila.find(".precioTotal");
var teprecio=parseFloat(fila.find("input[type=hidden]").val());
var teCosteTotal=$("#importeTotal");
teCosteTotal.text(jsonStr.total+"€");
tetotal.text(teprecio*cantidad+"€");
var resumenTotal=$("#resumenTicket td:nth-child(3)");
resumenTotal.text(jsonStr.total+"€");
var resumenNumProductos=$("#resumenTicket td:nth-child(1)");
resumenNumProductos.text(jsonStr.numTotalProductos+" Items en la cesta");
},
error:function(err){
alert(err);
},
timeout:4000
});
The file masProducto.php where the JSON object is built:
<?php
include 'functions.php';
include('./ShoppingCart.php');
include('./Item.php');
sec_session_start(); //Nuestra manera personalizada segura de iniciar sesión php.
if (!isset($_SESSION['cesta'])){
header('Location: ./login.php?error=1');
}
else {
$cesta=new ShoppingCart();
$cesta=unserialize($_SESSION['cesta']);
}
header('Content-Type: application/json');
$listaItems=$cesta->getItems();
$numEltos=$cesta->count();
$tecantidad=$_POST['tecantidad'];
$id=$_POST['valorId'];
foreach ($listaItems as $celda){
if($id===$celda['item']->getId()){
$cesta->updateItem($celda['item'],$tecantidad);
}
}
$_SESSION['cesta']=serialize($cesta);
if(isset($id)){
$data = array(
"cantidad" => $tecantidad,
"id" => $id,
"total" => $cesta->calcularTotal(),
"numTotalProductos" => $numEltos
);
echo json_encode($data);
}
?>
I am using PHP OOP, and i use to objects for my shopping basket which are the "Soppingcart" and "Item".
My problem is that this code works right, but when i click fast to the plus (or rest button), it gives me back an undefined object.
I would apreciate if some could help me, because i dont even know how to look for the solution for this problem.
for more details you can enter in this website www.galeonweb.es/Index.php, where if you loggin with "test#example.com" and password "123456" you can see what is my problem better.
Thank you in advance
First off this line is pretty bad practice
if (!isset($_SESSION['cesta'])){
header('Location: ./login.php?error=1');
}
You should rather have something like
if (!isset($_SESSION['cesta'])){
echo json_encode(array(code => 2, message => 'Session invalid'));
}
And redirect the user to the login page from jQuery.
You would then need to modify the rest accordingly
if(isset($id)){
$data = array(
"code" => 0,
"message" => "Success",
"data" => array(
"cantidad" => $tecantidad,
"id" => $id,
"total" => $cesta->calcularTotal(),
"numTotalProductos" => $numEltos
)
);
echo json_encode($data);
}
I would also add the following to that
else {
echo json_encode(array('code' => 1, 'message' => 'Item not found' ));
}
Furthermore rather than test if an id is passed at the very end I would do
if(isset($id)){
$found = false;
foreach ($listaItems as $celda){
if($id===$celda['item']->getId()){
$cesta->updateItem($celda['item'],$tecantidad);
$found = true;
}
}
}
else
{
echo json_encode(array(code => 1, message => 'Fatal error, id not set'));
}
And replace
if(isset($id)){
$data = array(
With
if($found === true){
$data = array(
You'll of course have to adapt your javascript accordingly to parse the response.
Those changes should give you a better idea of what is going wrong. But, as I said in my comment, using a debug tool like Firebug will also go a long way.
Have you tried non async?
$.ajax({
async:false,
type:"POST",
url: "masProducto.php",
datatype:"JSON",
...

Categories