<?php
/**
*
* @author Benjamin Gillissen <hide@address.com>
*
* **************************************************************
Copyright (C) 2009 Benjamin Gillissen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details at:
http://www.gnu.org/copyleft/gpl.html
* **************************************************************
*/
class captcha {
private $acceptedChars = 'ABCDEFGHIJKLMNPQRSTUVWXYZ123456789';
private $stringlength = 4;
private $contrast = 60; // A value between 0 and 100 describing how much color overlap
// there is between text and other objects. Lower is more
// secure against bots, but also harder to read.
private $num_polygons = 3; // Number of triangles to draw. 0 = none
private $num_ellipses = 2; // Number of ellipses to draw. 0 = none
private $num_lines = 2; // Number of lines to draw. 0 = none
private $num_dots = 3; // Number of dots to draw. 0 = none
private $min_thickness = 2; // Minimum thickness in pixels of lines
private $max_thickness = 8; // Maximum thickness in pixles of lines
private $min_radius = 5; // Minimum radius in pixels of ellipses
private $max_radius = 15; // Maximum radius in pixels of ellipses
private $object_alpha = 80; // How opaque should the obscuring objects be. 0 is opaque, 127 is transparent.
private $o_contrast;
private $width;
private $height;
private $img;
public function __construct(){
//TODO check needed functions, drop fatal if missing
}
public function sendimage($key){
$this->buildimage($key);
header('Content-type: image/png');
imagepng($this->img);
}
public function genkey(){
$max = strlen($this->acceptedChars)-1;
$o = '';
for($i=0; $i < $this->stringlength; $i++) {
$o .= $this->acceptedChars{mt_rand(0, $max)};
}
return $o;
}
private function buildimage($pass){
if ( empty($pass) ){ $pass = ' ? '; }
// Keep #'s reasonable.
$this->min_thickness = max(1,$this->min_thickness);
$this->max_thickness = min(20,$this->max_thickness);
// Make radii into height/width
$this->min_radius *= 2;
$this->max_radius *= 2;
// Renormalize contrast
$this->contrast = 255 * ($this->contrast / 100.0);
$this->o_contrast = 1.3 * $this->contrast;
$this->width = 15 * imagefontwidth ($this->stringlength+1);
$this->height = 2.2 * imagefontheight ($this->stringlength+1);
$this->img = imagecreatetruecolor ($this->width, $this->height);
imagealphablending($this->img, true);
imagecolorallocatealpha($this->img,0,0,0,0);
$this->addstring($pass);
$this->addpoly();
$this->addcircles();
$this->addlines();
$this->adddots();
}
private function addstring($pass){
$c=$this->stringlength;
for($i=0; $i < $this->stringlength; $i++) {
$chars[$i] = substr($pass, ($this->stringlength-$c), 1 );
$c--;
}
// Add string to image
$rotated = imagecreatetruecolor (70, 70);
$x=0;
for ($i = 0; $i < $this->stringlength; $i++) {
$buffer = imagecreatetruecolor (20, 20);
$buffer2 = imagecreatetruecolor (40, 40);
// Get a random color
$red = mt_rand(0,255);
$green = mt_rand(0,255);
$blue = 255 - sqrt($red * $red + $green * $green);
$color = imagecolorallocate ($buffer, $red, $green, $blue);
// Create character
imagestring($buffer, 5, 0, 0, $chars[$i], $color);
// Resize character
imagecopyresized ($buffer2, $buffer, 0, 0, 0, 0, 25 + mt_rand(0,12), 25 + mt_rand(0,12), 20, 20);
// Rotate characters a little
$rotated = imagerotate($buffer2, mt_rand(-25, 25),imagecolorallocatealpha($buffer2,0,0,0,0));
imagecolortransparent ($rotated, imagecolorallocatealpha($rotated,0,0,0,0));
// Move characters around a little
$y = mt_rand(1, 3);
$x += mt_rand(2, 6);
imagecopymerge ($this->img, $rotated, $x, $y, 0, 0, 40, 40, 100);
$x += 22;
imagedestroy ($buffer);
imagedestroy ($buffer2);
}
}
private function addpoly(){
// Draw polygons
if ($this->num_polygons > 0) for ($i = 0; $i < $this->num_polygons; $i++) {
$vertices = array (
mt_rand(-0.25*$this->width,$this->width*1.25),mt_rand(-0.25*$this->width,$this->width*1.25),
mt_rand(-0.25*$this->width,$this->width*1.25),mt_rand(-0.25*$this->width,$this->width*1.25),
mt_rand(-0.25*$this->width,$this->width*1.25),mt_rand(-0.25*$this->width,$this->width*1.25)
);
$color = imagecolorallocatealpha ( $this->img,
mt_rand(0,$this->o_contrast),
mt_rand(0,$this->o_contrast),
mt_rand(0,$this->o_contrast),
$this->object_alpha
);
imagefilledpolygon($this->img, $vertices, 3, $color);
}
}
private function addcircles(){
// Draw random circles
if ($this->num_ellipses > 0) for ($i = 0; $i < $this->num_ellipses; $i++) {
$x1 = mt_rand(0,$this->width);
$y1 = mt_rand(0,$this->height);
$color = imagecolorallocatealpha ( $this->img,
mt_rand(0,$this->o_contrast),
mt_rand(0,$this->o_contrast),
mt_rand(0,$this->o_contrast),
$this->object_alpha
);
imagefilledellipse( $this->img,
$x1,
$y1,
mt_rand($this->min_radius,$this->max_radius),
mt_rand($this->min_radius,$this->max_radius),
$color
);
}
}
private function addlines(){
// Draw random lines
if ($this->num_lines > 0) for ($i = 0; $i < $this->num_lines; $i++) {
$x1 = mt_rand(-$this->width*0.25,$this->width*1.25);
$y1 = mt_rand(-$this->height*0.25,$this->height*1.25);
$x2 = mt_rand(-$this->width*0.25,$this->width*1.25);
$y2 = mt_rand(-$this->height*0.25,$this->height*1.25);
$color = imagecolorallocatealpha ( $this->img,
mt_rand(0,$this->o_contrast),
mt_rand(0,$this->o_contrast),
mt_rand(0,$this->o_contrast),
$this->object_alpha
);
imagesetthickness ($this->img, mt_rand($this->min_thickness,$this->max_thickness));
imageline($this->img, $x1, $y1, $x2, $y2 , $color);
}
}
private function adddots(){
// Draw random dots
if ($this->num_dots > 0) for ($i = 0; $i < $this->num_dots; $i++) {
$x1 = mt_rand(0,$this->width);
$y1 = mt_rand(0,$this->height);
$color = imagecolorallocatealpha ( $this->img,
mt_rand(0,$this->o_contrast),
mt_rand(0,$this->o_contrast),
mt_rand(0,$this->o_contrast),
$this->object_alpha
);
imagesetpixel($this->img, $x1, $y1, $color);
}
}
}