Object-oriented or procedural?

As I mentioned in the previous post, I needed a CAPTCHA algorithm. As I couldn’t find anything simple and usable that would do what I want (ie follow the basic principles of captcha creation (readibility for humans, and hopefully unreadibility for machines)), I decided to write my own. The purpose of this was just to generate the image, I left generating the text, passing it in a secure way and all the other boring stuff for others. And as an exercise, I’ve done both procedural and object-oriented versions.

I’m not an expert on object oriented programming, so my little class could have probably been written in a better (read: longer and even more confusing) way. Anyway, here it is:

[code lang=”php”]/**
* @name TasuCaptcha
* @author Vit ‘tasuki’ Brunner
* @license GNU GPL
* @version 0.001
*
* remarks:
* you need php (duh)
* you need gd
* you need the font file, in the same directory as this
* (get it at http://www.sil.org/~gaultney/gentium/ )
*
* if you want to use antialiased line, you need function drawQSLine()
* get it from http://php.net/manual/function.imageline.php
* code_couturier at graffiti dot net
* # antialiased draw_line function 1.1 (faster)
*/

class TasuCaptcha {
private $bg;
private $fg;

// picture
public $width; // width of the picture
public $height; // height of the picture

// letters
public $font; // font for the letters
public $fontHeight; // height of the letters
public $maxAngle; // maximum angle for the letters
public $top; // where the letters should start – y
public $left; // where the letters should start – x
public $letterWidth; // approximate width of each letter

// line
public $step; // the length of line between turns
public $stepDiff; // the max height difference for step
public $lineBorder; // borders for the middle line
public $thickness; // thickness of the line
public $antialiased; // if true, makes the line antialiased

function __construct($text) {
// picture
$this->width = 170;
$this->height = 50;
$bgColor = ‘113355’;
$fgColor = ‘CCCCCC’;

// letters
$this->text = $text;
$this->font = ‘./gentium.ttf’;
$this->fontHeight = 25;
$this->maxAngle = 15;
$this->top = 35;
$this->left = 10;
$this->letterWidth = 30;

// center line
$this->step = 5;
$this->stepDiff = 5;
$this->lineBorder = 15;
$this->thickness = 2;
$this->antialiased = false;

$this->setBgColor($bgColor);
$this->setFgColor($fgColor);
}

function setBgColor($color) {
if (strlen($color) != ‘6’) die(‘setBgColor needs 6 letter hex color’);
$this->bg[‘r’] = hexdec(substr($color, 0, 2));
$this->bg[‘g’] = hexdec(substr($color, 2, 2));
$this->bg[‘b’] = hexdec(substr($color, 4, 2));
}
function setFgColor($color) {
if (strlen($color) != ‘6’) die(‘setFgColor needs 6 letter hex color’);
$this->fg[‘r’] = hexdec(substr($color, 0, 2));
$this->fg[‘g’] = hexdec(substr($color, 2, 2));
$this->fg[‘b’] = hexdec(substr($color, 4, 2));
}

function drawImage() {
// create image and set colors
$im = imagecreatetruecolor($this->width, $this->height);
$background = imagecolorallocate($im,
$this->bg[‘r’], $this->bg[‘g’], $this->bg[‘b’]);
imagefill($im, 0, 0, $background);
$textcolor = imagecolorallocate($im,
$this->fg[‘r’], $this->fg[‘g’], $this->fg[‘b’]);

// draw letters
for ($i = 0; $i < strlen($this->text); $i++) {
$this->angle = rand(- $this->maxAngle, $this->maxAngle);
imagettftext($im, $this->fontHeight, $this->angle,
$this->left + $this->letterWidth * $i, $this->top,
$textcolor, $this->font, $this->text{$i});
}

// draw the line
$curheight = $this->height / 2;
for ($i = 0; $i < ($this->width / $this->step); $i++) {
$lastheight = $curheight;
$curheight = $curheight + rand(-$this->stepDiff, $this->stepDiff);
if ($curheight > $this->height – $this->lineBorder)
$curheight -= $this->stepDiff;
if ($curheight < $this->lineBorder)
$curheight += $this->stepDiff;

// this could be done better…
for ($j = 0; $j < $this->thickness; $j++) {
if ($this->antialiased) // draw antialiased line
drawQSLine($im, $this->step * $i, $lastheight – $j,
$this->step * $i + $this->step, $curheight – $j,
$this->fg[‘r’], $this->fg[‘g’], $this->fg[‘b’]);
else // draw aliased line
imageline($im, $this->step * $i, $lastheight – $j,
$this->step * $i + $this->step, $curheight – $j,
$textcolor);
}
}

// output the image
header(‘Content-type: image/png’);
imagepng($im);
imagedestroy($im);

// maybe someone could find this useful
return $this->text;
}
}

// now we can try to use it:
$captcha = new TasuCaptcha($cnum);
$captcha->antialiased = true;
$captcha->drawImage();[/code]

Well, that was long, wasn’t it? And most of the time we were just moving values around… $this->shit = $shit;

Now the procedural version:

[code lang=”php”]/**
* @name tasucaptcha
* @author Vit ‘tasuki’ Brunner
* @license GNU GPL
* @version 0.001
*
* remarks:
* you need php (duh)
* you need gd
* you need the font file, in the same directory as this
* (get it at http://www.sil.org/~gaultney/gentium/ )
*
* if you want to use antialiased line, you need function drawQSLine()
* get it from http://php.net/manual/function.imageline.php
* code_couturier at graffiti dot net
* # antialiased draw_line function 1.1 (faster)
*/

function tasucaptcha($text) {
// picture
$width = 170; // width of the picture
$height = 50; // height of the picture
$bgcolor = ‘113355’; // please keep this 6 letters long
$fgcolor = ‘CCCCCC’; // please keep this 6 letters long

// letters
$font = ‘./gentium.ttf’; // font for the letters
$fontHeight = 25; // height of the letters
$maxAngle = 15; // maximum angle for the letters
$top = 35; // where the letters should start – y
$left = 10; // where the letters should start – x
$letterWidth = 30; // approximate width of each letter

// center line
$step = 5; // the length of line between turns
$stepdiff = 5; // the max height difference for step
$lineBorder = 15; // borders for the middle line
$thickness = 2; // thickness of the line
$antialiased = false; // if true, makes the line antialiased

// END OF SETTINGS

// get colors
$bg[‘r’] = hexdec(substr($bgcolor, 0, 2));
$bg[‘g’] = hexdec(substr($bgcolor, 2, 2));
$bg[‘b’] = hexdec(substr($bgcolor, 4, 2));
$color[‘r’] = hexdec(substr($fgcolor, 0, 2));
$color[‘g’] = hexdec(substr($fgcolor, 2, 2));
$color[‘b’] = hexdec(substr($fgcolor, 4, 2));

// set up the image
$im = imagecreatetruecolor($width, $height);
$background = imagecolorallocate($im, $bg[‘r’], $bg[‘g’], $bg[‘b’]);
imagefill($im, 0, 0, $background);
$textcolor = imagecolorallocate($im, $color[‘r’], $color[‘g’], $color[‘b’]);

// draw letters
for ($i = 0; $i < strlen($text); $i++) { $angle = rand(-$maxAngle, $maxAngle); imagettftext($im, $fontHeight, $angle, $left + $letterWidth*$i, $top, $textcolor, $font, $text{$i}); } // draw the line $curheight = $height/2; for ($i = 0; $i < ($width / $step); $i++) { $lastheight = $curheight; $curheight = $curheight + rand(-$stepdiff, $stepdiff); if ($curheight > $height – $lineBorder) $curheight -= $stepdiff;
if ($curheight < $lineBorder) $curheight += $stepdiff; // for ($j = 0; $j < $thickness; $j++) { if ($antialiased) // create antialiased line drawQSLine($im, $step * $i, $lastheight - $j, $step * $i + $step, $curheight - $j, $color['r'], $color['g'], $color['b']); else // draw aliased line imageline($im, $step * $i, $lastheight - $j, $step * $i + $step, $curheight - $j, $textcolor); } } // draw the image header('Content-type: image/png'); imagepng($im); imagedestroy($im); return $text; } tasucaptcha($cnum);[/code] Unless one is paid by lines of code, one must conclude that the second version is much better. It's half as long and twice as readable. As for the captcha itself -- I can't guarantee that the results are machine-unreadable, but at least they are human readable. :-)

One thought on “Object-oriented or procedural?

Comments are closed.