I'm trying to create a CAPTCHA class with gifsicle, but my script keeps hanging (even time limit has no effect).
I'm using proc_open so I don't need any temp images:
<?php
/*****************************************************************
* Animated CAPTCHA Class
* Created by Lucas van Dijk (http://www.lucasvd.nl)
*
* This script requires gifsicle to run.
* http://www.lcdf.org/gifsicle/
*
* (c) Copyright 2006 by Lucas van Dijk. All Rights Reserved
******************************************************************
*
* 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.
*
******************************************************************/
error_reporting(E_ALL);
/**
* CAPTCHA Class
*
* Used for creating the animated image, with the code
* @package CAPTCHA
*/
class Captcha
{
protected $font;
protected $code;
protected $colors;
protected $gifsicle_path;
protected $delay;
protected $file_to_save;
protected $number_of_frames;
/**
* Inits the vars
* @param string $code The code to show
* @param string $font The TTF font to use for the code
* @param string $gifsicle_path Path to the gifsicle library
*/
public function __construct($font, $gifsicle_path, $number_of_frames = 5)
{
$this -> font = $font;
$this -> colors = array();
$this -> gifsicle_path = $gifsicle_path;
$this -> delay = 50;
$this -> file_to_save = "captcha.gif";
$this -> number_of_frames = (int) $number_of_frames;
}
/**
* Sets the delay
* @param int $delay The delay to use for the animation
*/
public function set_delay($delay)
{
$this -> delay = intval($delay);
}
/**
* Returns the delay
* @return int The currently used delay
*/
public function get_delay()
{
return $this -> delay;
}
/**
* Sets the filename to save the captcha image to
* @param string $file The filename of the captcha image
*/
public function set_file($file)
{
$this -> file_to_save = $file;
}
/**
* Returns the current filename of the capctha image
* @return string The current filename
*/
public function get_file()
{
return $this -> file_to_save;
}
/**
* Generates a random string
* @param bool $return_array return an array with three elememts containing each a part of the color, default false
* @return string A random hex color
*/
protected function random_hex_color($return_array = false)
{
$chars = array_merge(range('A', 'F'), range('0', '9 '));
$max_chars = count($chars) - 1;
srand( (double) microtime()*1000000);
$rand_color = '#';
for($i = 0; $i < 6; $i++)
{
$rand_color = ( empty($rand_color)) ? $chars[rand(0, $max_chars)] : $rand_color . $chars[rand(0, $max_chars)];
}
if($return_array)
{
$rand_color_array = array();
$rand_color_array[0] = substr($rand_color, 1, 2);
$rand_color_array[1] = substr($rand_color, 3, 2);
$rand_color_array[2] = substr($rand_color, 5, 2);
return $rand_color_array;
}
return $rand_color;
}
/**
* Generates an random RGB Color
* @return array An array with the RGB values
*/
protected function random_rgb_color()
{
$color = array();
for ($c = 0; $c < 3; $c++)
{
$color[] = rand(1, 255);
}
return $color;
}
/**
* Makes a random RGB color darker
* @param array The RGB Color array
* @param float $factor Factor to darken it, the lower, the darker
* @return array The new darkened RGB Color array
*/
protected function make_color_darker($rgb, $factor = 0.7)
{
if($factor > 1)
{
$factor = 0.7;
}
$rgb[0] = (int) ($rgb[0] * $factor);
$rgb[1] = (int) ($rgb[1] * $factor);
$rgb[2] = (int) ($rgb[2] * $factor);
return $rgb;
}
/**
* generates a random string
* @param bool $hash hash to md5?
* @param int $max_length Length of the string
* @return string The new random string
*/
public static function gen_random_string($hash = false, $max_length = 8)
{
$chars = array_merge(range('a', 'z'), range('A', 'Z'), range('0', '9'));
$max_chars = count($chars) - 1;
srand( (double) microtime()*1000000);
$rand_str = '';
for($i = 0; $i < $max_length; $i++)
{
$rand_str = ( $i == 0 ) ? $chars[rand(0, $max_chars)] : $rand_str . $chars[rand(0, $max_chars)];
}
return ( $hash ) ? md5($rand_str) : $rand_str;
}
/**
* Generates the image
*/
protected function generate_frame($border)
{
$image = imagecreatetruecolor(175, 75);
if(!$image)
{
throw new Exception('Could not create image resource');
}
$this -> colors['white'] = imagecolorallocate($image, 255, 255, 255);
$this -> colors['black'] = imagecolorallocate($image, 0, 0, 0);
imagefilledrectangle($image, 0, 0, imagesx($image) - 1, imagesy($image) - 1, $this -> colors['white']);
// Add some text as background with a low alpha
for($i = 0; $i < 30; $i++)
{
$random_color = $this -> random_rgb_color();
$color = imagecolorallocatealpha($image, $random_color[0], $random_color[1], $random_color[2], 80);
imagettftext($image, 16, rand(0, 360), rand(0, imagesx($image)), rand(0, imagesy($image)), $color, $this -> font, self::gen_random_string(false, 5));
}
imagerectangle($image, 0, 0, imagesx($image) - 1, imagesy($image) - 1, $this -> colors['black']);
// Generate the code
$x = 10;
$code = self::gen_random_string(false, 7);
if($border)
{
$this -> code = $code;
}
for($i = 0; $i < strlen($code); $i++)
{
// Create random color
$random_color = $this -> random_rgb_color();
$shadow_color = $this -> make_color_darker($random_color, 0.5);
$color = imagecolorallocate($image, $random_color[0], $random_color[1], $random_color[2]);
$shadow = imagecolorallocate($image, $shadow_color[0], $shadow_color[1], $shadow_color[2]);
// Do we have to create the border?
if($border)
{
$width = imagesx($image);
$height = imagesy($image);
for($i = 0; $i < 4; $i++)
{
$this -> colors['green'] = imagecolorallocate($image, 0x00, 0xFF, 0x00);
imagerectangle($image, 5 + $i, 5 + $i, $width - 5 - $i, $height - 5 - $i, $this -> colors['green']);
}
}
// Calculate Y and angle
$y = 35 + (rand(-7, 7));
$angle = rand(-8, 8);
// Add shadow
imagettftext($image, 22, $angle, $x+2, $y+2, $shadow, $this -> font, $this -> code{$i});
// The actual text
imagettftext($image, 22, $angle, $x, $y, $color, $this -> font, $this -> code{$i});
$x += 22;
}
$this -> generate_dots(&$image);
return $image;
}
/**
* Generates some dots
*/
protected function generate_dots(&$image)
{
// Generate some random dots
$max_x = imagesx($image);
$max_y = imagesy($image);
for($i = 0; $i < 300; $i++)
{
imagesetpixel($image, rand(0, $max_x - 1), rand(0, $max_y -1), $this -> colors['black']);
}
}
/**
* Creates the animation
*
* Creates an animation with the code, and than saves it to a file
*/
public function create_animation()
{
$cmd = $this -> gifsicle_path.' --loop -O1 --multifile --delay '.$this -> delay.' - > '.$this -> file_to_save;
$desc = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("file", "errors.txt", "a"));
$proc = proc_open($cmd, $desc, $pipes);
if(!is_resource($proc))
{
throw new Exception('Could not start gifsicle');
}
$border_frame = rand(0, $this -> number_of_frames - 1);
for($i = 0; $i < $this -> number_of_frames; $i++)
{
$image = $this -> generate_frame($i == $border_frame ? true : false);
// Get image contents
ob_start();
imagegif($image);
$contents = ob_get_contents();
ob_end_clean();
// Write it to gifsicle
fwrite($pipes[0], $contents));
fclose($pipes[0]);
// Clean up image
imagedestroy($image);
}
fclose($pipes[1]);
fclose($pipes[2]);
return proc_close($proc);
}
/**
* Returns the code used on the image
* @return string The code
*/
public function __toString()
{
return $this -> code;
}
}
?>
captcha.php:
<?php
/*****************************************************************
* Animated CAPTCHA Class
* Created by Lucas van Dijk (http://www.lucasvd.nl)
*
* This script requires gifsicle to run.
* http://www.lcdf.org/gifsicle/
*
* (c) Copyright 2006 by Lucas van Dijk. All Rights Reserved
******************************************************************
*
* 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.
*
******************************************************************/
include '../anicaptcha.class.php';
$captcha = new Captcha(Captcha::gen_random_string(false, 6), 'elected.ttf', 'C:/Server/htdocs/classes/captcha/gifsicle.exe');
$return = $captcha -> create_animation();
session_start();
echo "Return value: ".$return;
$_SESSION['code'] = $captcha;
//header("Location: captcha.gif");
?>
When I comment out proc_open() It does not hang.
What's the problem?