Skip to content

Instantly share code, notes, and snippets.

@akostadinov
Created April 1, 2018 20:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save akostadinov/f8d013e41391dcbaf0708679730f2af8 to your computer and use it in GitHub Desktop.
Save akostadinov/f8d013e41391dcbaf0708679730f2af8 to your computer and use it in GitHub Desktop.
Joomla 2.5 reCaptcha patch to support 2.0 API
<?php
/**
* @package Joomla.Plugin
* @subpackage Captcha
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
* @note Sorry for the ugliness, just a quick patch to make this work with the 2.0 API, it also connects through TLS now. Just replace original plugins/captcha/recaptcha/recaptcha.php
*/
defined('_JEXEC') or die;
jimport('joomla.environment.browser');
/**
* Recaptcha Plugin.
* Based on the oficial recaptcha library( http://recaptcha.net/plugins/php/ )
*
* @package Joomla.Plugin
* @subpackage Captcha
* @since 2.5
*/
class plgCaptchaRecaptcha extends JPlugin
{
const RECAPTCHA_API_SERVER = "http://www.google.com/recaptcha";
const RECAPTCHA_API_SECURE_SERVER = "https://www.google.com/recaptcha";
const RECAPTCHA_VERIFY_SERVER = "www.google.com";
public function __construct($subject, $config)
{
parent::__construct($subject, $config);
$this->loadLanguage();
}
/**
* Initialise the captcha
*
* @param string $id The id of the field.
*
* @return Boolean True on success, false otherwise
*
* @since 2.5
*/
public function onInit($id)
{
// Initialise variables
$lang = $this->_getLanguage();
$pubkey = $this->params->get('public_key', '');
$theme = $this->params->get('theme', 'clean');
if ($pubkey == null || $pubkey == '')
{
throw new Exception(JText::_('PLG_RECAPTCHA_ERROR_NO_PUBLIC_KEY'));
}
$server = self::RECAPTCHA_API_SERVER;
if (JBrowser::getInstance()->isSSLConnection())
{
$server = self::RECAPTCHA_API_SECURE_SERVER;
}
JHtml::_('script', $server.'/api.js');
$document = JFactory::getDocument();
$document->addScriptDeclaration('window.addEvent(\'domready\', function() {
Recaptcha.create("'.$pubkey.'", "dynamic_recaptcha_1", {theme: "'.$theme.'",'.$lang.'tabindex: 0});});'
);
return true;
}
/**
* Gets the challenge HTML
*
* @return string The HTML to be embedded in the form.
*
* @since 2.5
*/
public function onDisplay($name, $id, $class)
{
$pubkey = $this->params->get('public_key', '');
return "<div class=\"g-recaptcha\" data-sitekey=\"{$pubkey}\"></div>";
}
/**
* Calls an HTTP POST function to verify if the user's guess was correct
*
* @return True if the answer is correct, false otherwise
*
* @since 2.5
*/
public function onCheckAnswer($code)
{
// Initialise variables
$privatekey = $this->params->get('private_key');
$response = JRequest::getString('g-recaptcha-response', '');;
// Check for Private Key
if (empty($privatekey))
{
$this->_subject->setError(JText::_('PLG_RECAPTCHA_ERROR_NO_PRIVATE_KEY'));
return false;
}
// Discard spam submissions
if ($response == null || strlen($response) == 0)
{
$this->_subject->setError(JText::_('PLG_RECAPTCHA_ERROR_EMPTY_SOLUTION'));
return false;
}
$response = $this->_recaptcha_http_get(self::RECAPTCHA_VERIFY_SERVER, "/recaptcha/api/siteverify",
array(
'secret' => $privatekey,
'response' => $response
)
);
/* $answers = explode("\n", $response[1]);
if (trim($answers[0]) == 'true') {
return true;
}
else
{
//@todo use exceptions here
$this->_subject->setError(JText::_('PLG_RECAPTCHA_ERROR_'.strtoupper(str_replace('-', '_', $answers[1]))));
return false;
}
*/
$res = preg_match('/"success":\s*true/', $response[1], $match);
if (!$res) {
$this->_subject->setError(JText::_('PLG_RECAPTCHA_ERROR_'.strtoupper(str_replace('-', '_', $response[1]))));
return false;
}
return true;
}
/**
* Encodes the given data into a query string format.
*
* @param string $data Array of string elements to be encoded
*
* @return string Encoded request
*
* @since 2.5
*/
private function _recaptcha_qsencode($data)
{
$req = "";
foreach ($data as $key => $value)
{
$req .= $key . '=' . urlencode(stripslashes($value)) . '&';
}
// Cut the last '&'
$req = rtrim($req, '&');
return $req;
}
/**
* Submits an HTTP POST to a reCAPTCHA server.
*
* @param string $host
* @param string $path
* @param array $data
* @param int $port
*
* @return array Response
*
* @since 2.5
*/
private function _recaptcha_http_post($host, $path, $data, $port = 80)
{
$req = $this->_recaptcha_qsencode($data);
$http_request = "POST $path HTTP/1.0\r\n";
$http_request .= "Host: $host\r\n";
$http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
$http_request .= "Content-Length: " . strlen($req) . "\r\n";
$http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
$http_request .= "\r\n";
$http_request .= $req;
$response = '';
if (($fs = @fsockopen($host, $port, $errno, $errstr, 10)) == false )
{
die('Could not open socket');
}
fwrite($fs, $http_request);
while (!feof($fs))
{
// One TCP-IP packet
$response .= fgets($fs, 1160);
}
fclose($fs);
$response = explode("\r\n\r\n", $response, 2);
return $response;
}
private function _recaptcha_http_get($host, $path, $data, $port = 443, $proto = "tls://")
{
$req = $this->_recaptcha_qsencode($data);
$query = $path.'?'.$req;
$http_request = "GET $query HTTP/1.0\r\n";
$http_request .= "Host: $host\r\n";
$http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
$http_request .= "\r\n";
$response = '';
if (($fs = @fsockopen($proto.$host, $port, $errno, $errstr, 10)) == false )
{
die("Could not open socket $errstr");
}
fwrite($fs, $http_request);
while (!feof($fs))
{
// One TCP-IP packet
$response .= fgets($fs, 1160);
}
fclose($fs);
$response = explode("\r\n\r\n", $response, 2);
return $response;
}
/**
* Get the language tag or a custom translation
*
* @return string
*
* @since 2.5
*/
private function _getLanguage()
{
// Initialise variables
$language = JFactory::getLanguage();
$tag = explode('-', $language->getTag());
$tag = $tag[0];
$available = array('en', 'pt', 'fr', 'de', 'nl', 'ru', 'es', 'tr');
if (in_array($tag, $available))
{
return "lang : '" . $tag . "',";
}
// If the default language is not available, let's search for a custom translation
if ($language->hasKey('PLG_RECAPTCHA_CUSTOM_LANG'))
{
$custom[] ='custom_translations : {';
$custom[] ="\t".'instructions_visual : "' . JText::_('PLG_RECAPTCHA_INSTRUCTIONS_VISUAL') . '",';
$custom[] ="\t".'instructions_audio : "' . JText::_('PLG_RECAPTCHA_INSTRUCTIONS_AUDIO') . '",';
$custom[] ="\t".'play_again : "' . JText::_('PLG_RECAPTCHA_PLAY_AGAIN') . '",';
$custom[] ="\t".'cant_hear_this : "' . JText::_('PLG_RECAPTCHA_CANT_HEAR_THIS') . '",';
$custom[] ="\t".'visual_challenge : "' . JText::_('PLG_RECAPTCHA_VISUAL_CHALLENGE') . '",';
$custom[] ="\t".'audio_challenge : "' . JText::_('PLG_RECAPTCHA_AUDIO_CHALLENGE') . '",';
$custom[] ="\t".'refresh_btn : "' . JText::_('PLG_RECAPTCHA_REFRESH_BTN') . '",';
$custom[] ="\t".'help_btn : "' . JText::_('PLG_RECAPTCHA_HELP_BTN') . '",';
$custom[] ="\t".'incorrect_try_again : "' . JText::_('PLG_RECAPTCHA_INCORRECT_TRY_AGAIN') . '",';
$custom[] ='},';
$custom[] ="lang : '" . $tag . "',";
return implode("\n", $custom);
}
// If nothing helps fall back to english
return '';
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment