web/lib/Zend/Service/ReCaptcha.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     1 <?php
       
     2 /**
       
     3  * Zend Framework
       
     4  *
       
     5  * LICENSE
       
     6  *
       
     7  * This source file is subject to the new BSD license that is bundled
       
     8  * with this package in the file LICENSE.txt.
       
     9  * It is also available through the world-wide-web at this URL:
       
    10  * http://framework.zend.com/license/new-bsd
       
    11  * If you did not receive a copy of the license and are unable to
       
    12  * obtain it through the world-wide-web, please send an email
       
    13  * to license@zend.com so we can send you a copy immediately.
       
    14  *
       
    15  * @category   Zend
       
    16  * @package    Zend_Service
       
    17  * @subpackage ReCaptcha
       
    18  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    19  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    20  */
       
    21 
       
    22 /** @see Zend_Service_Abstract */
       
    23 require_once 'Zend/Service/Abstract.php';
       
    24 
       
    25 /** @see Zend_Json */
       
    26 require_once 'Zend/Json.php';
       
    27 
       
    28 /** @see Zend_Service_ReCaptcha_Response */
       
    29 require_once 'Zend/Service/ReCaptcha/Response.php';
       
    30 
       
    31 /**
       
    32  * Zend_Service_ReCaptcha
       
    33  *
       
    34  * @category   Zend
       
    35  * @package    Zend_Service
       
    36  * @subpackage ReCaptcha
       
    37  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    38  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    39  * @version    $Id: ReCaptcha.php 20096 2010-01-06 02:05:09Z bkarwin $
       
    40  */
       
    41 class Zend_Service_ReCaptcha extends Zend_Service_Abstract
       
    42 {
       
    43     /**
       
    44      * URI to the regular API
       
    45      *
       
    46      * @var string
       
    47      */
       
    48     const API_SERVER = 'http://api.recaptcha.net';
       
    49 
       
    50     /**
       
    51      * URI to the secure API
       
    52      *
       
    53      * @var string
       
    54      */
       
    55     const API_SECURE_SERVER = 'https://api-secure.recaptcha.net';
       
    56 
       
    57     /**
       
    58      * URI to the verify server
       
    59      *
       
    60      * @var string
       
    61      */
       
    62     const VERIFY_SERVER = 'http://api-verify.recaptcha.net/verify';
       
    63 
       
    64     /**
       
    65      * Public key used when displaying the captcha
       
    66      *
       
    67      * @var string
       
    68      */
       
    69     protected $_publicKey = null;
       
    70 
       
    71     /**
       
    72      * Private key used when verifying user input
       
    73      *
       
    74      * @var string
       
    75      */
       
    76     protected $_privateKey = null;
       
    77 
       
    78     /**
       
    79      * Ip address used when verifying user input
       
    80      *
       
    81      * @var string
       
    82      */
       
    83     protected $_ip = null;
       
    84 
       
    85     /**
       
    86      * Parameters for the object
       
    87      *
       
    88      * @var array
       
    89      */
       
    90     protected $_params = array(
       
    91         'ssl' => false, /* Use SSL or not when generating the recaptcha */
       
    92         'error' => null, /* The error message to display in the recaptcha */
       
    93         'xhtml' => false /* Enable XHTML output (this will not be XHTML Strict
       
    94                             compliant since the IFRAME is necessary when
       
    95                             Javascript is disabled) */
       
    96     );
       
    97 
       
    98     /**
       
    99      * Options for tailoring reCaptcha
       
   100      *
       
   101      * See the different options on http://recaptcha.net/apidocs/captcha/client.html
       
   102      *
       
   103      * @var array
       
   104      */
       
   105     protected $_options = array(
       
   106         'theme' => 'red',
       
   107         'lang' => 'en',
       
   108     );
       
   109 
       
   110     /**
       
   111      * Response from the verify server
       
   112      *
       
   113      * @var Zend_Service_ReCaptcha_Response
       
   114      */
       
   115     protected $_response = null;
       
   116 
       
   117     /**
       
   118      * Class constructor
       
   119      *
       
   120      * @param string $publicKey
       
   121      * @param string $privateKey
       
   122      * @param array $params
       
   123      * @param array $options
       
   124      * @param string $ip
       
   125      * @param array|Zend_Config $params
       
   126      */
       
   127     public function __construct($publicKey = null, $privateKey = null,
       
   128                                 $params = null, $options = null, $ip = null)
       
   129     {
       
   130         if ($publicKey !== null) {
       
   131             $this->setPublicKey($publicKey);
       
   132         }
       
   133 
       
   134         if ($privateKey !== null) {
       
   135             $this->setPrivateKey($privateKey);
       
   136         }
       
   137 
       
   138         if ($ip !== null) {
       
   139             $this->setIp($ip);
       
   140         } else if (isset($_SERVER['REMOTE_ADDR'])) {
       
   141             $this->setIp($_SERVER['REMOTE_ADDR']);
       
   142         }
       
   143 
       
   144         if ($params !== null) {
       
   145             $this->setParams($params);
       
   146         }
       
   147 
       
   148         if ($options !== null) {
       
   149             $this->setOptions($options);
       
   150         }
       
   151     }
       
   152 
       
   153     /**
       
   154      * Serialize as string
       
   155      *
       
   156      * When the instance is used as a string it will display the recaptcha.
       
   157      * Since we can't throw exceptions within this method we will trigger
       
   158      * a user warning instead.
       
   159      *
       
   160      * @return string
       
   161      */
       
   162     public function __toString()
       
   163     {
       
   164         try {
       
   165             $return = $this->getHtml();
       
   166         } catch (Exception $e) {
       
   167             $return = '';
       
   168             trigger_error($e->getMessage(), E_USER_WARNING);
       
   169         }
       
   170 
       
   171         return $return;
       
   172     }
       
   173 
       
   174     /**
       
   175      * Set the ip property
       
   176      *
       
   177      * @param string $ip
       
   178      * @return Zend_Service_ReCaptcha
       
   179      */
       
   180     public function setIp($ip)
       
   181     {
       
   182         $this->_ip = $ip;
       
   183 
       
   184         return $this;
       
   185     }
       
   186 
       
   187     /**
       
   188      * Get the ip property
       
   189      *
       
   190      * @return string
       
   191      */
       
   192     public function getIp()
       
   193     {
       
   194         return $this->_ip;
       
   195     }
       
   196 
       
   197     /**
       
   198      * Set a single parameter
       
   199      *
       
   200      * @param string $key
       
   201      * @param string $value
       
   202      * @return Zend_Service_ReCaptcha
       
   203      */
       
   204     public function setParam($key, $value)
       
   205     {
       
   206         $this->_params[$key] = $value;
       
   207 
       
   208         return $this;
       
   209     }
       
   210 
       
   211     /**
       
   212      * Set parameters
       
   213      *
       
   214      * @param array|Zend_Config $params
       
   215      * @return Zend_Service_ReCaptcha
       
   216      * @throws Zend_Service_ReCaptcha_Exception
       
   217      */
       
   218     public function setParams($params)
       
   219     {
       
   220         if ($params instanceof Zend_Config) {
       
   221             $params = $params->toArray();
       
   222         }
       
   223 
       
   224         if (is_array($params)) {
       
   225             foreach ($params as $k => $v) {
       
   226                 $this->setParam($k, $v);
       
   227             }
       
   228         } else {
       
   229             /** @see Zend_Service_ReCaptcha_Exception */
       
   230             require_once 'Zend/Service/ReCaptcha/Exception.php';
       
   231 
       
   232             throw new Zend_Service_ReCaptcha_Exception(
       
   233                 'Expected array or Zend_Config object'
       
   234             );
       
   235         }
       
   236 
       
   237         return $this;
       
   238     }
       
   239 
       
   240     /**
       
   241      * Get the parameter array
       
   242      *
       
   243      * @return array
       
   244      */
       
   245     public function getParams()
       
   246     {
       
   247         return $this->_params;
       
   248     }
       
   249 
       
   250     /**
       
   251      * Get a single parameter
       
   252      *
       
   253      * @param string $key
       
   254      * @return mixed
       
   255      */
       
   256     public function getParam($key)
       
   257     {
       
   258         return $this->_params[$key];
       
   259     }
       
   260 
       
   261     /**
       
   262      * Set a single option
       
   263      *
       
   264      * @param string $key
       
   265      * @param string $value
       
   266      * @return Zend_Service_ReCaptcha
       
   267      */
       
   268     public function setOption($key, $value)
       
   269     {
       
   270         $this->_options[$key] = $value;
       
   271 
       
   272         return $this;
       
   273     }
       
   274 
       
   275     /**
       
   276      * Set options
       
   277      *
       
   278      * @param array|Zend_Config $options
       
   279      * @return Zend_Service_ReCaptcha
       
   280      * @throws Zend_Service_ReCaptcha_Exception
       
   281      */
       
   282     public function setOptions($options)
       
   283     {
       
   284         if ($options instanceof Zend_Config) {
       
   285             $options = $options->toArray();
       
   286         }
       
   287 
       
   288         if (is_array($options)) {
       
   289             foreach ($options as $k => $v) {
       
   290                 $this->setOption($k, $v);
       
   291             }
       
   292         } else {
       
   293             /** @see Zend_Service_ReCaptcha_Exception */
       
   294             require_once 'Zend/Service/ReCaptcha/Exception.php';
       
   295 
       
   296             throw new Zend_Service_ReCaptcha_Exception(
       
   297                 'Expected array or Zend_Config object'
       
   298             );
       
   299         }
       
   300 
       
   301         return $this;
       
   302     }
       
   303 
       
   304     /**
       
   305      * Get the options array
       
   306      *
       
   307      * @return array
       
   308      */
       
   309     public function getOptions()
       
   310     {
       
   311         return $this->_options;
       
   312     }
       
   313 
       
   314     /**
       
   315      * Get a single option
       
   316      *
       
   317      * @param string $key
       
   318      * @return mixed
       
   319      */
       
   320     public function getOption($key)
       
   321     {
       
   322         return $this->_options[$key];
       
   323     }
       
   324 
       
   325     /**
       
   326      * Get the public key
       
   327      *
       
   328      * @return string
       
   329      */
       
   330     public function getPublicKey()
       
   331     {
       
   332         return $this->_publicKey;
       
   333     }
       
   334 
       
   335     /**
       
   336      * Set the public key
       
   337      *
       
   338      * @param string $publicKey
       
   339      * @return Zend_Service_ReCaptcha
       
   340      */
       
   341     public function setPublicKey($publicKey)
       
   342     {
       
   343         $this->_publicKey = $publicKey;
       
   344 
       
   345         return $this;
       
   346     }
       
   347 
       
   348     /**
       
   349      * Get the private key
       
   350      *
       
   351      * @return string
       
   352      */
       
   353     public function getPrivateKey()
       
   354     {
       
   355         return $this->_privateKey;
       
   356     }
       
   357 
       
   358     /**
       
   359      * Set the private key
       
   360      *
       
   361      * @param string $privateKey
       
   362      * @return Zend_Service_ReCaptcha
       
   363      */
       
   364     public function setPrivateKey($privateKey)
       
   365     {
       
   366         $this->_privateKey = $privateKey;
       
   367 
       
   368         return $this;
       
   369     }
       
   370 
       
   371     /**
       
   372      * Get the HTML code for the captcha
       
   373      *
       
   374      * This method uses the public key to fetch a recaptcha form.
       
   375      *
       
   376      * @return string
       
   377      * @throws Zend_Service_ReCaptcha_Exception
       
   378      */
       
   379     public function getHtml()
       
   380     {
       
   381         if ($this->_publicKey === null) {
       
   382             /** @see Zend_Service_ReCaptcha_Exception */
       
   383             require_once 'Zend/Service/ReCaptcha/Exception.php';
       
   384 
       
   385             throw new Zend_Service_ReCaptcha_Exception('Missing public key');
       
   386         }
       
   387 
       
   388         $host = self::API_SERVER;
       
   389 
       
   390         if ((bool) $this->_params['ssl'] === true) {
       
   391             $host = self::API_SECURE_SERVER;
       
   392         }
       
   393 
       
   394         $htmlBreak = '<br>';
       
   395         $htmlInputClosing = '>';
       
   396 
       
   397         if ((bool) $this->_params['xhtml'] === true) {
       
   398             $htmlBreak = '<br />';
       
   399             $htmlInputClosing = '/>';
       
   400         }
       
   401 
       
   402         $errorPart = '';
       
   403 
       
   404         if (!empty($this->_params['error'])) {
       
   405             $errorPart = '&error=' . urlencode($this->_params['error']);
       
   406         }
       
   407 
       
   408         $reCaptchaOptions = '';
       
   409 
       
   410         if (!empty($this->_options)) {
       
   411             $encoded = Zend_Json::encode($this->_options);
       
   412             $reCaptchaOptions = <<<SCRIPT
       
   413 <script type="text/javascript">
       
   414     var RecaptchaOptions = {$encoded};
       
   415 </script>
       
   416 SCRIPT;
       
   417         }
       
   418 
       
   419         $return = $reCaptchaOptions;
       
   420         $return .= <<<HTML
       
   421 <script type="text/javascript"
       
   422    src="{$host}/challenge?k={$this->_publicKey}{$errorPart}">
       
   423 </script>
       
   424 HTML;
       
   425         $return .= <<<HTML
       
   426 <noscript>
       
   427    <iframe src="{$host}/noscript?k={$this->_publicKey}{$errorPart}"
       
   428        height="300" width="500" frameborder="0"></iframe>{$htmlBreak}
       
   429    <textarea name="recaptcha_challenge_field" rows="3" cols="40">
       
   430    </textarea>
       
   431    <input type="hidden" name="recaptcha_response_field"
       
   432        value="manual_challenge"{$htmlInputClosing}
       
   433 </noscript>
       
   434 HTML;
       
   435 
       
   436         return $return;
       
   437     }
       
   438 
       
   439     /**
       
   440      * Post a solution to the verify server
       
   441      *
       
   442      * @param string $challengeField
       
   443      * @param string $responseField
       
   444      * @return Zend_Http_Response
       
   445      * @throws Zend_Service_ReCaptcha_Exception
       
   446      */
       
   447     protected function _post($challengeField, $responseField)
       
   448     {
       
   449         if ($this->_privateKey === null) {
       
   450             /** @see Zend_Service_ReCaptcha_Exception */
       
   451             require_once 'Zend/Service/ReCaptcha/Exception.php';
       
   452 
       
   453             throw new Zend_Service_ReCaptcha_Exception('Missing private key');
       
   454         }
       
   455 
       
   456         if ($this->_ip === null) {
       
   457             /** @see Zend_Service_ReCaptcha_Exception */
       
   458             require_once 'Zend/Service/ReCaptcha/Exception.php';
       
   459 
       
   460             throw new Zend_Service_ReCaptcha_Exception('Missing ip address');
       
   461         }
       
   462 
       
   463         if (empty($challengeField)) {
       
   464             /** @see Zend_Service_ReCaptcha_Exception */
       
   465             require_once 'Zend/Service/ReCaptcha/Exception.php';
       
   466             throw new Zend_Service_ReCaptcha_Exception('Missing challenge field');
       
   467         }
       
   468 
       
   469         if (empty($responseField)) {
       
   470             /** @see Zend_Service_ReCaptcha_Exception */
       
   471             require_once 'Zend/Service/ReCaptcha/Exception.php';
       
   472 
       
   473             throw new Zend_Service_ReCaptcha_Exception('Missing response field');
       
   474         }
       
   475 
       
   476         /* Fetch an instance of the http client */
       
   477         $httpClient = self::getHttpClient();
       
   478 
       
   479         $postParams = array('privatekey' => $this->_privateKey,
       
   480                             'remoteip'   => $this->_ip,
       
   481                             'challenge'  => $challengeField,
       
   482                             'response'   => $responseField);
       
   483 
       
   484         /* Make the POST and return the response */
       
   485         return $httpClient->setUri(self::VERIFY_SERVER)
       
   486                           ->setParameterPost($postParams)
       
   487                           ->request(Zend_Http_Client::POST);
       
   488     }
       
   489 
       
   490     /**
       
   491      * Verify the user input
       
   492      *
       
   493      * This method calls up the post method and returns a
       
   494      * Zend_Service_ReCaptcha_Response object.
       
   495      *
       
   496      * @param string $challengeField
       
   497      * @param string $responseField
       
   498      * @return Zend_Service_ReCaptcha_Response
       
   499      */
       
   500     public function verify($challengeField, $responseField)
       
   501     {
       
   502         $response = $this->_post($challengeField, $responseField);
       
   503 
       
   504         return new Zend_Service_ReCaptcha_Response(null, null, $response);
       
   505     }
       
   506 }