Source for file recaptcha.php

Documentation is available at recaptcha.php

  1. <?php
  2. /**
  3.  * @package     Joomla.Plugin
  4.  * @subpackage  Captcha
  5.  *
  6.  * @copyright   Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
  7.  * @license     GNU General Public License version 2 or later; see LICENSE.txt
  8.  */
  9.  
  10. defined('_JEXEC') or die;
  11.  
  12. /**
  13.  * Recaptcha Plugin.
  14.  * Based on the official recaptcha library( https://developers.google.com/recaptcha/docs/php )
  15.  *
  16.  * @package     Joomla.Plugin
  17.  * @subpackage  Captcha
  18.  * @since       2.5
  19.  */
  20. class PlgCaptchaRecaptcha extends JPlugin
  21. {
  22.     const RECAPTCHA_API_SERVER = "http://api.recaptcha.net";
  23.     const RECAPTCHA_API_SECURE_SERVER = "https://www.google.com/recaptcha/api";
  24.     const RECAPTCHA_VERIFY_SERVER = "api-verify.recaptcha.net";
  25.  
  26.     /**
  27.      * Load the language file on instantiation.
  28.      *
  29.      * @var    boolean 
  30.      * @since  3.1
  31.      */
  32.     protected $autoloadLanguage = true;
  33.  
  34.     /**
  35.      * Initialise the captcha
  36.      *
  37.      * @param   string  $id  The id of the field.
  38.      *
  39.      * @return  Boolean    True on success, false otherwise
  40.      *
  41.      * @since  2.5
  42.      */
  43.     public function onInit($id)
  44.     {
  45.         $document = JFactory::getDocument();
  46.         $app      = JFactory::getApplication();
  47.  
  48.         $lang   = $this->_getLanguage();
  49.         $pubkey = $this->params->get('public_key', '');
  50.         $theme  = $this->params->get('theme', 'clean');
  51.  
  52.         if ($pubkey == null || $pubkey == '')
  53.         {
  54.             throw new Exception(JText::_('PLG_RECAPTCHA_ERROR_NO_PUBLIC_KEY'));
  55.         }
  56.  
  57.         $server = self::RECAPTCHA_API_SERVER;
  58.  
  59.         if ($app->isSSLConnection())
  60.         {
  61.             $server = self::RECAPTCHA_API_SECURE_SERVER;
  62.         }
  63.  
  64.         JHtml::_('script', $server . '/js/recaptcha_ajax.js');
  65.         $document->addScriptDeclaration('window.addEvent(\'domready\', function()
  66.         {
  67.             Recaptcha.create("' . $pubkey . '", "dynamic_recaptcha_1", {theme: "' . $theme . '",' . $lang . 'tabindex: 0});});'
  68.         );
  69.  
  70.         return true;
  71.     }
  72.  
  73.     /**
  74.      * Gets the challenge HTML
  75.      *
  76.      * @param   string  $name   The name of the field.
  77.      * @param   string  $id     The id of the field.
  78.      * @param   string  $class  The class of the field.
  79.      *
  80.      * @return  string  The HTML to be embedded in the form.
  81.      *
  82.      * @since  2.5
  83.      */
  84.     public function onDisplay($name, $id, $class)
  85.     {
  86.         return '<div id="dynamic_recaptcha_1"></div>';
  87.     }
  88.  
  89.     /**
  90.       * Calls an HTTP POST function to verify if the user's guess was correct
  91.       *
  92.       * @return  True if the answer is correct, false otherwise
  93.       *
  94.       * @since  2.5
  95.       */
  96.     public function onCheckAnswer($code)
  97.     {
  98.         $input      = JFactory::getApplication()->input;
  99.         $privatekey = $this->params->get('private_key');
  100.         $remoteip   = $input->server->get('REMOTE_ADDR', '', 'string');
  101.         $challenge  = $input->get('recaptcha_challenge_field', '', 'string');
  102.         $response   = $input->get('recaptcha_response_field', '', 'string');
  103.  
  104.         // Check for Private Key
  105.         if (empty($privatekey))
  106.         {
  107.             $this->_subject->setError(JText::_('PLG_RECAPTCHA_ERROR_NO_PRIVATE_KEY'));
  108.  
  109.             return false;
  110.         }
  111.  
  112.         // Check for IP
  113.         if (empty($remoteip))
  114.         {
  115.             $this->_subject->setError(JText::_('PLG_RECAPTCHA_ERROR_NO_IP'));
  116.  
  117.             return false;
  118.         }
  119.  
  120.         // Discard spam submissions
  121.         if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0)
  122.         {
  123.             $this->_subject->setError(JText::_('PLG_RECAPTCHA_ERROR_EMPTY_SOLUTION'));
  124.  
  125.             return false;
  126.         }
  127.  
  128.         $response = $this->_recaptcha_http_post(
  129.             self::RECAPTCHA_VERIFY_SERVER, "/verify",
  130.             array(
  131.                 'privatekey' => $privatekey,
  132.                 'remoteip'   => $remoteip,
  133.                 'challenge'  => $challenge,
  134.                 'response'   => $response
  135.             )
  136.     );
  137.  
  138.         $answers = explode("\n", $response[1]);
  139.  
  140.         if (trim($answers[0]) == 'true')
  141.             {
  142.                 return true;
  143.         }
  144.         else
  145.         {
  146.             // @todo use exceptions here
  147.             $this->_subject->setError(JText::_('PLG_RECAPTCHA_ERROR_' . strtoupper(str_replace('-', '_', $answers[1]))));
  148.  
  149.             return false;
  150.         }
  151.     }
  152.  
  153.     /**
  154.      * Encodes the given data into a query string format.
  155.      *
  156.      * @param   array  $data  Array of string elements to be encoded
  157.      *
  158.      * @return  string  Encoded request
  159.      *
  160.      * @since  2.5
  161.      */
  162.     private function _recaptcha_qsencode($data)
  163.     {
  164.         $req = "";
  165.  
  166.         foreach ($data as $key => $value)
  167.         {
  168.             $req .= $key . '=' . urlencode(stripslashes($value)) . '&';
  169.         }
  170.  
  171.         // Cut the last '&'
  172.         $req = rtrim($req, '&');
  173.  
  174.         return $req;
  175.     }
  176.  
  177.     /**
  178.      * Submits an HTTP POST to a reCAPTCHA server.
  179.      *
  180.      * @param   string  $host 
  181.      * @param   string  $path 
  182.      * @param   array   $data 
  183.      * @param   int     $port 
  184.      *
  185.      * @return  array   Response
  186.      *
  187.      * @since  2.5
  188.      */
  189.     private function _recaptcha_http_post($host, $path, $data, $port = 80)
  190.     {
  191.         $req = $this->_recaptcha_qsencode($data);
  192.  
  193.         $http_request  = "POST $path HTTP/1.0\r\n";
  194.         $http_request .= "Host: $host\r\n";
  195.         $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
  196.         $http_request .= "Content-Length: " . strlen($req) . "\r\n";
  197.         $http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
  198.         $http_request .= "\r\n";
  199.         $http_request .= $req;
  200.  
  201.         $response = '';
  202.  
  203.         if (($fs = @fsockopen($host, $port, $errno, $errstr, 10)) == false )
  204.         {
  205.             die('Could not open socket');
  206.         }
  207.  
  208.         fwrite($fs, $http_request);
  209.  
  210.         while (!feof($fs))
  211.         {
  212.             // One TCP-IP packet
  213.             $response .= fgets($fs, 1160);
  214.         }
  215.  
  216.         fclose($fs);
  217.         $response = explode("\r\n\r\n", $response, 2);
  218.  
  219.         return $response;
  220.     }
  221.  
  222.     /**
  223.      * Get the language tag or a custom translation
  224.      *
  225.      * @return  string 
  226.      *
  227.      * @since  2.5
  228.      */
  229.     private function _getLanguage()
  230.     {
  231.         $language = JFactory::getLanguage();
  232.  
  233.         $tag = explode('-', $language->getTag());
  234.         $tag = $tag[0];
  235.         $available = array('en', 'pt', 'fr', 'de', 'nl', 'ru', 'es', 'tr');
  236.  
  237.         if (in_array($tag, $available))
  238.         {
  239.             return "lang : '" . $tag . "',";
  240.         }
  241.  
  242.         // If the default language is not available, let's search for a custom translation
  243.         if ($language->hasKey('PLG_RECAPTCHA_CUSTOM_LANG'))
  244.         {
  245.             $custom[] = 'custom_translations : {';
  246.             $custom[] = "\t" . 'instructions_visual : "' . JText::_('PLG_RECAPTCHA_INSTRUCTIONS_VISUAL') . '",';
  247.             $custom[] = "\t" . 'instructions_audio : "' . JText::_('PLG_RECAPTCHA_INSTRUCTIONS_AUDIO') . '",';
  248.             $custom[] = "\t" . 'play_again : "' . JText::_('PLG_RECAPTCHA_PLAY_AGAIN') . '",';
  249.             $custom[] = "\t" . 'cant_hear_this : "' . JText::_('PLG_RECAPTCHA_CANT_HEAR_THIS') . '",';
  250.             $custom[] = "\t" . 'visual_challenge : "' . JText::_('PLG_RECAPTCHA_VISUAL_CHALLENGE') . '",';
  251.             $custom[] = "\t" . 'audio_challenge : "' . JText::_('PLG_RECAPTCHA_AUDIO_CHALLENGE') . '",';
  252.             $custom[] = "\t" . 'refresh_btn : "' . JText::_('PLG_RECAPTCHA_REFRESH_BTN') . '",';
  253.             $custom[] = "\t" . 'help_btn : "' . JText::_('PLG_RECAPTCHA_HELP_BTN') . '",';
  254.             $custom[] = "\t" . 'incorrect_try_again : "' . JText::_('PLG_RECAPTCHA_INCORRECT_TRY_AGAIN') . '",';
  255.             $custom[] = '},';
  256.             $custom[] = "lang : '" . $tag . "',";
  257.  
  258.             return implode("\n", $custom);
  259.         }
  260.  
  261.         // If nothing helps fall back to english
  262.         return '';
  263.     }
  264. }

Documentation generated on Tue, 19 Nov 2013 15:11:37 +0100 by phpDocumentor 1.4.3