Free Animated Captcha - HelloCaptcha


/ Published in: PHP
Save to your folder(s)

PHP class to create animated CAPTCHAs


Copy this code and paste it in your HTML
  1. <?php
  2.  
  3. /**
  4.  
  5.   * This file contains the HelloCaptcha class that is the essential
  6.  
  7.   * PHP class for embedding HelloCaptcha CAPTCHAs.
  8.  
  9.   *
  10.  
  11.   * The most recent version of this file can be downloaded from:
  12.  
  13.   * http://www.hellocaptcha.com/dl/HelloCaptcha.class.php
  14.  
  15.   *
  16.  
  17.   * A sample file that demonstrates how to use this class can be
  18.  
  19.   * downloaded from:
  20.  
  21.   * http://www.hellocaptcha.com/dl/sample-captcha.php
  22.  
  23.   *
  24.  
  25.   * PHP versions before 5.2 do not have JSON support enabled. To solve
  26.  
  27.   * this issue download JSON.php from our server and place it near the
  28.  
  29.   * HelloCaptcha.class.php file. The HelloCaptcha.class.php file
  30.  
  31.   * automatically includes it if neccessary. The file can be downloaded
  32.  
  33.   * from:
  34.  
  35.   * http://www.hellocaptcha.com/dl/JSON.php
  36.  
  37.   *
  38.  
  39.   * @see http://www.hellocaptcha.com
  40.  
  41.   * @see http://www.hellocaptcha.com/doc/embedding
  42.  
  43.   * @Copyright Program Produkt, 2010-2011
  44.  
  45.   */
  46.  
  47.  
  48.  
  49. /** Version */
  50.  
  51. define("HELLOCAPTCHA_VERSION", "1.0");
  52.  
  53. /** Release date */
  54.  
  55. define("HELLOCAPTCHA_RELEASE_DATE", "2011-02-07");
  56.  
  57.  
  58.  
  59. /**
  60.  
  61.   * This if will be used, if profile is not set. You can override this
  62.  
  63.   * constant by defining it before including this file.
  64.  
  65.   */
  66.  
  67. define("HELLOCAPTCHA_TRIAL_PROFILE_ID", "hellocaptchatrialprofile");
  68.  
  69. /** HelloCaptcha service domain */
  70.  
  71. define("HELLOCAPTCHA_SERVER_DOMAIN", "service.hellocaptcha.com");
  72.  
  73. /** Path for verifying user's answer */
  74.  
  75. define("HELLOCAPTCHA_GET_NEW_TEST_PATH", "/getnewtest/");
  76.  
  77. /** Path for verifying user's answer */
  78.  
  79. define("HELLOCAPTCHA_VERIFY_ANSWER_PATH", "/verifyanswer/");
  80.  
  81.  
  82.  
  83. /** Error codes for getNewTest */
  84.  
  85. define("HELLOCAPTCHA_ERROR_1", "The profile named profileid does not exist.");
  86.  
  87. define("HELLOCAPTCHA_ERROR_2", "There is no pre-rendered CAPTCHA in the profile pool, yet. Please wait, until HelloCaptcha server generates the CAPTCHA animations.");
  88.  
  89.  
  90.  
  91. /** Error codes for verifyAnswer */
  92.  
  93. define("HELLOCAPTCHA_ERROR_3", "The Turing test identified by turingtestid does not exist.");
  94.  
  95. define("HELLOCAPTCHA_ERROR_4", "Either test turingtestid or answer is empty.");
  96.  
  97. define("HELLOCAPTCHA_ERROR_5", "The Turing test was already verified once.");
  98.  
  99. define("HELLOCAPTCHA_ERROR_6", "The Turing test is expired.");
  100.  
  101. define("HELLOCAPTCHA_ERROR_7", "There are too many bad tries (on a retryable CAPTCHA).");
  102.  
  103.  
  104.  
  105. /**
  106.  
  107.   * Class that wraps functionality of HelloCaptcha service by implementing HTTP based
  108.  
  109.   * communication and creating wrapper methods for HelloCaptcha service. This class
  110.  
  111.   * should be used if someone needs custom functionality of this service. The HelloCaptcha
  112.  
  113.   * class is based on the functions of this class.
  114.  
  115.   *
  116.  
  117.   * @version 1.0
  118.  
  119.   */
  120.  
  121. class HelloCaptchaWrapper {
  122.  
  123.  
  124.  
  125. /**
  126.  
  127.   * Converts an error code to string
  128.  
  129.   *
  130.  
  131.   * @param int $p_error_code
  132.  
  133.   * @return string response
  134.  
  135.   */
  136.  
  137. public static function errorCodeToString( $p_errorcode ) {
  138.  
  139. $cn = "HELLOCAPTCHA_ERROR_" . $p_errorcode;
  140.  
  141. if ( defined( $cn ) )
  142.  
  143. return constant( $cn );
  144.  
  145. else
  146.  
  147. return "Unknown error.";
  148.  
  149. }
  150.  
  151.  
  152.  
  153. /**
  154.  
  155.   * Submits an HTTP POST to a server and returns its result.
  156.  
  157.   *
  158.  
  159.   * @param string $p_host
  160.  
  161.   * @param string $p_path
  162.  
  163.   * @param array $p_data
  164.  
  165.   * @param int $p_port
  166.  
  167.   * @return string response
  168.  
  169.   */
  170.  
  171. private static function doHTTPPost( $p_host, $p_path, $p_data, $p_port = 80 ) {
  172.  
  173.  
  174.  
  175. // Url encode the passed values
  176.  
  177. $request = Array();
  178.  
  179. foreach ( $p_data as $key => $value ) {
  180.  
  181. $request[] = $key . '=' . urlencode( stripslashes($value) );
  182.  
  183. }
  184.  
  185. $request = implode('&', $request);
  186.  
  187.  
  188.  
  189. // Create HTTP request string
  190.  
  191. $http_request = "POST $p_path HTTP/1.0
  192. ";
  193.  
  194. $http_request .= "Host: $p_host
  195. ";
  196.  
  197. $http_request .= "Content-Type: application/x-www-form-urlencoded;
  198. ";
  199.  
  200. $http_request .= "Content-Length: " . strlen($request) . "
  201. ";
  202.  
  203. $http_request .= "User-Agent: HELLOCAPTCHA/PHP
  204. ";
  205.  
  206. $http_request .= "
  207. ";
  208.  
  209. $http_request .= $request;
  210.  
  211.  
  212.  
  213. // Connect to server
  214.  
  215. if( false == ( $fs = @fsockopen($p_host, $p_port, $errno, $errstr, 10) ) )
  216.  
  217. throw new Exception( __METHOD__ . ': Cannot connect to server: ' . $p_host . ' on port: ' . $p_port . '.' );
  218.  
  219.  
  220.  
  221. // Do the request
  222.  
  223. fwrite($fs, $http_request);
  224.  
  225.  
  226.  
  227. // Get the response
  228.  
  229. $response = '';
  230.  
  231. while ( !feof($fs) ) {
  232.  
  233. // One TCP-IP packet
  234.  
  235. $response .= fgets($fs, 1160);
  236.  
  237. }
  238.  
  239.  
  240.  
  241. // Disconnect from the server
  242.  
  243. fclose($fs);
  244.  
  245.  
  246.  
  247. // Return the response
  248.  
  249. return $response;
  250.  
  251. }
  252.  
  253.  
  254.  
  255. /**
  256.  
  257.   * Decodes a server response response is valid. If the response contains an exception
  258.  
  259.   * then throws it.
  260.  
  261.   */
  262.  
  263. protected static function decodeResponse( $p_response ) {
  264.  
  265. $p_response = explode("
  266.  
  267. ", $p_response, 2);
  268.  
  269. $p_response = $p_response[1];
  270.  
  271.  
  272.  
  273. // Check response for trivial errors
  274.  
  275. if ( is_null( $p_response ) )
  276.  
  277. throw new Exception( __METHOD__ . ': Server response is NULL.' );
  278.  
  279. if ( empty( $p_response ) )
  280.  
  281. throw new Exception( __METHOD__ . ': Server response is EMPTY.' );
  282.  
  283.  
  284.  
  285. // JSON decode
  286.  
  287. $response = json_decode( $p_response, TRUE );
  288.  
  289. if ( NULL === $response )
  290.  
  291. throw new Exception( __METHOD__ . ': Error decoding server response.' );
  292.  
  293.  
  294.  
  295. // Check for exception
  296.  
  297. if ( !empty( $response['e'] ) )
  298.  
  299. throw new Exception( __METHOD__ . ': Server returned an error: ' . $response['e']['message'], $response['e']['code'] );
  300.  
  301.  
  302.  
  303. // Return value if not empty
  304.  
  305. if ( empty( $response['d'] ) )
  306.  
  307. throw new Exception( __METHOD__ . ': Server returned empty data' );
  308.  
  309. return $response['d'];
  310.  
  311. }
  312.  
  313.  
  314.  
  315. /**
  316.  
  317.   * Calls remote service and return the result.
  318.  
  319.   *
  320.  
  321.   * @param string $p_path
  322.  
  323.   * @param array $p_data
  324.  
  325.   * @return array response
  326.  
  327.   */
  328.  
  329. protected static function callRemote( $p_path, $p_data ) {
  330.  
  331.  
  332.  
  333. // Post data over HTTP
  334.  
  335. $response = self::doHTTPPost( HELLOCAPTCHA_SERVER_DOMAIN, $p_path, $p_data );
  336.  
  337.  
  338.  
  339. // Decode and return response
  340.  
  341. $response = self::decodeResponse( $response );
  342.  
  343. return $response;
  344.  
  345. }
  346.  
  347.  
  348.  
  349. /**
  350.  
  351.   * Creates a new Turing test and returns the received result.
  352.  
  353.   *
  354.  
  355.   * @param string $p_profileid
  356.  
  357.   * @return array response
  358.  
  359.   */
  360.  
  361. public function getNewTest( $p_profileid = HELLOCAPTCHA_TRIAL_PROFILE_ID ) {
  362.  
  363.  
  364.  
  365. // Call remote service
  366.  
  367. return self::callRemote(
  368.  
  369. HELLOCAPTCHA_GET_NEW_TEST_PATH,
  370.  
  371. Array( 'profileid' => $p_profileid )
  372.  
  373. );
  374.  
  375. }
  376.  
  377.  
  378.  
  379. /**
  380.  
  381.   * Checks the answer for a given Turing test.
  382.  
  383.   *
  384.  
  385.   * @param string $p_turingtestid
  386.  
  387.   * @param string $p_answer
  388.  
  389.   * @return array response
  390.  
  391.   */
  392.  
  393. public function verifyAnswer( $p_turingtestid, $p_answer ) {
  394.  
  395.  
  396.  
  397. // Assert Turing test id is not empty
  398.  
  399. if ( empty( $p_turingtestid ) )
  400.  
  401. 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/ .");
  402.  
  403. // Assert answer is not empty
  404.  
  405. if ( empty( $p_answer ) )
  406.  
  407. die (__METHOD__ . ": Answer is empty. Please specify answer to let the system know what to evaluate.");
  408.  
  409.  
  410.  
  411. // Call remote service
  412.  
  413. return self::callRemote(
  414.  
  415. HELLOCAPTCHA_VERIFY_ANSWER_PATH,
  416.  
  417. Array( 'turingtestid' => $p_turingtestid, 'answer' => $p_answer )
  418.  
  419. );
  420.  
  421. }
  422.  
  423.  
  424.  
  425. }
  426.  
  427.  
  428.  
  429. /**
  430.  
  431.   * Class that provides high level functionality for HelloCaptcha service.
  432.  
  433.   * This class uses the low level methods of HelloCaptchaWrapper class. If you need
  434.  
  435.   * custom behaviour, you can create a custom class (MyHelloCaptcha) by modifying this
  436.  
  437.   * class or by derivating from it.
  438.  
  439.   */
  440.  
  441. class HelloCaptcha extends HelloCaptchaWrapper {
  442.  
  443.  
  444.  
  445. /**
  446.  
  447.   * Asks for a new test on HelloCaptcha server and returns a default
  448.  
  449.   * embedding code for the CAPTCHA of the given profile.
  450.  
  451.   */
  452.  
  453. public static function getEmbedCode( $p_profileid = HELLOCAPTCHA_TRIAL_PROFILE_ID ) {
  454.  
  455. try {
  456.  
  457. // Call wrapper method, and return the ready-made part of the answer.
  458.  
  459. $res = self::getNewTest( $p_profileid );
  460.  
  461. return $res['html'];
  462.  
  463. } catch (Exception $e) {
  464.  
  465. echo "Error acquiring HelloCaptcha embedding code. " . self::errorCodeToString( $e->getCode() );
  466.  
  467. error_log( __METHOD__ . ": Unexpected error occured. Error message: " . self::errorCodeToString( $e->getCode() ) );
  468.  
  469. error_log( __METHOD__ . ": Unexpected error occured. HelloCaptcha server said: " . $e->getMessage() );
  470.  
  471. }
  472.  
  473. }
  474.  
  475.  
  476.  
  477. public static function checkAnswer( $p_turingtestid, $p_answer ) {
  478.  
  479. try {
  480.  
  481. // Call wrapper method, and return the validity of the answer.
  482.  
  483. $res = self::verifyAnswer( $p_turingtestid, $p_answer );
  484.  
  485. return $res['is_valid'];
  486.  
  487. } catch (Exception $e) {
  488.  
  489. echo "Error checking user answer for HelloCaptcha. " . self::errorCodeToString( $e->getCode() ) . "<br />";
  490.  
  491. error_log( __METHOD__ . ": Unexpected error occured. Error message: " . self::errorCodeToString( $e->getCode() ) );
  492.  
  493. error_log( __METHOD__ . ": Unexpected error occured. HelloCaptcha server said: " . $e->getMessage() );
  494.  
  495. return false;
  496.  
  497. }
  498.  
  499. }
  500.  
  501.  
  502.  
  503. }
  504.  
  505.  
  506.  
  507. if ( !function_exists('json_decode') ) {
  508.  
  509. function json_decode($p_content, $p_assoc = true) {
  510.  
  511. require_once 'JSON.php';
  512.  
  513. if ( $p_assoc ) {
  514.  
  515. $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
  516.  
  517. } else {
  518.  
  519. $json = new Services_JSON;
  520.  
  521. }
  522.  
  523. return $json->decode($p_content);
  524.  
  525. }
  526.  
  527. }
  528.  
  529.  
  530.  
  531. if ( !function_exists('json_encode') ){
  532.  
  533. function json_encode($p_content){
  534.  
  535. require_once 'JSON.php';
  536.  
  537. $json = new Services_JSON;
  538.  
  539. return $json->encode($p_content);
  540.  
  541. }
  542.  
  543. }
  544.  
  545.  
  546.  
  547. ?>

URL: www.hellocaptcha.com

Report this snippet


Comments

RSS Icon Subscribe to comments

You need to login to post a comment.