Current File : //opt/RZphp73/includes/Services/ReCaptcha.php
<?php

/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */

/**
 * This file is part of the PEAR Services_ReCaptcha package.
 *
 * PHP version 5
 *
 * LICENSE: This source file is subject to the MIT license that is available
 * through the world-wide-web at the following URI:
 * http://opensource.org/licenses/mit-license.php
 *
 * @category  Services
 * @package   Services_ReCaptcha
 * @author    David Jean Louis <izi@php.net>
 * @copyright 2008-2009 David Jean Louis
 * @license   http://opensource.org/licenses/mit-license.php MIT License 
 * @version   CVS: $Id$
 * @link      http://pear.php.net/package/Services_ReCaptcha
 * @link      http://recaptcha.net/apidocs/captcha/client.html
 * @since     File available since release 0.1.0
 * @filesource
 */

/**
 * Dependencies.
 */
require_once 'Services/ReCaptcha/Base.php';
require_once 'HTTP/Request2.php';
 
/**
 * PHP5 interface to the reCATCHA API.
 *
 * reCAPTCHA is a freely available CAPTCHA implementation. It distinguishes 
 * humans from computers.
 *
 * In order to use reCAPTCHA, you need a public/private API key pair. This key 
 * pair helps to prevent an attack where somebody hosts a reCAPTCHA on their 
 * website, collects answers from their visitors and submits the answers to 
 * your site. You can sign up for a key on the
 * {@link http://recaptcha.net/api/getkey reCAPTCHA Administration Portal}
 *
 * @category  Services
 * @package   Services_ReCaptcha
 * @author    David Jean Louis <izi@php.net>
 * @copyright 2008-2009 David Jean Louis
 * @license   http://opensource.org/licenses/mit-license.php MIT License 
 * @version   Release: @package_version@
 * @link      http://pear.php.net/package/Services_ReCaptcha
 * @link      http://recaptcha.net/apidocs/captcha/client.html
 * @since     Class available since release 0.1.0
 * @example   examples/example-01.php Services_ReCaptcha simple example
 * @example   examples/example-02.php Services_ReCaptcha advanced example
 */
class Services_ReCaptcha extends Services_ReCaptcha_Base
{
    // properties {{{

    /**
     * The reCAPTCHA API URL.
     *
     * @var string $apiURL
     */
    public $apiURL = 'https://www.google.com/recaptcha/api';

    /**
     * The reCAPTCHA API secure URL, this is URL is used by default when the 
     * script is running on an https host or when you force it via the 'secure' 
     * option.
     *
     * @var string $apiSecureURL
     */
    public $apiSecureURL = 'https://www.google.com/recaptcha/api';

    /**
     * Url of the ReCaptcha verify API.
     *
     * @var string $apiVerifyURL
     */
    public $apiVerifyURL = 'http://www.google.com/recaptcha/api/verify';

    /**
     * The error code used to display the error message in the captcha.
     *
     * @var string $error
     * @see Services_ReCaptcha::getError()
     * @see Services_ReCaptcha::setError()
     */
    protected $error;

    /**
     * Options to customize the html, the url and the look and feel of the captcha.
     * Available options are:
     *   - secure: whether to force the ssl url (default: false);
     *   - xhtml: whether the html should be xhtml compliant (default: true);
     *   - theme: string, defines which theme to use for reCAPTCHA (default: red);
     *   - lang: string, one of the supported language codes (default: en);
     *   - custom_translations: array, se this to specify custom translations 
     *     of reCAPTCHA strings (default: null).
     *   - custom_theme_widget: string, the ID of a DOM element (default: null);
     *   - tabindex: integer, the tabindex for the reCAPTCHA text area.
     * 
     * For a full documentation of theses options please consult the  
     * {@link http://recaptcha.net/apidocs/captcha/client.html API documentation}.
     *
     * @var array $options
     * @see Services_ReCaptcha_Base::getOption()
     * @see Services_ReCaptcha_Base::setOption()
     * @see Services_ReCaptcha_Base::getOptions()
     * @see Services_ReCaptcha_Base::setOptions()
     */
    protected $options = array(
        'secure'              => false,
        'xhtml'               => true,
        'theme'               => null,
        'lang'                => null,
        'custom_translations' => null,
        'custom_theme_widget' => null,
        'tabindex'            => null,
    );

    /**
     * The HTTP_Request2 instance.
     *
     * You can customize the request if you need to (ie: if you use a proxy)
     * with the get/setRequest() methods, for example:
     *
     * <code>
     * require_once 'Services/ReCaptcha.php';
     *
     * $recaptcha = new Services_ReCaptcha('pubkey', 'privkey');
     * $recaptcha->getRequest()->setConfig(array(
     *     'proxy_host' => 'localhost',
     *     'proxy_port' => 8118,
     * ));
     * </code>
     *
     * @var HTTP_Request2 $request
     * @see Services_ReCaptcha::getRequest()
     * @see Services_ReCaptcha::setRequest()
     */
    protected $request;

    // }}}
    // __construct() {{{
    
    /**
     * Constructor, you must pass a valid public and private API key.
     *
     * @param string $pubKey  The public API key (mandatory)
     * @param string $privKey The private API key (mandatory)
     * @param array  $options An array of options (optional)
     * 
     * @see Services_ReCaptcha::$options
     * @return void
     */
    public function __construct($pubKey, $privKey, array $options = array()) 
    {
        parent::__construct($pubKey, $privKey, $options);
    }
    
    // }}}
    // getURL() {{{
    
    /**
     * Returns the URL of the script or iframe src attribute.
     *
     * @param string $path Set this to "noscript" to get the iframe URL instead 
     *                     of the script URL
     *
     * @return string The URL of the script or iframe src attribute
     */
    public function getURL($path = 'challenge')
    {
        // in order to avoid getting browser warnings, if we have an SSL web 
        // site we use the secure url
        if ($this->options['secure'] 
            || (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on')
        ) {
            $url = $this->apiSecureURL;
        } else {
            $url = $this->apiURL;
        }

        $url .= '/' . $path . '?k=' . $this->apiPublicKey;
        if ($this->error !== null) {
            $url .= '&error=' . urlencode($this->error);
        }
        return $url;
    }
    
    // }}}
    // getHTML() {{{
    
    /**
     * Returns the HTML code to insert into your form.
     *
     * Instead of this method you can use the __toString() magic method to get 
     * the HTML code, for example:
     *
     * <code>
     * require_once 'Services/ReCaptcha.php';
     *
     * $recaptcha = new Services_ReCaptcha('pubkey', 'privkey');
     * // both are equivalents:
     * $html = $recaptcha->getHTML();
     * $html = (string) $recaptcha;
     * </code>
     *
     * @return string The HTML to include in your webpage
     * @see Services_ReCaptcha_Base::__toString()
     */
    public function getHTML()
    {
        $return = '';
        // we use array_slice to get only look and feel options, and
        // array_filter to filter null keys
        $options = array_filter(array_slice($this->options, 2));

        // whether to be xhtml or html compliant
        if ($this->options['xhtml']) {
            $br  = '<br/>';
            $end = '/>';
        } else {
            $br  = '<br>';
            $end = '>';
        }

        if (!empty($options)) {
            $opts    = json_encode($options);
            $return .= <<<HTML
<script type="text/javascript">
    var RecaptchaOptions = $opts;
</script>

HTML;
        }
        $scriptURL = $this->getURL();
        $iframeURL = $this->getURL('noscript');
        $return   .= <<<HTML
<script type="text/javascript" src="{$scriptURL}"></script>
<noscript>
    <iframe src="{$iframeURL}" height="300" width="500" frameborder="0">
    </iframe>
    $br
    <textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
    <input type="hidden" name="recaptcha_response_field" value="manual_challenge"$end
</noscript>

HTML;
        return $return;
    }
    
    // }}}
    // validate() {{{
    
    /**
     * Validates the challenge response typed by the user and returns true if 
     * the challenge response is ok or false otherwise.
     *
     * You can explicitely pass the challenge, response and ip values if for 
     * some reason you need to do so.
     *
     * @param string $challenge Value of the challenge field, if not given, the
     *                          method will look for the value in $_POST array
     * @param string $response  Value of the response field, if not given, the
     *                          method will look for the value in $_POST array
     * @param int    $ip        The user IP address, if not given, the method 
     *                          will use $_SERVER['REMOTE_ADDR']
     *
     * @return bool Whether the challenge response is valid or not
     * @throws Services_ReCaptcha_Exception When the request cannot be sent
     * @throws Services_ReCaptcha_HTTPException When the server returns an 
     *                                          error response
     */
    public function validate($challenge = null, $response = null, $ip = null)
    {
        if ($challenge === null && isset($_POST['recaptcha_challenge_field'])) {
            $challenge = $_POST['recaptcha_challenge_field'];
        }
        if ($response === null && isset($_POST['recaptcha_response_field'])) {
            $response = $_POST['recaptcha_response_field'];
        }
        if ($ip === null && isset($_SERVER['REMOTE_ADDR'])) {
            $ip = $_SERVER['REMOTE_ADDR'];
        }

        if (!$challenge || !$response) {
            // Don't send a request if challenge or response is empty
            $this->setError('incorrect-captcha-sol');
            return false;
        }

        try {
            $request = clone $this->getRequest();
            $request->setMethod(HTTP_Request2::METHOD_POST);
            $request->setUrl($this->apiVerifyURL);
            $params = array(
                'privatekey' => $this->apiPrivateKey,
                'remoteip'   => $ip,
                'challenge'  => $challenge,
                'response'   => $response,
            );
            $request->addPostParameter($params);
            $httpResponse = $request->send();
        } catch (Exception $exc) {
            throw new Services_ReCaptcha_Exception(
                $exc->getMessage(),
                $exc
            );
        }

        if ($httpResponse->getStatus() != 200) {
            throw new Services_ReCaptcha_HTTPException(
                $httpResponse->getReasonPhrase(),
                $httpResponse->getStatus(),
                $httpResponse
            );
        }

        $body = explode("\n", $httpResponse->getBody(), 2);
        if (count($body) != 2) {
            $this->setError('unknown');
            return false;
        }
        if ($body[0] != 'true') {
            $this->setError($body[1]);
            return false;
        }

        return true;
    }
    
    // }}}
    // getError() {{{

    /**
     * Returns the current error code.
     *
     * @return string The error code
     * @see Services_ReCaptcha::$error
     */
    public function getError()
    {
        return $this->error;
    }

    // }}}
    // setError() {{{

    /**
     * Sets the error code to display in the captcha and returns the current 
     * Services_ReCaptcha instance.
     *
     * @param string $error The error message
     *
     * @return Services_ReCaptcha
     * @see Services_ReCaptcha::$error
     */
    public function setError($error)
    {
        $this->error = $error;
        return $this;
    }

    // }}}
    // getRequest() {{{
    
    /**
     * Returns the HTTP_Request2 instance, if it's not yet set it is 
     * instanciated on the fly.
     * 
     * @return HTTP_Request2 The request instance
     * @see Services_ReCaptcha::$request
     */
    public function getRequest()
    {
        if (!$this->request instanceof HTTP_Request2) {
            $this->request = new HTTP_Request2();
        }
        return $this->request;
    }
    
    // }}}
    // setRequest() {{{
    
    /**
     * Sets the HTTP_Request2 instance and returns the current 
     * Services_ReCaptcha instance.
     * 
     * @param HTTP_Request2 $request The request to set
     *
     * @return Services_ReCaptcha
     * @see Services_ReCaptcha::$request
     */
    public function setRequest(HTTP_Request2 $request)
    {
        $this->request = $request;
        return $this;
    }
    
    // }}}
}