File indexing completed on 2024-12-22 05:36:18

0001 <?php
0002 namespace Cgsmith\Validate;
0003 
0004 /**
0005  * Class Recaptcha
0006  * Handle validation against Google API
0007  *
0008  * @package Cgsmith
0009  * @license MIT
0010  * @author Chris Smith
0011  * @link   https://github.com/google/recaptcha
0012  */
0013 class Recaptcha extends \Zend_Validate_Abstract
0014 {
0015     /** @var string secret key */
0016     protected $_secretKey;
0017 
0018     /** @const string invalid captcha */
0019     const INVALID_CAPTCHA = 'invalidCaptcha';
0020 
0021     /** @const string invalid captcha */
0022     const CAPTCHA_EMPTY = 'captchaEmpty';
0023 
0024     /** @const string URL to where requests are posted */
0025     const SITE_VERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify';
0026 
0027     /** @const string http method for communicating with google */
0028     const POST_METHOD = 'POST';
0029 
0030     /** @const string peer key for communication */
0031     const PEER_KEY = 'www.google.com';
0032 
0033     /** @const string default name for captcha result in $_POST array */
0034     const CAPTCHA_NAME = 'g-recaptcha-response';
0035 
0036     protected $_messageTemplates = array(
0037         self::INVALID_CAPTCHA => 'The captcha was invalid',
0038         self::CAPTCHA_EMPTY   => 'The captcha must be completed'
0039     );
0040 
0041     /**
0042      * @param $options
0043      */
0044     public function __construct($options) {
0045         $this->_secretKey = $options['secretKey'];
0046     }
0047 
0048     /**
0049      * Validate our form's element
0050      *
0051      * @param mixed $value
0052      * @param null $context
0053      * @return bool
0054      */
0055     public function isValid($value, $context = null)
0056     {
0057         if (empty($value) AND (false == isset($context[self::CAPTCHA_NAME]))) {
0058             $this->_error(self::CAPTCHA_EMPTY);
0059             return false;
0060         }
0061 
0062         if (empty($value)) {
0063             $this->_value = $context[self::CAPTCHA_NAME];
0064         } else {
0065             $this->_value = $value;
0066         }
0067 
0068         if (false == $this->_verify($this->_value)) {
0069             $this->_error(self::INVALID_CAPTCHA);
0070             return false;
0071         }
0072 
0073         return true;
0074     }
0075 
0076     /**
0077      * Calls the reCAPTCHA siteverify API to verify whether the user passes the captcha test.
0078      *
0079      * @param  mixed $value
0080      * @return boolean
0081      * @link   https://github.com/google/recaptcha
0082      */
0083     protected function _verify($value)
0084     {
0085         $queryString = http_build_query(array(
0086             'secret'   => $this->_secretKey,
0087             'response' => $value,
0088             'remoteIp' => $_SERVER['REMOTE_ADDR']
0089         ));
0090 
0091         /**
0092          * PHP 5.6.0 changed the way you specify the peer name for SSL context options.
0093          * Using "CN_name" will still work, but it will raise deprecated errors.
0094          */
0095         $peerKey = version_compare(PHP_VERSION, '5.6.0', '<') ? 'CN_name' : 'peer_name';
0096         $context = stream_context_create(array(
0097             'http'  => array(
0098                 'header'      => "Content-type: application/x-www-form-urlencoded\r\n",
0099                 'method'      => self::POST_METHOD,
0100                 'content'     => $queryString,
0101                 'verify_peer' => true,
0102                 $peerKey      => self::PEER_KEY
0103             )
0104         ));
0105         $jsonObject = json_decode(file_get_contents(self::SITE_VERIFY_URL,false,$context));
0106 
0107         return $jsonObject->success;
0108     }
0109 }