File indexing completed on 2024-05-12 06:03:06

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Service
0017  * @subpackage ReCaptcha
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  */
0021 
0022 /** @see Zend_Service_Abstract */
0023 // require_once 'Zend/Service/Abstract.php';
0024 
0025 /** @see Zend_Json */
0026 // require_once 'Zend/Json.php';
0027 
0028 /** @see Zend_Service_ReCaptcha_Response */
0029 // require_once 'Zend/Service/ReCaptcha/Response.php';
0030 
0031 /**
0032  * Zend_Service_ReCaptcha
0033  *
0034  * @category   Zend
0035  * @package    Zend_Service
0036  * @subpackage ReCaptcha
0037  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0038  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0039  * @version    $Id$
0040  */
0041 class Zend_Service_ReCaptcha extends Zend_Service_Abstract
0042 {
0043     /**
0044      * URI to the regular API
0045      *
0046      * @var string
0047      */
0048     const API_SERVER = 'http://www.google.com/recaptcha/api';
0049 
0050     /**
0051      * URI to the secure API
0052      *
0053      * @var string
0054      */
0055     const API_SECURE_SERVER = 'https://www.google.com/recaptcha/api';
0056 
0057     /**
0058      * URI to the verify server
0059      *
0060      * @var string
0061      */
0062     const VERIFY_SERVER = 'http://www.google.com/recaptcha/api/verify';
0063 
0064     /**
0065      * Public key used when displaying the captcha
0066      *
0067      * @var string
0068      */
0069     protected $_publicKey = null;
0070 
0071     /**
0072      * Private key used when verifying user input
0073      *
0074      * @var string
0075      */
0076     protected $_privateKey = null;
0077 
0078     /**
0079      * Ip address used when verifying user input
0080      *
0081      * @var string
0082      */
0083     protected $_ip = null;
0084 
0085     /**
0086      * Parameters for the object
0087      *
0088      * @var array
0089      */
0090     protected $_params = array(
0091         'ssl' => false, /* Use SSL or not when generating the recaptcha */
0092         'error' => null, /* The error message to display in the recaptcha */
0093         'xhtml' => false /* Enable XHTML output (this will not be XHTML Strict
0094                             compliant since the IFRAME is necessary when
0095                             Javascript is disabled) */
0096     );
0097 
0098     /**
0099      * Options for tailoring reCaptcha
0100      *
0101      * See the different options on http://recaptcha.net/apidocs/captcha/client.html
0102      *
0103      * @var array
0104      */
0105     protected $_options = array(
0106         'theme'               => 'red',
0107         'lang'                => 'en',
0108         'custom_translations' => array(),
0109     );
0110 
0111     /**
0112      * Response from the verify server
0113      *
0114      * @var Zend_Service_ReCaptcha_Response
0115      */
0116     protected $_response = null;
0117 
0118     /**
0119      * Class constructor
0120      *
0121      * @param string $publicKey
0122      * @param string $privateKey
0123      * @param array $params
0124      * @param array $options
0125      * @param string $ip
0126      * @param array|Zend_Config $params
0127      */
0128     public function __construct($publicKey = null, $privateKey = null,
0129                                 $params = null, $options = null, $ip = null)
0130     {
0131         if ($publicKey !== null) {
0132             $this->setPublicKey($publicKey);
0133         }
0134 
0135         if ($privateKey !== null) {
0136             $this->setPrivateKey($privateKey);
0137         }
0138 
0139         if ($ip !== null) {
0140             $this->setIp($ip);
0141         } else if (isset($_SERVER['REMOTE_ADDR'])) {
0142             $this->setIp($_SERVER['REMOTE_ADDR']);
0143         }
0144 
0145         if ($params !== null) {
0146             $this->setParams($params);
0147         }
0148 
0149         if ($options !== null) {
0150             $this->setOptions($options);
0151         }
0152     }
0153 
0154     /**
0155      * Serialize as string
0156      *
0157      * When the instance is used as a string it will display the recaptcha.
0158      * Since we can't throw exceptions within this method we will trigger
0159      * a user warning instead.
0160      *
0161      * @return string
0162      */
0163     public function __toString()
0164     {
0165         try {
0166             $return = $this->getHtml();
0167         } catch (Exception $e) {
0168             $return = '';
0169             trigger_error($e->getMessage(), E_USER_WARNING);
0170         }
0171 
0172         return $return;
0173     }
0174 
0175     /**
0176      * Set the ip property
0177      *
0178      * @param string $ip
0179      * @return Zend_Service_ReCaptcha
0180      */
0181     public function setIp($ip)
0182     {
0183         $this->_ip = $ip;
0184 
0185         return $this;
0186     }
0187 
0188     /**
0189      * Get the ip property
0190      *
0191      * @return string
0192      */
0193     public function getIp()
0194     {
0195         return $this->_ip;
0196     }
0197 
0198     /**
0199      * Set a single parameter
0200      *
0201      * @param string $key
0202      * @param string $value
0203      * @return Zend_Service_ReCaptcha
0204      */
0205     public function setParam($key, $value)
0206     {
0207         $this->_params[$key] = $value;
0208 
0209         return $this;
0210     }
0211 
0212     /**
0213      * Set parameters
0214      *
0215      * @param array|Zend_Config $params
0216      * @return Zend_Service_ReCaptcha
0217      * @throws Zend_Service_ReCaptcha_Exception
0218      */
0219     public function setParams($params)
0220     {
0221         if ($params instanceof Zend_Config) {
0222             $params = $params->toArray();
0223         }
0224 
0225         if (is_array($params)) {
0226             foreach ($params as $k => $v) {
0227                 $this->setParam($k, $v);
0228             }
0229         } else {
0230             /** @see Zend_Service_ReCaptcha_Exception */
0231             // require_once 'Zend/Service/ReCaptcha/Exception.php';
0232 
0233             throw new Zend_Service_ReCaptcha_Exception(
0234                 'Expected array or Zend_Config object'
0235             );
0236         }
0237 
0238         return $this;
0239     }
0240 
0241     /**
0242      * Get the parameter array
0243      *
0244      * @return array
0245      */
0246     public function getParams()
0247     {
0248         return $this->_params;
0249     }
0250 
0251     /**
0252      * Get a single parameter
0253      *
0254      * @param string $key
0255      * @return mixed
0256      */
0257     public function getParam($key)
0258     {
0259         return $this->_params[$key];
0260     }
0261 
0262     /**
0263      * Set a single option
0264      *
0265      * @param string $key
0266      * @param string $value
0267      * @return Zend_Service_ReCaptcha
0268      */
0269     public function setOption($key, $value)
0270     {
0271         $this->_options[$key] = $value;
0272 
0273         return $this;
0274     }
0275 
0276     /**
0277      * Set options
0278      *
0279      * @param array|Zend_Config $options
0280      * @return Zend_Service_ReCaptcha
0281      * @throws Zend_Service_ReCaptcha_Exception
0282      */
0283     public function setOptions($options)
0284     {
0285         if ($options instanceof Zend_Config) {
0286             $options = $options->toArray();
0287         }
0288 
0289         if (is_array($options)) {
0290             foreach ($options as $k => $v) {
0291                 $this->setOption($k, $v);
0292             }
0293         } else {
0294             /** @see Zend_Service_ReCaptcha_Exception */
0295             // require_once 'Zend/Service/ReCaptcha/Exception.php';
0296 
0297             throw new Zend_Service_ReCaptcha_Exception(
0298                 'Expected array or Zend_Config object'
0299             );
0300         }
0301 
0302         return $this;
0303     }
0304 
0305     /**
0306      * Get the options array
0307      *
0308      * @return array
0309      */
0310     public function getOptions()
0311     {
0312         return $this->_options;
0313     }
0314 
0315     /**
0316      * Get a single option
0317      *
0318      * @param string $key
0319      * @return mixed
0320      */
0321     public function getOption($key)
0322     {
0323         return $this->_options[$key];
0324     }
0325 
0326     /**
0327      * Get the public key
0328      *
0329      * @return string
0330      */
0331     public function getPublicKey()
0332     {
0333         return $this->_publicKey;
0334     }
0335 
0336     /**
0337      * Set the public key
0338      *
0339      * @param string $publicKey
0340      * @return Zend_Service_ReCaptcha
0341      */
0342     public function setPublicKey($publicKey)
0343     {
0344         $this->_publicKey = $publicKey;
0345 
0346         return $this;
0347     }
0348 
0349     /**
0350      * Get the private key
0351      *
0352      * @return string
0353      */
0354     public function getPrivateKey()
0355     {
0356         return $this->_privateKey;
0357     }
0358 
0359     /**
0360      * Set the private key
0361      *
0362      * @param string $privateKey
0363      * @return Zend_Service_ReCaptcha
0364      */
0365     public function setPrivateKey($privateKey)
0366     {
0367         $this->_privateKey = $privateKey;
0368 
0369         return $this;
0370     }
0371 
0372     /**
0373      * Get the HTML code for the captcha
0374      *
0375      * This method uses the public key to fetch a recaptcha form.
0376      *
0377      * @param  null|string $name Base name for recaptcha form elements
0378      * @return string
0379      * @throws Zend_Service_ReCaptcha_Exception
0380      */
0381     public function getHtml($name = null)
0382     {
0383         if ($this->_publicKey === null) {
0384             /** @see Zend_Service_ReCaptcha_Exception */
0385             // require_once 'Zend/Service/ReCaptcha/Exception.php';
0386 
0387             throw new Zend_Service_ReCaptcha_Exception('Missing public key');
0388         }
0389 
0390         $host = self::API_SERVER;
0391 
0392         if ((bool) $this->_params['ssl'] === true) {
0393             $host = self::API_SECURE_SERVER;
0394         }
0395 
0396         $htmlBreak = '<br>';
0397         $htmlInputClosing = '>';
0398 
0399         if ((bool) $this->_params['xhtml'] === true) {
0400             $htmlBreak = '<br />';
0401             $htmlInputClosing = '/>';
0402         }
0403 
0404         $errorPart = '';
0405 
0406         if (!empty($this->_params['error'])) {
0407             $errorPart = '&error=' . urlencode($this->_params['error']);
0408         }
0409 
0410         $reCaptchaOptions = '';
0411 
0412         if (!empty($this->_options)) {
0413             $encoded = Zend_Json::encode($this->_options);
0414             $reCaptchaOptions = <<<SCRIPT
0415 <script type="text/javascript">
0416     var RecaptchaOptions = {$encoded};
0417 </script>
0418 SCRIPT;
0419         }
0420         $challengeField = 'recaptcha_challenge_field';
0421         $responseField  = 'recaptcha_response_field';
0422         if (!empty($name)) {
0423             $challengeField = $name . '[' . $challengeField . ']';
0424             $responseField  = $name . '[' . $responseField . ']';
0425         }
0426 
0427         $return = $reCaptchaOptions;
0428         $return .= <<<HTML
0429 <script type="text/javascript"
0430    src="{$host}/challenge?k={$this->_publicKey}{$errorPart}">
0431 </script>
0432 HTML;
0433         $return .= <<<HTML
0434 <noscript>
0435    <iframe src="{$host}/noscript?k={$this->_publicKey}{$errorPart}"
0436        height="300" width="500" frameborder="0"></iframe>{$htmlBreak}
0437    <textarea name="{$challengeField}" rows="3" cols="40">
0438    </textarea>
0439    <input type="hidden" name="{$responseField}"
0440        value="manual_challenge"{$htmlInputClosing}
0441 </noscript>
0442 HTML;
0443 
0444         return $return;
0445     }
0446 
0447     /**
0448      * Post a solution to the verify server
0449      *
0450      * @param string $challengeField
0451      * @param string $responseField
0452      * @return Zend_Http_Response
0453      * @throws Zend_Service_ReCaptcha_Exception
0454      */
0455     protected function _post($challengeField, $responseField)
0456     {
0457         if ($this->_privateKey === null) {
0458             /** @see Zend_Service_ReCaptcha_Exception */
0459             // require_once 'Zend/Service/ReCaptcha/Exception.php';
0460 
0461             throw new Zend_Service_ReCaptcha_Exception('Missing private key');
0462         }
0463 
0464         if ($this->_ip === null) {
0465             /** @see Zend_Service_ReCaptcha_Exception */
0466             // require_once 'Zend/Service/ReCaptcha/Exception.php';
0467 
0468             throw new Zend_Service_ReCaptcha_Exception('Missing ip address');
0469         }
0470 
0471         /* Fetch an instance of the http client */
0472         $httpClient = self::getHttpClient();
0473         $httpClient->resetParameters(true);
0474 
0475         $postParams = array('privatekey' => $this->_privateKey,
0476                             'remoteip'   => $this->_ip,
0477                             'challenge'  => $challengeField,
0478                             'response'   => $responseField);
0479 
0480         /* Make the POST and return the response */
0481         return $httpClient->setUri(self::VERIFY_SERVER)
0482                           ->setParameterPost($postParams)
0483                           ->request(Zend_Http_Client::POST);
0484     }
0485 
0486     /**
0487      * Verify the user input
0488      *
0489      * This method calls up the post method and returns a
0490      * Zend_Service_ReCaptcha_Response object.
0491      *
0492      * @param string $challengeField
0493      * @param string $responseField
0494      * @return Zend_Service_ReCaptcha_Response
0495      */
0496     public function verify($challengeField, $responseField)
0497     {
0498         $response = $this->_post($challengeField, $responseField);
0499 
0500         return new Zend_Service_ReCaptcha_Response(null, null, $response);
0501     }
0502 }