Wednesday, April 2, 2014

Yes, I did reinvent the wheel. I spent about 3 hours creating a Captcha type form validation script.

I had a custom form in a WordPress page that submitted to PHP form handler. I needed some type of Captcha style validation function. All the plugins I found used form plugins, and all the PHP scripts I found required me to insert PHP into the form itself, which I could not because the form code was in a post/page that does not allow server-side code. I know there are other plugins for that purpose also, but that had me looking at installing three different plugins to accomplish what I felt I could do myself.

Well, it took me way long than I though. I probably spent about 4 hours on it, but it looks like it works.
The form was getting a lot of spam from bots, so it wasn't a huge security issue, but just the annoyance to the client having to check 20 posts to get one legit one.

The form has an AJAX JS validator and also validates on the server-side using PHP, so I wanted I created the Captcha script in both places.

I needed to generate a random image and then get its value.

I used JS to randomly pull an image path from an array, and then assign that to the SRC of the random IMG.
This worked fine, but getting that value from PHP on POST end was a little tricky.

I had to also use a hidden input an assign its value the same random image path as the actual image, so on the server side I am comparing the user input string to the value of the hidden input string.

I had to use some fancy PHP string manipulation to trim down the path to get just the number in the file name. That number is the number that is in the image, and the number the user will try and match.

$match_ran_num = strip_tags( trim($_POST['match_ran_num'] ));
$randomImgValue = $_POST['randomImgValue'];
$randomImgValue = basename($randomImgValue);
$randomImgValue = basename($randomImgValue, '.jpg');
$randomImgValue = ltrim($randomImgValue,"randomImg_");

if($match_ran_num != $randomImgValue){return;};
On server-side I just kicked out of the function if the stings don't match. This took a little while, but was pretty straight forward.

Client-side, I edited the function that was already checking for any empty fields. Once it looped through all the form fields successfully, I checked the value of the input text to the generated image path. Once again having to trim down the random path to get to the number that was part of the image file name.

var randomImg_num = formData[19].value;
randomImg_num = randomImg_num.substr( randomImg_num.indexOf('_' ) +1);
randomImg_num = randomImg_num.substr( randomImg_num.indexOf('_' ) +1);
randomImg_num = randomImg_num.substr( 0,randomImg_num.indexOf('.' ) );

if(formData[20].value != randomImg_num)
{
alert('The number you entered does not match the number displayed.');
return false;
}
As I am writing this I just can't figure out what took me so long, but I did go down a few rabbit holes along the way. I didn't start out the hindsight clarity I now have.
I was an interesting work-around to using the tried and true Captcha that we all know and love.
Now I just need to wait and see if the random images are distorted enough, and if I made enough of them. Hopefully it's a done deal, but we'll see.

No comments:

Post a Comment