FDiri
4/17/2016 - 9:30 AM

reCAPTCHA without <form> / AJAX only (http://stackoverflow.com/a/36674977/66981)

reCAPTCHA without

/ AJAX only (http://stackoverflow.com/a/36674977/66981)

// callback function has to be in global namespace
// see https://github.com/google/recaptcha/issues/74#issuecomment-148071465 for details
window.recaptchaCallback = undefined;

jQuery(document).ready(function($) {

  window.recaptchaCallback = function recaptchaCallback(response) {
    // console.log('CALLBACK - captcha response: ' + response);

    $.ajax({
      method: "POST",
      url: "http://example.com/service.ajax.php",
      data: { 'g-recaptcha-response': response },
    })
      .done(function(msg) {
        // console.log(msg);
        if (msg.success === true) {
          // hide panel that contains recaptcha challenge...
          $("#panel-recaptcha").hide();
          // ... and show service result instead
          var tmpl = $.templates("#tmpl-service");
          $("#result").html(tmpl.render({data: msg.data}));
        } else {
          // show alert message
          var tmpl = $.templates("#tmpl-alert");
          $("#result").html(tmpl.render());
        }
      })
      .fail(function(jqXHR, textStatus) {
          // show alert message
        var tmpl = $.templates("#tmpl-alert");
        $("#result").html(tmpl.render());
      });
  }

});
<?php
header('Content-Type: application/json');

$data_payload = array(/* Add static payload here. If not static, you might want to add it conditionally. */);

// see https://www.google.com/recaptcha/admin for details
$siteKey = '';
$secret = '';

// see https://developers.google.com/recaptcha/docs/language for details
$lang = 'en';

// the following origins are allowed to use this service
// (we accept requests only if the Origin header contains only those white-listed origins)
$allowed_http_origins = array(
  "http://example.com",
  "http://example.net",
  // running Hugo server locally
  "http://localhost:1313",
);

$http_origin = $_SERVER['HTTP_ORIGIN'];
if (in_array($http_origin, $allowed_http_origins)){
  header("Access-Control-Allow-Origin: " . $http_origin);
}

// autoloader for ReCaptcha\Foo classes
require_once __DIR__ . '/vendor/autoload.php';

if (isset($_POST['g-recaptcha-response'])) {
  // user's response has been POSTed via g-recaptcha-response

  // $recaptcha = new \ReCaptcha\ReCaptcha($secret);
  // file_get_contents() with URLs is disabled on our PHP installation
  // (allow_url_fopen is set to false for security reasons)
  // thus, we use implementation that makes use of fsockopen() instead
  $recaptcha = new \ReCaptcha\ReCaptcha($secret, new \ReCaptcha\RequestMethod\SocketPost());

  $resp = $recaptcha->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']);

  if ($resp->isSuccess()) {
    // user has succeeded
    echo json_encode(
      array(
        'success' => true,
        'data' => $data_payload,
      )
    );
  } else {
    // user has failed or something went wrong
    echo json_encode(
      array(
        'success' => false,
        // just forward reCAPTCHA's error codes
        // see https://developers.google.com/recaptcha/docs/verify#error-code-reference for details
        // for instance, 'missing-input-response' means that the submitted response was empty
        'error-codes' => $resp->getErrorCodes(),
      )
    );
  }
} else {
  // user's response has *not* been POSTed via g-recaptcha-response
  echo json_encode(
    array(
      'success' => false,
      // use own error code
      'error-codes' => array('g-recaptcha-response-not-posted'),
    )
  );
}
?>
<h2>reCAPTCHA without form / AJAX only</h2>

<div class="panel panel-warning" id="panel-recaptcha">
  <div class="panel-heading">
    <h3 class="panel-title">Captcha</h3>
  </div>
  <div class="panel-body">
    <div id="recaptcha-service" class="g-recaptcha"
         data-callback="recaptchaCallback"
         data-sitekey=""></div>
    <script type="text/javascript" src="https://www.google.com/recaptcha/api.js?hl=en"></script>
  </div>
</div>

<div id="result"></div>

<script id="tmpl-alert" type="text/x-jsrender">
  <div class="alert alert-warning alert-dismissible fade in" role="alert">
    <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
    <strong>Oh snap! You got an error...</strong> Please try again.
  </div>
</script>

<script id="tmpl-service" type="text/x-jsrender">
  {{for data}}
    {{:}}<br>
  {{/for}}
</script>