Ian Marsh

28 Dec, 2007

Flickcha - PHP4

Posted by: Ian In: PHP

We deal with a lot of spam and bots on devbump and after a vulnerability was found in the version of captcha we were using for human verification I had to code a simple math test in its place. That solution is extremely trivial to bypass and so I started looking at alternatives. There are some interesting ones that use pictures instread of garbled numbers which I liked but the ones I saw just rotated a fixed number of images (probably easier to bypass than captcha if one tried). The solution I decided to try and code up was one that used pictures grabbed from flickr which will never be seen twice. So here is my attempt in a PHP4 class with example usage. Feel free to point out any glaringly obvious flaws in it that I might have missed. It does take some time to grab the images since it has to hit as many xml feeds as the number of images you use. It is also a good idea to use tag names that wouldn't normally be associated with eachother to avoid ambiguous images.
Example usage:

PHP:
  1. $flickcha = new Flickcha("kitten,hamster,bird");
  2. if(isset($_POST['submit'])) {
  3.     if($flickcha->validate())
  4.         echo "Welcome human.";
  5.     else
  6.         echo "Bad robot.";
  7. }
  8. else {
  9.     echo("<form action='$PHP_SELF' method='post' name='commentform'><p>");
  10.     $flickcha->formPrint('commentform');
  11.     echo("<p><input name='submit' type='submit' id='submit' value='Submit' /></form>");
  12. }

Click in order: kitten, hamster, bird

PHP:
  1. /**
  2. *  Flickcha class, for human verification
  3. *  Author: Ian Marsh
  4. *  Version 0.1
  5. **/
  6. class Flickcha {
  7.     var $tags;    // tags for photos used in verification
  8.    
  9.     /**
  10.      * Constructor: Contructs a new Flickcha
  11.      **/
  12.     function Flickcha($pass = "puppy,kitten,fish") {
  13.         $this->tags = explode(",", $pass);
  14.     }
  15.    
  16.     /**
  17.      * Validate: Return true if code was corrent, false if not
  18.      **/
  19.     function validate() {
  20.         if(md5($_POST['flickcha']) == $_POST['flickchaKey'])
  21.             return true;
  22.         else
  23.             return false;
  24.     }
  25.    
  26.     /**
  27.      * formPrint: Prints necessary code for html form.
  28.      **/
  29.      function formPrint($formID) {
  30.         // Print instructions
  31.         echo("<div id='flickchaInstructions'>Click in order: ");
  32.         $len = count($this->tags);
  33.         for($i = 0; $i <$len; $i++)
  34.             echo($this->tags[$i].($i == $len-1 ?'':', '));
  35.         echo("</div>")
  36.     
  37.         // Print out flickr photos in random order
  38.         $randTags = $this->tags;
  39.         shuffle($randTags);
  40.         for($i = 0; $i <$len; $i++) {
  41.             $rtag = $randTags[$i];
  42.             echo("<div style='display:inline' class='flickchaThumb' id='thumb$i'>");
  43.             echo("<img class='flickchaImg' src='".$this->getThumb($rtag)."' ");
  44.             echo("onClick=\"document.$formID.flickcha.value+='$i';document.getElementById('thumb$i').style.display='none';\" /></div>");
  45.         }
  46.        
  47.         // Encode correct code
  48.         $key = '';
  49.         for($i = 0; $i <$len; $i++) {
  50.             $key .= array_search($this->tags[$i], $randTags);
  51.         }
  52.         echo("<input type='hidden' name='flickchaKey' value='".md5($key)."' />");
  53.         echo("<input type='hidden' name='flickcha' value='' />");
  54.      }
  55.     
  56.      /**
  57.       * getThumb: Returns url for a flickr img of a given tag
  58.       **/
  59.      function getThumb($tag, $timeout = 10) {
  60.         $ch = curl_init();
  61.         curl_setopt($ch, CURLOPT_URL, "http://api.flickr.com/services/feeds/photos_public.gne?tags=".$tag);
  62.         curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  63.         curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
  64.         $feed = curl_exec($ch);
  65.         curl_close($ch);
  66.         $a = strpos($feed, "img src=&quot;") + 14;
  67.         $b = strpos($feed, "_m.jpg", $a);
  68.         return substr($feed, $a, $b-$a)."_s.jpg";
  69.      }
  70. }

1 Response to "Flickcha - PHP4"

1 | Yousuf Philips

July 21st, 2008 at 12:22 am

Avatar

Just a note, some countries block flickr, like here in the United Arab Emirates (UAE), so it might be a good idea to temporarily locally cache the file from flickr to solve this issue.

Comment Form


  • Bernard: Thank you for this wonderful game it is superbly. My partner is blind she can just see a little, I write the nine letters on an A4 sheet in felt pen a
  • Jean: Hi Ian, I was just checking, but Scoops is just for iTouch and iPhones? Is it possible to make it available for iPod Nanos? because they still have t
  • John GIBSON: Hi Ian; Once again, congratulations on Scoops. The game truly epitomises everything that the iPhone stands for. I understand you starting this