Created
April 1, 2018 20:17
-
-
Save akostadinov/f8d013e41391dcbaf0708679730f2af8 to your computer and use it in GitHub Desktop.
Joomla 2.5 reCaptcha patch to support 2.0 API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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