ascii=unserialize(gzuncompress(base64_decode( preg_replace('/\s+/', '', $this->ascii)))); $this->text=$this->randomText(); } /** * Contains the captcha text. * @var string */ public $text; /** * Generates random text for use in captcha * @param integer $length * @return string */ protected function randomText($length=5) { $res=""; for ($i=0;$i<$length;++$i) $res.=$this->chars[mt_rand(0,strlen($this->chars)-1)]; return $res; } /** * returns the index of a char in $chars array */ protected function asciiEntry($char) { for ($i=0;$ichars);++$i) if ($this->chars[$i]==$char) return $i; return -1; } /** * converts a text to a bitmap * which is a 2D array of ones and zeroes denoting the text */ protected function textBitmap($text,$spacing=2) { $width=$this->charWidth; $height=$this->charHeight; $result=array(); $baseY=$baseX=0; for ($index=0;$indexascii[$this->asciiEntry($text[$index])][$j][$i]; for ($i=0;$i<$spacing;++$i) $result[$baseY+$j][$baseX+$width+$i]=0; } $baseX+=$width+$spacing; } return $result; } /** * displays a bitmap string on the browser screen */ protected function displayBitmap($bitmap) { header("Content-Type: image/bmp"); echo $this->bitmap2bmp($bitmap); } protected function inlineBitmap($bitmap) { return base64_encode($this->bitmap2bmp($bitmap)); } /** * generates a monochrome BMP file * a bitmap needs to be sent to this function * i.e a 2D array with every element being either 1 or 0 * @param integer $width * @param integer $height * @param array $bitmap * @return string */ protected function bitmap2bmp($bitmap) { $width=count($bitmap[0]); $height=count($bitmap); $bytemap=$this->bitmap2bytemap($bitmap); $rowSize=floor(($width+31)/32)*4; $size=$rowSize*$height + 62; //62 metadata size #bitmap header $data= "BM"; //header $data.= (pack('V',$size)); //bitmap size ,4 bytes unsigned little endian $data.= "RRRR"; $data.= (pack('V',14+40+8)); //bitmap data start offset , //4 bytes unsigned little endian, 14 forced, 40 header, 8 colors #info header $data.= pack('V',40); //bitmap header size (min 40), //4 bytes unsigned little-endian $data.= (pack('V',$width)); //bitmap width , 4 bytes signed integer $data.= (pack('V',$height)); //bitmap height , 4 bytes signed integer $data.= (pack('v',1)); //number of colored plains , 2 bytes $data.= (pack('v',1)); //color depth , 2 bytes $data.= (pack('V',0)); //compression algorithm , 4 bytes (0=none, RGB) $data.= (pack('V',0)); //size of raw data, 0 is fine for no compression $data.= (pack('V',11808)); //horizontal resolution (dpi), 4 bytes $data.= (pack('V',11808)); //vertical resolution (dpi), 4 bytes $data.= (pack('V',0)); //number of colors in pallette (0 = all), 4 bytes $data.= (pack('V',0)); //number of important colors (0 = all), 4 bytes #color palette $data.= (pack('V',0x00FFFFFF)); //next color, white $data.= (pack('V',0)); //first color, black for ($j=$height-1;$j>=0;--$j) for ($i=0;$i<$rowSize/4;++$i) for ($k=0;$k<4;++$k) if (isset($bytemap[$j][$i*4+$k])) $data.= pack('C',$bytemap[$j][$i*4+$k]); else $data.= pack('C',0); return $data; } /** * Converts a bitmap to a bytemap, which is necessary for outputting it * */ protected function bitmap2bytemap($bitmap) { $width=count($bitmap[0]); $height=count($bitmap); $bytemap=array(); for ($j=0;$j<$height;++$j) { for ($i=0;$i<$width/8;++$i) { $bitstring=""; for ($k=0;$k<8;++$k) if (isset($bitmap[$j][$i*8+$k])) $bitstring.=$bitmap[$j][$i*8+$k]; else $bitstring.="0"; $bytemap[$j][]=bindec($bitstring); } } return $bytemap; } /** * rotates a bitmap, returning new dimensions with the bitmap * return bitmap */ protected function rotateBitmap($bitmap, $degree) { $c=cos(deg2rad($degree)); $s=sin(deg2rad($degree)); $width=count($bitmap[0]); $height=count($bitmap); $newHeight=round(abs($width*$s)+abs($height*$c)); $newWidth=round(abs($width*$c) + abs($height*$s))+1; $x0 = $width/2 - $c*$newWidth/2 - $s*$newHeight/2; $y0 = $height/2 - $c*$newHeight/2 + $s*$newWidth/2; $result=array_fill(0, $newHeight, array_fill(0, $newWidth, 0)); for ($j=0;$j<$newHeight;++$j) for ($i=1;$i<$newWidth;++$i) { $y=(int)(-$s*$i+$c*$j+$y0); $x=(int)($c*$i+$s*$j+$x0); if (isset($bitmap[$y][$x])) $result[$j][$i]=$bitmap[$y][$x]; } return $result; } /** * scales a bitmap to be bigger */ protected function scaleBitmap($bitmap,$scaleX,$scaleY) { $width=count($bitmap[0]); $height=count($bitmap); $newHeight=$height*$scaleY; $newWidth=$width*$scaleX; $result=array_fill(0, $newHeight, array_fill(0, $newWidth, 0)); for ($j=0;$j<$newHeight;++$j) for ($i=0;$i<$newWidth;++$i) $result[$j][$i]=$bitmap[(int)($j/$scaleY)] [(int)($i/$scaleX)]; return $result; } /** * adds random noise to the captcha */ protected function distort($bitmap,$noisePercent=5) { for ($j=0;$jtextBitmap($this->text); $degree=mt_rand(2,4); if (mt_rand()%100<50) $degree=-$degree; $bitmap=$this->rotateBitmap($bitmap,$degree); $bitmap=$this->scaleBitmap($bitmap,$scale,$scale); if ($distort) $bitmap=$this->distort($bitmap); return $this->inlineBitmap($bitmap); } }