Showing posts with label GD. Show all posts
Showing posts with label GD. Show all posts

Thursday, December 31, 2015

Simple Captcha Verification Using Javascript and PHP with GD Lib


This is a simple version that uses minimal amount of codes. However, this practice is not suitable for websites that require stringent security protection.

The PHP codes make use of the GD library to generate a PNG image file that will be read by the HTML code. The PHP will randomly generate two characters and two numbers with first digit as character followed by a number, then a character and a number. Of course, you can change it to something more complicated like making it a mathematical problem to be solved by the visitor. The PNG image will be accompanied by a browser cookie with the answer to the captcha. The cookie will then be compared with the input by the user to see if they match. You can also send the answer back to the server to be verified in order to make it more secure. However, it is not the scope of this example as I try to make it as simple as possible so that it is easy to understand.

Here are the PHP codes:

<?php

// I name this file captcha.php
error_reporting(0); // this is important to turn off all the warnings if any

session_start();

$angle = rand(-10,10);
$fontSize = 20;

$captchaText = chr(97 + rand(0, 25)).rand(0,9).chr(97 + rand(0, 25)).rand(0,9);


$img = imagecreatetruecolor(120, 50);
$bgColor = imagecolorallocate($img, rand(50,150), rand(50,150), rand(50,150)); //background color - random dark coolor
$fgColor = imagecolorallocate($img, rand(200,255), rand(200,255), rand(200,255)); //foreground color - random light color
imagefill($img, 0, 0, $bgColor);

imagettftext($img, $fontSize, $angle, 25, 35, $fgColor, "./LiberationSerif-Bold.ttf", $captchaText);

setcookie("randomCharacterCookieName", $captchaText, time()+3600, '/'); // will expire in one hour

header("Cache-Control: no-cache, must-revalidate");
header('Content-type: image/png');
imagepng($img);
imagedestroy($img);

?>


Make sure your PHP has the GD library support before you proceed.

The tricky part is the one highlighted in red. You need to upload a font to your home directory to make this PHP script to work. Why don't we use the server font? Most of the time, the shared server won't have any TrueType font in it or the GD doesn't have the authority to run it. It is still better to upload your own font and you have more choice for the font as well. I chose the Liberation font as it is royalty free. You can change to your own font if you prefer.

And now comes the Javascript and HTML:

<html>

<script>

function checkCaptcha() {
 var ans = document.getElementById('answer').value;
 var tmp = document.cookie;
 var chunk = tmp.split('=');
 if (chunk[chunk.length-1] == ans) {
  alert("yes!");
  // proceed with your post verification codes such submitting the form etc.
 }
 else {
 alert("no!");
 }
}

</script>

<body>
<img src="captcha.php">
<br>
Type what you see above here:
<br>
<input type="text" id=answer size=4 maxlength=4> <a href="javascript:checkCaptcha()">Check</a>

</body>

</html>


After running the HTML, I captured this response from Chrome after a right answer is entered:



I captured this response from Chrome after entering a wrong answer purposely:



There are still many things you can improve from these codes. For example, you can still include capital letter or even some special characters to the captcha. You can also scramble the answer in the cookie and descramble it during verification with the answer embedded in the cookie.

Well, here is the Captcha tutorial! Finally!

Read More »

Friday, December 21, 2012

Render Text in PNG Format using PHP GD2 in IIS Environment



The following example won't work if you are running GD version 1 in your PHP server. Some modications are required to make it work.

GD's imagettftext by default cannot set the spacing between characters. If you want to force spacing between characters, you can display each character at a time calculating the spacing your self using a loop.

However, there is one problem setting the spacing: each character's width is different. Therefore, the spacing varies depending on the width of each character.

We use imagettfbbox to measure the width of a character with a given font.

imagettfbbox is troublesome as it is using different requirement to specify the font location in IIS. For Linux environment, you also need to add './' in front of the relative font location. As for IIS, absolute font location is needed. dirname(__FILE__) is used to specify the absolute current script location.

If the font's location is not specified correctly, the error of "Warning: imagettfbbox(): Invalid font filename in ..." will be produced.

Even the location is specified correctly, imagettfbbox gives different result according to the GD version. The following example codes are targeted for GD version 2. If you are using GD version 1, you can modify the codes a bit to make it work.

For imagettfbbox in GD 2 environment, an array of 8 elements are returned. Each data in the array represents a x or y coordinate in the bounding box of a character:



For my case, I use x1 to deduct from x2 to get the width of the character.

Finally, enough said, here are the codes:


<?php

// Make sure you have the font arialbd.ttf in the ./font directory
// webtrick101.blogspot.com

$height = 40;
$width = 80;
$text = "test";
$font_space = 9; // You can change the font space here
$font_size = 19;
$angle = 0;
$x = 10;
$y = $height/2 + 7;
$color = 0; // text color black
$bgcolor = '#ffff00';
$font = 'fonts/arialbd.ttf';
$font2 = './fonts/arialbd.ttf';


$img = imagecreatetruecolor($width, $height);
imagefilledrectangle($img, 0, 0, $width - 1, $height - 1, gd_color($bgcolor));

$textlen = strlen($text);
for ($i = 0; $i < $textlen; $i++) {
 $charwidthArr = imagettfbbox(12, 0, dirname(__FILE__).'\\'.$font, $text[$i]);
 $charwidth = $charwidthArr[2] - $charwidthArr[0];
 imagettftext($img, $font_size, $angle, $x, $y, gd_color($color), $font2, $text[$i]);
 $x += $charwidth + $font_space;
}

header("Content-Type: image/png");
imagepng($img);
imagedestroy($img);


function gd_color($html_color) {
     return preg_match('/^#?([\dA-F]{6})$/i', $html_color, $rgb)
      ? hexdec($rgb[1]) : false;
}

?>


Read More »