Location: PHPKode > projects > Hello Captcha > HelloCaptcha.class.php
<?php

/**

  * This file contains the HelloCaptcha class that is the essential

  * PHP class for embedding HelloCaptcha CAPTCHAs.

  * 

  * The most recent version of this file can be downloaded from:

  * http://www.hellocaptcha.com/dl/HelloCaptcha.class.php

  *

  * A sample file that demonstrates how to use this class can be

  * downloaded from:

  * http://www.hellocaptcha.com/dl/sample-captcha.php

  *

  * PHP versions before 5.2 do not have JSON support enabled. To solve

  * this issue download JSON.php from our server and place it near the

  * HelloCaptcha.class.php file. The HelloCaptcha.class.php file

  * automatically includes it if neccessary. The file can be downloaded

  * from:

  * http://www.hellocaptcha.com/dl/JSON.php

  *

  * @see http://www.hellocaptcha.com

  * @see http://www.hellocaptcha.com/doc/embedding

  * @Copyright Program Produkt, 2010-2011

  */

  

/** Version */

define("HELLOCAPTCHA_VERSION", "1.0");

/** Release date */

define("HELLOCAPTCHA_RELEASE_DATE", "2011-02-07");



/**

  * This if will be used, if profile is not set. You can override this

  * constant by defining it before including this file.

  */

define("HELLOCAPTCHA_TRIAL_PROFILE_ID", "hellocaptchatrialprofile");

/** HelloCaptcha service domain */

define("HELLOCAPTCHA_SERVER_DOMAIN", "service.hellocaptcha.com");

/** Path for verifying user's answer */

define("HELLOCAPTCHA_GET_NEW_TEST_PATH", "/getnewtest/");

/** Path for verifying user's answer */

define("HELLOCAPTCHA_VERIFY_ANSWER_PATH", "/verifyanswer/");



/** Error codes for getNewTest */

define("HELLOCAPTCHA_ERROR_1", "The profile named profileid does not exist.");

define("HELLOCAPTCHA_ERROR_2", "There is no pre-rendered CAPTCHA in the profile pool, yet. Please wait, until HelloCaptcha server generates the CAPTCHA animations.");



/** Error codes for verifyAnswer */

define("HELLOCAPTCHA_ERROR_3", "The Turing test identified by turingtestid does not exist.");

define("HELLOCAPTCHA_ERROR_4", "Either test turingtestid or answer is empty.");

define("HELLOCAPTCHA_ERROR_5", "The Turing test was already verified once.");

define("HELLOCAPTCHA_ERROR_6", "The Turing test is expired."); 

define("HELLOCAPTCHA_ERROR_7", "There are too many bad tries (on a retryable CAPTCHA)."); 



/**

  * Class that wraps functionality of HelloCaptcha service by implementing HTTP based

  * communication and creating wrapper methods for HelloCaptcha service. This class

  * should be used if someone needs custom functionality of this service. The HelloCaptcha

  * class is based on the functions of this class.

  *

  * @version 1.0

  */

class HelloCaptchaWrapper {



  /**

    * Converts an error code to string

    *

    * @param int $p_error_code

    * @return string response

    */

  public static function errorCodeToString( $p_errorcode ) {

    $cn = "HELLOCAPTCHA_ERROR_" . $p_errorcode;

    if ( defined( $cn ) )

      return constant( $cn );

    else

      return "Unknown error.";

  }



  /**

    * Submits an HTTP POST to a server and returns its result.

    *

    * @param string $p_host

    * @param string $p_path

    * @param array $p_data

    * @param int $p_port

    * @return string response

    */

  private static function doHTTPPost( $p_host, $p_path, $p_data, $p_port = 80 ) {



      // Url encode the passed values

    $request = Array();

    foreach ( $p_data as $key => $value ) {

      $request[] = $key . '=' . urlencode( stripslashes($value) );

    }

    $request = implode('&', $request);



    // Create HTTP request string

    $http_request  = "POST $p_path HTTP/1.0\r\n";

    $http_request .= "Host: $p_host\r\n";

    $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";

    $http_request .= "Content-Length: " . strlen($request) . "\r\n";

    $http_request .= "User-Agent: HELLOCAPTCHA/PHP\r\n";

    $http_request .= "\r\n";

    $http_request .= $request;



    // Connect to server

    if( false == ( $fs = @fsockopen($p_host, $p_port, $errno, $errstr, 10) ) )

      throw new Exception( __METHOD__ . ': Cannot connect to server: ' . $p_host . ' on port: ' . $p_port . '.' );



    // Do the request

    fwrite($fs, $http_request);



    // Get the response

    $response = '';

    while ( !feof($fs) ) {

      // One TCP-IP packet

      $response .= fgets($fs, 1160);

    }



    // Disconnect from the server

    fclose($fs);

    

    // Return the response

    return $response;

  }

  

  /**

    * Decodes a server response response is valid. If the response contains an exception

    * then throws it.

    */

  protected static function decodeResponse( $p_response ) {

    $p_response = explode("\r\n\r\n", $p_response, 2);

    $p_response = $p_response[1];



    // Check response for trivial errors

    if ( is_null( $p_response ) )

      throw new Exception( __METHOD__ . ': Server response is NULL.' );

    if ( empty( $p_response ) )

      throw new Exception( __METHOD__ . ': Server response is EMPTY.' );



    // JSON decode

    $response = json_decode( $p_response, TRUE );

    if ( NULL === $response )

      throw new Exception( __METHOD__ . ': Error decoding server response.' );



    // Check for exception

    if ( !empty( $response['e'] ) )

      throw new Exception( __METHOD__ . ': Server returned an error: ' . $response['e']['message'], $response['e']['code'] );



    // Return value if not empty

    if ( empty( $response['d'] ) )

      throw new Exception( __METHOD__ . ': Server returned empty data' );

    return $response['d'];

  }



  /**

    * Calls remote service and return the result.

    *

    * @param string $p_path

    * @param array $p_data

    * @return array response

    */

  protected static function callRemote( $p_path, $p_data ) {



    // Post data over HTTP

    $response = self::doHTTPPost( HELLOCAPTCHA_SERVER_DOMAIN, $p_path, $p_data );



    // Decode and return response

    $response = self::decodeResponse( $response );

    return $response;

  }



  /**

    * Creates a new Turing test and returns the received result.

    *

    * @param string $p_profileid

    * @return array response

    */

  public function getNewTest( $p_profileid = HELLOCAPTCHA_TRIAL_PROFILE_ID ) {



    // Call remote service

    return self::callRemote(

      HELLOCAPTCHA_GET_NEW_TEST_PATH,

      Array( 'profileid' => $p_profileid )

    );

  }

  

  /**

    * Checks the answer for a given Turing test.

    *

    * @param string $p_turingtestid

    * @param string $p_answer

    * @return array response

    */

  public function verifyAnswer( $p_turingtestid, $p_answer ) {

    

    // Assert Turing test id is not empty

    if ( empty( $p_turingtestid ) )

      die (__METHOD__ . ": Turing test id is empty. Please specify Turing test id to let the system know which test was completed. A new test id can be obtained on http://www.hellocaptcha.com/registration/ .");

    // Assert answer is not empty

    if ( empty( $p_answer ) )

      die (__METHOD__ . ": Answer is empty. Please specify answer to let the system know what to evaluate.");

    

    // Call remote service

    return self::callRemote(

      HELLOCAPTCHA_VERIFY_ANSWER_PATH,

      Array( 'turingtestid' => $p_turingtestid, 'answer' => $p_answer )

    );

  }

  

}



/**

  * Class that provides high level functionality for HelloCaptcha service.

  * This class uses the low level methods of HelloCaptchaWrapper class. If you need

  * custom behaviour, you can create a custom class (MyHelloCaptcha) by modifying this

  * class or by derivating from it.

  */

class HelloCaptcha extends HelloCaptchaWrapper {



  /**

    * Asks for a new test on HelloCaptcha server and returns a default

    * embedding code for the CAPTCHA of the given profile.

    */

  public static function getEmbedCode( $p_profileid = HELLOCAPTCHA_TRIAL_PROFILE_ID  ) {

    try {

      // Call wrapper method, and return the ready-made part of the answer.

      $res = self::getNewTest( $p_profileid );

      return $res['html'];

    } catch (Exception $e) {

      echo "Error acquiring HelloCaptcha embedding code. " . self::errorCodeToString( $e->getCode() );

      error_log( __METHOD__ . ": Unexpected error occured. Error message: " . self::errorCodeToString( $e->getCode() ) ); 

      error_log( __METHOD__ . ": Unexpected error occured. HelloCaptcha server said: " . $e->getMessage() ); 

    }

  }



  public static function checkAnswer( $p_turingtestid, $p_answer ) {

    try {

      // Call wrapper method, and return the validity of the answer.

      $res = self::verifyAnswer( $p_turingtestid, $p_answer );

      return $res['is_valid'];

    } catch (Exception $e) {

      echo "Error checking user answer for HelloCaptcha. " . self::errorCodeToString( $e->getCode() ) . "<br />";

      error_log( __METHOD__ . ": Unexpected error occured. Error message: " . self::errorCodeToString( $e->getCode() ) );

      error_log( __METHOD__ . ": Unexpected error occured. HelloCaptcha server said: " . $e->getMessage() );

      return false;

    }

  }



}



if ( !function_exists('json_decode') ) {

  function json_decode($p_content, $p_assoc = true) {

    require_once 'JSON.php';

    if ( $p_assoc ) {

      $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);

    } else {

      $json = new Services_JSON;

    }

    return $json->decode($p_content);

  }

}



if ( !function_exists('json_encode') ){

  function json_encode($p_content){

    require_once 'JSON.php';

    $json = new Services_JSON;

    return $json->encode($p_content);

  }

}



?>

Return current item: Hello Captcha