diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 9b6f938..6b52af7 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -15,13 +15,16 @@ class Configuration implements ConfigurationInterface { $treeBuilder = new TreeBuilder(); $rootNode = $treeBuilder->root('gregwar_captcha', 'array'); - + $rootNode ->addDefaultsIfNotSet() ->children() ->scalarNode('length')->defaultValue(5)->end() ->scalarNode('width')->defaultValue(120)->end() ->scalarNode('height')->defaultValue(40)->end() + ->scalarNode('as_file')->defaultValue(false)->end() + ->scalarNode('image_folder')->defaultValue('captcha')->end() + ->scalarNode('web_path')->defaultValue('%kernel.root_dir%/../web')->end() ->end() ; return $treeBuilder; diff --git a/DependencyInjection/GregwarCaptchaExtension.php b/DependencyInjection/GregwarCaptchaExtension.php index 8c714c3..76e9813 100755 --- a/DependencyInjection/GregwarCaptchaExtension.php +++ b/DependencyInjection/GregwarCaptchaExtension.php @@ -22,11 +22,14 @@ class GregwarCaptchaExtension extends Extension $container->setParameter('gregwar_captcha.length', $config['length']); $container->setParameter('gregwar_captcha.height', $config['height']); $container->setParameter('gregwar_captcha.width', $config['width']); + $container->setParameter('gregwar_captcha.as_file', $config['as_file']); + $container->setParameter('gregwar_captcha.image_folder', $config['image_folder']); + $container->setParameter('gregwar_captcha.web_path', $config['web_path']); $resources = $container->getParameter('twig.form.resources'); $container->setParameter('twig.form.resources',array_merge(array('GregwarCaptchaBundle::captcha.html.twig'), $resources)); - + } - + } diff --git a/Generator/CaptchaGenerator.php b/Generator/CaptchaGenerator.php index dbf0b42..afc66dd 100644 --- a/Generator/CaptchaGenerator.php +++ b/Generator/CaptchaGenerator.php @@ -2,27 +2,68 @@ namespace Gregwar\CaptchaBundle\Generator; +use Symfony\Component\Finder\Finder; + /** * Generates a CAPTCHA image */ class CaptchaGenerator { + public $imageFolder; + public $webPath; public $value; - public function __construct($value) + public function __construct($value, $imageFolder, $webPath) { $this->value = $value; + $this->imageFolder = $imageFolder; + $this->webPath = $webPath; } public function getCode($width = 120, $height = 40) { return 'data:image/jpeg;base64,'.base64_encode($this->generate($width, $height)); } - + + /** + * Creates a captcha image with provided dimensions + * and randomly executes a garbage collection + * + * @param int $width + * @param int $height + * @return string Web path to the created image + */ + public function getFile($width = 120, $height = 40) + { + if (rand(0, 10) == 5) { + $this->garbageCollection(); + } + + return $this->generate($width, $height, true); + } + + /** + * Deletes all images in the configured folder + * that are older than 10 minutes + * + * @return void + */ + public function garbageCollection() + { + $finder = new Finder(); + $finder->in($this->webPath . '/' . $this->imageFolder) + ->date('since 10 minutes ago'); + + foreach($finder->files() as $file) + { + @unlink($file->getPathname()); + } + } + /** * Generate the image */ - public function generate($width, $height) + public function generate($width, $height, $createFile = false) { $i = imagecreatetruecolor($width,$height); @@ -73,7 +114,7 @@ class CaptchaGenerator { } $nY = $nY+$Scale*sin($Phase + $nX*0.2); - $p = $this->bilinearInterpolate($nX-floor($nX), $nY-floor($nY), + $p = $this->bilinearInterpolate($nX-floor($nX), $nY-floor($nY), $this->getCol($i,floor($nX),floor($nY)), $this->getCol($i,ceil($nX),floor($nY)), $this->getCol($i,floor($nX),ceil($nY)), @@ -87,9 +128,16 @@ class CaptchaGenerator { } // Renders it - ob_start(); - imagejpeg($out, null, 15); - return ob_get_clean(); + if (!$createFile) { + ob_start(); + imagejpeg($out, null, 15); + return ob_get_clean(); + } else { + $filename = md5(uniqid()) . '.jpg'; + $filepath = $this->webPath . '/' . $this->imageFolder . '/' . $filename; + imagejpeg($out, $filepath, 15); + return '/' . $this->imageFolder . '/' . $filename; + } } protected function getCol($image, $x, $y) diff --git a/README.md b/README.md index 06f3c2d..8f1cd3f 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,9 @@ You can define the following type option : * **width**: the width of the captcha image (default=120) * **height**: the height of the captcha image (default=40) * **length**: the length of the captcha (number of chars, default 5) +* **as_file**: if set to true an image file will be created instead of embedding to please IE6/7 (default=false) +* **image_folder**: name of folder for captcha images relative to public web folder in case **as_file** ist set to true (default="captcha") +* **web_path**: absolute path to public web folder (default="%kernel.root_dir%/../web") Example : @@ -109,7 +112,7 @@ Example : $builder->add('captcha', 'captcha', array( 'width' => 200, 'height' => 50, - 'length' => 6 + 'length' => 6, )); ``` @@ -137,6 +140,11 @@ The default rendering is: {% endblock %} ``` +Image creation +============== +If you choose to use real images instead of embedded the widget will execute a garbage collection +randomly and delete images that are older than 10 minutes. + License ======= This bundle is under the MIT license. See the complete license in the bundle: diff --git a/Resources/config/services.yml b/Resources/config/services.yml index 3ad484f..56c1ca3 100755 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -3,6 +3,6 @@ services: # captcha type captcha.type: class: Gregwar\CaptchaBundle\Type\CaptchaType - arguments: [@session, %gregwar_captcha.width%, %gregwar_captcha.height%, %gregwar_captcha.length%] + arguments: [ "@session", %gregwar_captcha.width%, %gregwar_captcha.height%, %gregwar_captcha.length%, %gregwar_captcha.as_file%, %gregwar_captcha.image_folder%, %gregwar_captcha.web_path% ] tags: - { name: form.type, alias: captcha } diff --git a/Type/CaptchaType.php b/Type/CaptchaType.php index 3b1a354..9baac91 100755 --- a/Type/CaptchaType.php +++ b/Type/CaptchaType.php @@ -39,21 +39,43 @@ class CaptchaType extends AbstractType */ protected $length; - /** + /** + * Generate image or data + * @var boolean + */ + protected $asFile; + + /** + * Folder to save captcha images in, + * relative to public web folder + * @var string + */ + protected $imageFolder; + + /** + * Public web folder + * @var string + */ + protected $webPath; + + /** * The session * @var Symfony\Component\HttpFoundation\Session */ protected $session; - + private $key = 'captcha'; - public function __construct(Session $session, $width, $height, $length) + public function __construct(Session $session, $width, $height, $length, $asFile, $imageFolder, $webPath) { $this->session = $session; $this->width = $width; $this->height = $height; $this->length = $length; + $this->asFile = $asFile; + $this->imageFolder = $imageFolder; + $this->webPath = $webPath; } public function buildForm(FormBuilder $builder, array $options) @@ -65,14 +87,18 @@ class CaptchaType extends AbstractType public function buildView(FormView $view, FormInterface $form) { - $generator = new CaptchaGenerator($this->generateCaptchaValue()); + $generator = new CaptchaGenerator($this->generateCaptchaValue(), $this->imageFolder, $this->webPath); - $view->set('captcha_code', $generator->getCode($this->width, $this->height)); + if ($this->asFile) { + $view->set('captcha_code', $generator->getFile($this->width, $this->height)); + } else { + $view->set('captcha_code', $generator->getCode($this->width, $this->height)); + } $view->set('captcha_width', $this->width); $view->set('captcha_height', $this->height); } - public function getDefaultOptions(array $options = array()) + public function getDefaultOptions(array $options = array()) { if (isset($options['width'])) { $this->width = $options['width']; @@ -83,11 +109,15 @@ class CaptchaType extends AbstractType if (isset($options['length'])) { $this->length = $options['length']; } + if (isset($options['as_file'])) { + $this->asFile = $options['as_file']; + } return array( 'width' => $this->width, 'height' => $this->height, 'length' => $this->length, + 'as_file' => $this->asFile, 'property_path' => false, ); }