summaryrefslogtreecommitdiff
path: root/vendor/gregwar/captcha
diff options
context:
space:
mode:
authorFrederic Guillot <fred@kanboard.net>2017-10-25 16:22:10 -0700
committerFrederic Guillot <fred@kanboard.net>2017-10-25 16:22:10 -0700
commit9e2b2a32fd0e967ad3184e9a5d091a29953acb91 (patch)
tree00822e24aa1110c73ca455a8d096ef296c008cbc /vendor/gregwar/captcha
parentc507c5416251c505cb3e088a03c6664bed73c812 (diff)
Include composer dependencies in repo
Diffstat (limited to 'vendor/gregwar/captcha')
-rw-r--r--vendor/gregwar/captcha/.gitignore3
-rw-r--r--vendor/gregwar/captcha/.travis.yml12
-rw-r--r--vendor/gregwar/captcha/CaptchaBuilder.php720
-rw-r--r--vendor/gregwar/captcha/CaptchaBuilderInterface.php30
-rw-r--r--vendor/gregwar/captcha/Font/captcha0.ttfbin0 -> 49224 bytes
-rw-r--r--vendor/gregwar/captcha/Font/captcha1.ttfbin0 -> 76232 bytes
-rw-r--r--vendor/gregwar/captcha/Font/captcha2.ttfbin0 -> 33984 bytes
-rw-r--r--vendor/gregwar/captcha/Font/captcha3.ttfbin0 -> 15976 bytes
-rw-r--r--vendor/gregwar/captcha/Font/captcha4.ttfbin0 -> 906980 bytes
-rw-r--r--vendor/gregwar/captcha/Font/captcha5.ttfbin0 -> 49724 bytes
-rw-r--r--vendor/gregwar/captcha/ImageFileHandler.php106
-rw-r--r--vendor/gregwar/captcha/LICENSE19
-rw-r--r--vendor/gregwar/captcha/PhraseBuilder.php34
-rw-r--r--vendor/gregwar/captcha/PhraseBuilderInterface.php21
-rw-r--r--vendor/gregwar/captcha/README.md108
-rw-r--r--vendor/gregwar/captcha/autoload.php16
-rw-r--r--vendor/gregwar/captcha/composer.json28
-rw-r--r--vendor/gregwar/captcha/demo/demo.php14
-rw-r--r--vendor/gregwar/captcha/demo/fingerprint.php15
-rw-r--r--vendor/gregwar/captcha/demo/index.php15
-rw-r--r--vendor/gregwar/captcha/demo/ocr.php42
-rw-r--r--vendor/gregwar/captcha/demo/output.php15
22 files changed, 1198 insertions, 0 deletions
diff --git a/vendor/gregwar/captcha/.gitignore b/vendor/gregwar/captcha/.gitignore
new file mode 100644
index 00000000..5a275919
--- /dev/null
+++ b/vendor/gregwar/captcha/.gitignore
@@ -0,0 +1,3 @@
+demo/*.jpg
+demo/*.pgm
+demo/temp/
diff --git a/vendor/gregwar/captcha/.travis.yml b/vendor/gregwar/captcha/.travis.yml
new file mode 100644
index 00000000..9c4b7049
--- /dev/null
+++ b/vendor/gregwar/captcha/.travis.yml
@@ -0,0 +1,12 @@
+language: php
+
+php:
+ - 5.3.3
+ - 5.3
+ - 5.4
+ - 5.5
+ - 5.6
+
+script:
+ - composer install
+ - phpunit
diff --git a/vendor/gregwar/captcha/CaptchaBuilder.php b/vendor/gregwar/captcha/CaptchaBuilder.php
new file mode 100644
index 00000000..bc6173fe
--- /dev/null
+++ b/vendor/gregwar/captcha/CaptchaBuilder.php
@@ -0,0 +1,720 @@
+<?php
+
+namespace Gregwar\Captcha;
+
+use \Exception;
+
+/**
+ * Builds a new captcha image
+ * Uses the fingerprint parameter, if one is passed, to generate the same image
+ *
+ * @author Gregwar <g.passault@gmail.com>
+ * @author Jeremy Livingston <jeremy.j.livingston@gmail.com>
+ */
+class CaptchaBuilder implements CaptchaBuilderInterface
+{
+ /**
+ * @var array
+ */
+ protected $fingerprint = array();
+
+ /**
+ * @var bool
+ */
+ protected $useFingerprint = false;
+
+ /**
+ * @var array
+ */
+ protected $textColor = null;
+
+ /**
+ * @var array
+ */
+ protected $backgroundColor = null;
+
+ /**
+ * @var array
+ */
+ protected $backgroundImages = array();
+
+ /**
+ * @var resource
+ */
+ protected $contents = null;
+
+ /**
+ * @var string
+ */
+ protected $phrase = null;
+
+ /**
+ * @var PhraseBuilderInterface
+ */
+ protected $builder;
+
+ /**
+ * @var bool
+ */
+ protected $distortion = true;
+
+ /**
+ * The maximum number of lines to draw in front of
+ * the image. null - use default algorithm
+ */
+ protected $maxFrontLines = null;
+
+ /**
+ * The maximum number of lines to draw behind
+ * the image. null - use default algorithm
+ */
+ protected $maxBehindLines = null;
+
+ /**
+ * The maximum angle of char
+ */
+ protected $maxAngle = 8;
+
+ /**
+ * The maximum offset of char
+ */
+ protected $maxOffset = 5;
+
+ /**
+ * Is the interpolation enabled ?
+ *
+ * @var bool
+ */
+ protected $interpolation = true;
+
+ /**
+ * Ignore all effects
+ *
+ * @var bool
+ */
+ protected $ignoreAllEffects = false;
+
+ /**
+ * Allowed image types for the background images
+ *
+ * @var array
+ */
+ protected $allowedBackgroundImageTypes = array('image/png', 'image/jpeg', 'image/gif');
+
+ /**
+ * The image contents
+ */
+ public function getContents()
+ {
+ return $this->contents;
+ }
+
+ /**
+ * Enable/Disables the interpolation
+ *
+ * @param $interpolate bool True to enable, false to disable
+ *
+ * @return CaptchaBuilder
+ */
+ public function setInterpolation($interpolate = true)
+ {
+ $this->interpolation = $interpolate;
+
+ return $this;
+ }
+
+ /**
+ * Temporary dir, for OCR check
+ */
+ public $tempDir = 'temp/';
+
+ public function __construct($phrase = null, PhraseBuilderInterface $builder = null)
+ {
+ if ($builder === null) {
+ $this->builder = new PhraseBuilder;
+ } else {
+ $this->builder = $builder;
+ }
+
+ if ($phrase === null) {
+ $phrase = $this->builder->build();
+ }
+
+ $this->phrase = $phrase;
+ }
+
+ /**
+ * Setting the phrase
+ */
+ public function setPhrase($phrase)
+ {
+ $this->phrase = (string) $phrase;
+ }
+
+ /**
+ * Enables/disable distortion
+ */
+ public function setDistortion($distortion)
+ {
+ $this->distortion = (bool) $distortion;
+
+ return $this;
+ }
+
+ public function setMaxBehindLines($maxBehindLines)
+ {
+ $this->maxBehindLines = $maxBehindLines;
+
+ return $this;
+ }
+
+ public function setMaxFrontLines($maxFrontLines)
+ {
+ $this->maxFrontLines = $maxFrontLines;
+
+ return $this;
+ }
+
+ public function setMaxAngle($maxAngle)
+ {
+ $this->maxAngle = $maxAngle;
+
+ return $this;
+ }
+
+ public function setMaxOffset($maxOffset)
+ {
+ $this->maxOffset = $maxOffset;
+
+ return $this;
+ }
+
+ /**
+ * Gets the captcha phrase
+ */
+ public function getPhrase()
+ {
+ return $this->phrase;
+ }
+
+ /**
+ * Returns true if the given phrase is good
+ */
+ public function testPhrase($phrase)
+ {
+ return ($this->builder->niceize($phrase) == $this->builder->niceize($this->getPhrase()));
+ }
+
+ /**
+ * Instantiation
+ */
+ public static function create($phrase = null)
+ {
+ return new self($phrase);
+ }
+
+ /**
+ * Sets the text color to use
+ */
+ public function setTextColor($r, $g, $b)
+ {
+ $this->textColor = array($r, $g, $b);
+
+ return $this;
+ }
+
+ /**
+ * Sets the background color to use
+ */
+ public function setBackgroundColor($r, $g, $b)
+ {
+ $this->backgroundColor = array($r, $g, $b);
+
+ return $this;
+ }
+
+ /**
+ * Sets the ignoreAllEffects value
+ *
+ * @param bool $ignoreAllEffects
+ * @return CaptchaBuilder
+ */
+ public function setIgnoreAllEffects($ignoreAllEffects)
+ {
+ $this->ignoreAllEffects = $ignoreAllEffects;
+
+ return $this;
+ }
+
+ /**
+ * Sets the list of background images to use (one image is randomly selected)
+ */
+ public function setBackgroundImages(array $backgroundImages)
+ {
+ $this->backgroundImages = $backgroundImages;
+
+ return $this;
+ }
+
+ /**
+ * Draw lines over the image
+ */
+ protected function drawLine($image, $width, $height, $tcol = null)
+ {
+ if ($tcol === null) {
+ $tcol = imagecolorallocate($image, $this->rand(100, 255), $this->rand(100, 255), $this->rand(100, 255));
+ }
+
+ if ($this->rand(0, 1)) { // Horizontal
+ $Xa = $this->rand(0, $width/2);
+ $Ya = $this->rand(0, $height);
+ $Xb = $this->rand($width/2, $width);
+ $Yb = $this->rand(0, $height);
+ } else { // Vertical
+ $Xa = $this->rand(0, $width);
+ $Ya = $this->rand(0, $height/2);
+ $Xb = $this->rand(0, $width);
+ $Yb = $this->rand($height/2, $height);
+ }
+ imagesetthickness($image, $this->rand(1, 3));
+ imageline($image, $Xa, $Ya, $Xb, $Yb, $tcol);
+ }
+
+ /**
+ * Apply some post effects
+ */
+ protected function postEffect($image)
+ {
+ if (!function_exists('imagefilter')) {
+ return;
+ }
+
+ if ($this->backgroundColor != null || $this->textColor != null) {
+ return;
+ }
+
+ // Negate ?
+ if ($this->rand(0, 1) == 0) {
+ imagefilter($image, IMG_FILTER_NEGATE);
+ }
+
+ // Edge ?
+ if ($this->rand(0, 10) == 0) {
+ imagefilter($image, IMG_FILTER_EDGEDETECT);
+ }
+
+ // Contrast
+ imagefilter($image, IMG_FILTER_CONTRAST, $this->rand(-50, 10));
+
+ // Colorize
+ if ($this->rand(0, 5) == 0) {
+ imagefilter($image, IMG_FILTER_COLORIZE, $this->rand(-80, 50), $this->rand(-80, 50), $this->rand(-80, 50));
+ }
+ }
+
+ /**
+ * Writes the phrase on the image
+ */
+ protected function writePhrase($image, $phrase, $font, $width, $height)
+ {
+ $length = strlen($phrase);
+ if ($length === 0) {
+ return imagecolorallocate($image, 0, 0, 0);
+ }
+
+ // Gets the text size and start position
+ $size = $width / $length - $this->rand(0, 3) - 1;
+ $box = imagettfbbox($size, 0, $font, $phrase);
+ $textWidth = $box[2] - $box[0];
+ $textHeight = $box[1] - $box[7];
+ $x = ($width - $textWidth) / 2;
+ $y = ($height - $textHeight) / 2 + $size;
+
+ if (!count($this->textColor)) {
+ $textColor = array($this->rand(0, 150), $this->rand(0, 150), $this->rand(0, 150));
+ } else {
+ $textColor = $this->textColor;
+ }
+ $col = imagecolorallocate($image, $textColor[0], $textColor[1], $textColor[2]);
+
+ // Write the letters one by one, with random angle
+ for ($i=0; $i<$length; $i++) {
+ $box = imagettfbbox($size, 0, $font, $phrase[$i]);
+ $w = $box[2] - $box[0];
+ $angle = $this->rand(-$this->maxAngle, $this->maxAngle);
+ $offset = $this->rand(-$this->maxOffset, $this->maxOffset);
+ imagettftext($image, $size, $angle, $x, $y + $offset, $col, $font, $phrase[$i]);
+ $x += $w;
+ }
+
+ return $col;
+ }
+
+ /**
+ * Try to read the code against an OCR
+ */
+ public function isOCRReadable()
+ {
+ if (!is_dir($this->tempDir)) {
+ @mkdir($this->tempDir, 0755, true);
+ }
+
+ $tempj = $this->tempDir . uniqid('captcha', true) . '.jpg';
+ $tempp = $this->tempDir . uniqid('captcha', true) . '.pgm';
+
+ $this->save($tempj);
+ shell_exec("convert $tempj $tempp");
+ $value = trim(strtolower(shell_exec("ocrad $tempp")));
+
+ @unlink($tempj);
+ @unlink($tempp);
+
+ return $this->testPhrase($value);
+ }
+
+ /**
+ * Builds while the code is readable against an OCR
+ */
+ public function buildAgainstOCR($width = 150, $height = 40, $font = null, $fingerprint = null)
+ {
+ do {
+ $this->build($width, $height, $font, $fingerprint);
+ } while ($this->isOCRReadable());
+ }
+
+ /**
+ * Generate the image
+ */
+ public function build($width = 150, $height = 40, $font = null, $fingerprint = null)
+ {
+ if (null !== $fingerprint) {
+ $this->fingerprint = $fingerprint;
+ $this->useFingerprint = true;
+ } else {
+ $this->fingerprint = array();
+ $this->useFingerprint = false;
+ }
+
+ if ($font === null) {
+ $font = __DIR__ . '/Font/captcha'.$this->rand(0, 5).'.ttf';
+ }
+
+ if (empty($this->backgroundImages)) {
+ // if background images list is not set, use a color fill as a background
+ $image = imagecreatetruecolor($width, $height);
+ if ($this->backgroundColor == null) {
+ $bg = imagecolorallocate($image, $this->rand(200, 255), $this->rand(200, 255), $this->rand(200, 255));
+ } else {
+ $color = $this->backgroundColor;
+ $bg = imagecolorallocate($image, $color[0], $color[1], $color[2]);
+ }
+ $this->background = $bg;
+ imagefill($image, 0, 0, $bg);
+ } else {
+ // use a random background image
+ $randomBackgroundImage = $this->backgroundImages[rand(0, count($this->backgroundImages)-1)];
+
+ $imageType = $this->validateBackgroundImage($randomBackgroundImage);
+
+ $image = $this->createBackgroundImageFromType($randomBackgroundImage, $imageType);
+ }
+
+ // Apply effects
+ if (!$this->ignoreAllEffects) {
+ $square = $width * $height;
+ $effects = $this->rand($square/3000, $square/2000);
+
+ // set the maximum number of lines to draw in front of the text
+ if ($this->maxBehindLines != null && $this->maxBehindLines > 0) {
+ $effects = min($this->maxBehindLines, $effects);
+ }
+
+ if ($this->maxBehindLines !== 0) {
+ for ($e = 0; $e < $effects; $e++) {
+ $this->drawLine($image, $width, $height);
+ }
+ }
+ }
+
+ // Write CAPTCHA text
+ $color = $this->writePhrase($image, $this->phrase, $font, $width, $height);
+
+ // Apply effects
+ if (!$this->ignoreAllEffects) {
+ $square = $width * $height;
+ $effects = $this->rand($square/3000, $square/2000);
+
+ // set the maximum number of lines to draw in front of the text
+ if ($this->maxFrontLines != null && $this->maxFrontLines > 0) {
+ $effects = min($this->maxFrontLines, $effects);
+ }
+
+ if ($this->maxFrontLines !== 0) {
+ for ($e = 0; $e < $effects; $e++) {
+ $this->drawLine($image, $width, $height, $color);
+ }
+ }
+ }
+
+ // Distort the image
+ if ($this->distortion && !$this->ignoreAllEffects) {
+ $image = $this->distort($image, $width, $height, $bg);
+ }
+
+ // Post effects
+ if (!$this->ignoreAllEffects) {
+ $this->postEffect($image);
+ }
+
+ $this->contents = $image;
+
+ return $this;
+ }
+
+ /**
+ * Distorts the image
+ */
+ public function distort($image, $width, $height, $bg)
+ {
+ $contents = imagecreatetruecolor($width, $height);
+ $X = $this->rand(0, $width);
+ $Y = $this->rand(0, $height);
+ $phase = $this->rand(0, 10);
+ $scale = 1.1 + $this->rand(0, 10000) / 30000;
+ for ($x = 0; $x < $width; $x++) {
+ for ($y = 0; $y < $height; $y++) {
+ $Vx = $x - $X;
+ $Vy = $y - $Y;
+ $Vn = sqrt($Vx * $Vx + $Vy * $Vy);
+
+ if ($Vn != 0) {
+ $Vn2 = $Vn + 4 * sin($Vn / 30);
+ $nX = $X + ($Vx * $Vn2 / $Vn);
+ $nY = $Y + ($Vy * $Vn2 / $Vn);
+ } else {
+ $nX = $X;
+ $nY = $Y;
+ }
+ $nY = $nY + $scale * sin($phase + $nX * 0.2);
+
+ if ($this->interpolation) {
+ $p = $this->interpolate(
+ $nX - floor($nX),
+ $nY - floor($nY),
+ $this->getCol($image, floor($nX), floor($nY), $bg),
+ $this->getCol($image, ceil($nX), floor($nY), $bg),
+ $this->getCol($image, floor($nX), ceil($nY), $bg),
+ $this->getCol($image, ceil($nX), ceil($nY), $bg)
+ );
+ } else {
+ $p = $this->getCol($image, round($nX), round($nY), $bg);
+ }
+
+ if ($p == 0) {
+ $p = $bg;
+ }
+
+ imagesetpixel($contents, $x, $y, $p);
+ }
+ }
+
+ return $contents;
+ }
+
+ /**
+ * Saves the Captcha to a jpeg file
+ */
+ public function save($filename, $quality = 90)
+ {
+ imagejpeg($this->contents, $filename, $quality);
+ }
+
+ /**
+ * Gets the image GD
+ */
+ public function getGd()
+ {
+ return $this->contents;
+ }
+
+ /**
+ * Gets the image contents
+ */
+ public function get($quality = 90)
+ {
+ ob_start();
+ $this->output($quality);
+
+ return ob_get_clean();
+ }
+
+ /**
+ * Gets the HTML inline base64
+ */
+ public function inline($quality = 90)
+ {
+ return 'data:image/jpeg;base64,' . base64_encode($this->get($quality));
+ }
+
+ /**
+ * Outputs the image
+ */
+ public function output($quality = 90)
+ {
+ imagejpeg($this->contents, null, $quality);
+ }
+
+ /**
+ * @return array
+ */
+ public function getFingerprint()
+ {
+ return $this->fingerprint;
+ }
+
+ /**
+ * Returns a random number or the next number in the
+ * fingerprint
+ */
+ protected function rand($min, $max)
+ {
+ if (!is_array($this->fingerprint)) {
+ $this->fingerprint = array();
+ }
+
+ if ($this->useFingerprint) {
+ $value = current($this->fingerprint);
+ next($this->fingerprint);
+ } else {
+ $value = mt_rand($min, $max);
+ $this->fingerprint[] = $value;
+ }
+
+ return $value;
+ }
+
+ /**
+ * @param $x
+ * @param $y
+ * @param $nw
+ * @param $ne
+ * @param $sw
+ * @param $se
+ *
+ * @return int
+ */
+ protected function interpolate($x, $y, $nw, $ne, $sw, $se)
+ {
+ list($r0, $g0, $b0) = $this->getRGB($nw);
+ list($r1, $g1, $b1) = $this->getRGB($ne);
+ list($r2, $g2, $b2) = $this->getRGB($sw);
+ list($r3, $g3, $b3) = $this->getRGB($se);
+
+ $cx = 1.0 - $x;
+ $cy = 1.0 - $y;
+
+ $m0 = $cx * $r0 + $x * $r1;
+ $m1 = $cx * $r2 + $x * $r3;
+ $r = (int) ($cy * $m0 + $y * $m1);
+
+ $m0 = $cx * $g0 + $x * $g1;
+ $m1 = $cx * $g2 + $x * $g3;
+ $g = (int) ($cy * $m0 + $y * $m1);
+
+ $m0 = $cx * $b0 + $x * $b1;
+ $m1 = $cx * $b2 + $x * $b3;
+ $b = (int) ($cy * $m0 + $y * $m1);
+
+ return ($r << 16) | ($g << 8) | $b;
+ }
+
+ /**
+ * @param $image
+ * @param $x
+ * @param $y
+ *
+ * @return int
+ */
+ protected function getCol($image, $x, $y, $background)
+ {
+ $L = imagesx($image);
+ $H = imagesy($image);
+ if ($x < 0 || $x >= $L || $y < 0 || $y >= $H) {
+ return $background;
+ }
+
+ return imagecolorat($image, $x, $y);
+ }
+
+ /**
+ * @param $col
+ *
+ * @return array
+ */
+ protected function getRGB($col)
+ {
+ return array(
+ (int) ($col >> 16) & 0xff,
+ (int) ($col >> 8) & 0xff,
+ (int) ($col) & 0xff,
+ );
+ }
+
+ /**
+ * Validate the background image path. Return the image type if valid
+ *
+ * @param string $backgroundImage
+ * @return string
+ * @throws Exception
+ */
+ protected function validateBackgroundImage($backgroundImage)
+ {
+ // check if file exists
+ if (!file_exists($backgroundImage)) {
+ $backgroundImageExploded = explode('/', $backgroundImage);
+ $imageFileName = count($backgroundImageExploded) > 1? $backgroundImageExploded[count($backgroundImageExploded)-1] : $backgroundImage;
+
+ throw new Exception('Invalid background image: ' . $imageFileName);
+ }
+
+ // check image type
+ $finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
+ $imageType = finfo_file($finfo, $backgroundImage);
+ finfo_close($finfo);
+
+ if (!in_array ($imageType, $this->allowedBackgroundImageTypes)) {
+ throw new Exception('Invalid background image type! Allowed types are: ' . join(', ', $this->allowedBackgroundImageTypes));
+ }
+
+ return $imageType;
+ }
+
+ /**
+ * Create background image from type
+ *
+ * @param string $backgroundImage
+ * @param string $imageType
+ * @return resource
+ * @throws Exception
+ */
+ protected function createBackgroundImageFromType($backgroundImage, $imageType)
+ {
+ switch ($imageType) {
+ case 'image/jpeg':
+ $image = imagecreatefromjpeg($backgroundImage);
+ break;
+ case 'image/png':
+ $image = imagecreatefrompng($backgroundImage);
+ break;
+ case 'image/gif':
+ $image = imagecreatefromgif($backgroundImage);
+ break;
+
+ default:
+ throw new Exception('Not supported file type for background image!');
+ break;
+ }
+
+ return $image;
+ }
+}
diff --git a/vendor/gregwar/captcha/CaptchaBuilderInterface.php b/vendor/gregwar/captcha/CaptchaBuilderInterface.php
new file mode 100644
index 00000000..bdebf38f
--- /dev/null
+++ b/vendor/gregwar/captcha/CaptchaBuilderInterface.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace Gregwar\Captcha;
+
+/**
+ * A Captcha builder
+ */
+interface CaptchaBuilderInterface
+{
+ /**
+ * Builds the code
+ */
+ public function build($width, $height, $font, $fingerprint);
+
+ /**
+ * Saves the code to a file
+ */
+ public function save($filename, $quality);
+
+ /**
+ * Gets the image contents
+ */
+ public function get($quality);
+
+ /**
+ * Outputs the image
+ */
+ public function output($quality);
+}
+
diff --git a/vendor/gregwar/captcha/Font/captcha0.ttf b/vendor/gregwar/captcha/Font/captcha0.ttf
new file mode 100644
index 00000000..139f0b43
--- /dev/null
+++ b/vendor/gregwar/captcha/Font/captcha0.ttf
Binary files differ
diff --git a/vendor/gregwar/captcha/Font/captcha1.ttf b/vendor/gregwar/captcha/Font/captcha1.ttf
new file mode 100644
index 00000000..bb1abf6b
--- /dev/null
+++ b/vendor/gregwar/captcha/Font/captcha1.ttf
Binary files differ
diff --git a/vendor/gregwar/captcha/Font/captcha2.ttf b/vendor/gregwar/captcha/Font/captcha2.ttf
new file mode 100644
index 00000000..8d1f31e8
--- /dev/null
+++ b/vendor/gregwar/captcha/Font/captcha2.ttf
Binary files differ
diff --git a/vendor/gregwar/captcha/Font/captcha3.ttf b/vendor/gregwar/captcha/Font/captcha3.ttf
new file mode 100644
index 00000000..d232902c
--- /dev/null
+++ b/vendor/gregwar/captcha/Font/captcha3.ttf
Binary files differ
diff --git a/vendor/gregwar/captcha/Font/captcha4.ttf b/vendor/gregwar/captcha/Font/captcha4.ttf
new file mode 100644
index 00000000..ab154440
--- /dev/null
+++ b/vendor/gregwar/captcha/Font/captcha4.ttf
Binary files differ
diff --git a/vendor/gregwar/captcha/Font/captcha5.ttf b/vendor/gregwar/captcha/Font/captcha5.ttf
new file mode 100644
index 00000000..f7cd9986
--- /dev/null
+++ b/vendor/gregwar/captcha/Font/captcha5.ttf
Binary files differ
diff --git a/vendor/gregwar/captcha/ImageFileHandler.php b/vendor/gregwar/captcha/ImageFileHandler.php
new file mode 100644
index 00000000..6b6bdb87
--- /dev/null
+++ b/vendor/gregwar/captcha/ImageFileHandler.php
@@ -0,0 +1,106 @@
+<?php
+
+namespace Gregwar\Captcha;
+
+use Symfony\Component\Finder\Finder;
+
+/**
+ * Handles actions related to captcha image files including saving and garbage collection
+ *
+ * @author Gregwar <g.passault@gmail.com>
+ * @author Jeremy Livingston <jeremy@quizzle.com>
+ */
+class ImageFileHandler
+{
+ /**
+ * Name of folder for captcha images
+ * @var string
+ */
+ protected $imageFolder;
+
+ /**
+ * Absolute path to public web folder
+ * @var string
+ */
+ protected $webPath;
+
+ /**
+ * Frequency of garbage collection in fractions of 1
+ * @var int
+ */
+ protected $gcFreq;
+
+ /**
+ * Maximum age of images in minutes
+ * @var int
+ */
+ protected $expiration;
+
+ /**
+ * @param $imageFolder
+ * @param $webPath
+ * @param $gcFreq
+ * @param $expiration
+ */
+ public function __construct($imageFolder, $webPath, $gcFreq, $expiration)
+ {
+ $this->imageFolder = $imageFolder;
+ $this->webPath = $webPath;
+ $this->gcFreq = $gcFreq;
+ $this->expiration = $expiration;
+ }
+
+ /**
+ * Saves the provided image content as a file
+ *
+ * @param string $contents
+ *
+ * @return string
+ */
+ public function saveAsFile($contents)
+ {
+ $this->createFolderIfMissing();
+
+ $filename = md5(uniqid()) . '.jpg';
+ $filePath = $this->webPath . '/' . $this->imageFolder . '/' . $filename;
+ imagejpeg($contents, $filePath, 15);
+
+ return '/' . $this->imageFolder . '/' . $filename;
+ }
+
+ /**
+ * Randomly runs garbage collection on the image directory
+ *
+ * @return bool
+ */
+ public function collectGarbage()
+ {
+ if (!mt_rand(1, $this->gcFreq) == 1) {
+ return false;
+ }
+
+ $this->createFolderIfMissing();
+
+ $finder = new Finder();
+ $criteria = sprintf('<= now - %s minutes', $this->expiration);
+ $finder->in($this->webPath . '/' . $this->imageFolder)
+ ->date($criteria);
+
+ foreach($finder->files() as $file) {
+ unlink($file->getPathname());
+ }
+
+ return true;
+ }
+
+ /**
+ * Creates the folder if it doesn't exist
+ */
+ protected function createFolderIfMissing()
+ {
+ if (!file_exists($this->webPath . '/' . $this->imageFolder)) {
+ mkdir($this->webPath . '/' . $this->imageFolder, 0755);
+ }
+ }
+}
+
diff --git a/vendor/gregwar/captcha/LICENSE b/vendor/gregwar/captcha/LICENSE
new file mode 100644
index 00000000..7db6ad8e
--- /dev/null
+++ b/vendor/gregwar/captcha/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) <2012-2015> Grégoire Passault
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/gregwar/captcha/PhraseBuilder.php b/vendor/gregwar/captcha/PhraseBuilder.php
new file mode 100644
index 00000000..b94bd61c
--- /dev/null
+++ b/vendor/gregwar/captcha/PhraseBuilder.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Gregwar\Captcha;
+
+/**
+ * Generates random phrase
+ *
+ * @author Gregwar <g.passault@gmail.com>
+ */
+class PhraseBuilder implements PhraseBuilderInterface
+{
+ /**
+ * Generates random phrase of given length with given charset
+ */
+ public function build($length = 5, $charset = 'abcdefghijklmnpqrstuvwxyz123456789')
+ {
+ $phrase = '';
+ $chars = str_split($charset);
+
+ for ($i = 0; $i < $length; $i++) {
+ $phrase .= $chars[array_rand($chars)];
+ }
+
+ return $phrase;
+ }
+
+ /**
+ * "Niceize" a code
+ */
+ public function niceize($str)
+ {
+ return strtr(strtolower($str), '01', 'ol');
+ }
+}
diff --git a/vendor/gregwar/captcha/PhraseBuilderInterface.php b/vendor/gregwar/captcha/PhraseBuilderInterface.php
new file mode 100644
index 00000000..0a4f5361
--- /dev/null
+++ b/vendor/gregwar/captcha/PhraseBuilderInterface.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace Gregwar\Captcha;
+
+/**
+ * Interface for the PhraseBuilder
+ *
+ * @author Gregwar <g.passault@gmail.com>
+ */
+interface PhraseBuilderInterface
+{
+ /**
+ * Generates random phrase of given length with given charset
+ */
+ public function build($length, $charset);
+
+ /**
+ * "Niceize" a code
+ */
+ public function niceize($str);
+}
diff --git a/vendor/gregwar/captcha/README.md b/vendor/gregwar/captcha/README.md
new file mode 100644
index 00000000..9f6c17a9
--- /dev/null
+++ b/vendor/gregwar/captcha/README.md
@@ -0,0 +1,108 @@
+Captcha
+=======
+
+![Captchas examples](http://gregwar.com/captchas.png)
+
+Installation
+============
+
+With composer :
+
+``` json
+{
+ ...
+ "require": {
+ "gregwar/captcha": "1.*"
+ }
+}
+```
+
+Usage
+=====
+
+You can create a captcha with the `CaptchaBuilder` :
+
+```php
+<?php
+
+use Gregwar\Captcha\CaptchaBuilder;
+
+$builder = new CaptchaBuilder;
+$builder->build();
+```
+
+You can then save it to a file :
+
+```php
+<?php
+
+$builder->save('out.jpg');
+```
+
+Or output it directly :
+
+```php
+<?php
+
+header('Content-type: image/jpeg');
+$builder->output();
+```
+
+Or inline it directly in the HTML page:
+
+```php
+<img src="<?php echo $builder->inline(); ?>" />
+```
+
+You'll be able to get the code and compare it with a user input :
+
+```php
+<?php
+
+// Example: storing the phrase in the session to test for the user
+// input later
+$_SESSION['phrase'] = $builder->getPhrase();
+```
+
+You can compare the phrase with user input:
+```php
+if($builder->testPhrase($userInput)) {
+ // instructions if user phrase is good
+}
+else {
+ // user phrase is wrong
+}
+```
+
+API
+===
+
+You can use theses functions :
+
+* **__construct($phrase = null)**, constructs the builder with the given phrase, if the phrase is null, a random one will be generated
+* **getPhrase()**, allow you to get the phrase contents
+* **setDistortion($distortion)**, enable or disable the distortion, call it before `build()`
+* **isOCRReadable()**, returns `true` if the OCR can be read using the `ocrad` software, you'll need to have shell_exec enabled, imagemagick and ocrad installed
+* **buildAgainstOCR($width = 150, $height = 40, $font = null)**, builds a code until it is not readable by `ocrad`
+* **build($width = 150, $height = 40, $font = null)**, builds a code with the given $width, $height and $font. By default, a random font will be used from the library
+* **save($filename, $quality = 80)**, saves the captcha into a jpeg in the $filename, with the given quality
+* **get($quality = 80)**, returns the jpeg data
+* **output($quality = 80)**, directly outputs the jpeg code to a browser
+* **setBackgroundColor($r, $g, $b)**, sets the background color to force it (this will disable many effects and is not recommended)
+* **setBackgroundImages(array($imagepath1, $imagePath2))**, Sets custom background images to be used as captcha background. It is recommended to disable image effects when passing custom images for background (ignore_all_effects). A random image is selected from the list passed, the full paths to the image files must be passed.
+* **setInterpolation($interpolate)**, enable or disable the interpolation (enabled by default), disabling it will be quicker but the images will look uglier
+* **setIgnoreAllEffects($ignoreAllEffects)**, disable all effects on the captcha image. Recommended to use when passing custom background images for the captcha.
+* **testPhrase($phrase)**, returns true if the given phrase is good
+* **setMaxBehindLines($lines)**, sets the maximum number of lines behind the code
+* **setMaxFrontLines($lines)**, sets the maximum number of lines on the front of the code
+
+Symfony 2 Bundle
+================
+
+You can have a look at the following repository to enjoy the Symfony 2 bundle packaging this captcha generator :
+https://github.com/Gregwar/CaptchaBundle
+
+License
+=======
+
+This library is under MIT license, have a look to the `LICENSE` file
diff --git a/vendor/gregwar/captcha/autoload.php b/vendor/gregwar/captcha/autoload.php
new file mode 100644
index 00000000..8b3fa392
--- /dev/null
+++ b/vendor/gregwar/captcha/autoload.php
@@ -0,0 +1,16 @@
+<?php
+
+/**
+* Registers an autoload for all the classes in Gregwar\Captcha
+*/
+spl_autoload_register(function ($className) {
+ $namespace = 'Gregwar\\Captcha';
+
+ if (strpos($className, $namespace) === 0) {
+ $className = str_replace($namespace, '', $className);
+ $fileName = __DIR__ . '/' . str_replace('\\', '/', $className) . '.php';
+ if (file_exists($fileName)) {
+ require($fileName);
+ }
+ }
+});
diff --git a/vendor/gregwar/captcha/composer.json b/vendor/gregwar/captcha/composer.json
new file mode 100644
index 00000000..ef79423b
--- /dev/null
+++ b/vendor/gregwar/captcha/composer.json
@@ -0,0 +1,28 @@
+{
+ "name": "gregwar/captcha",
+ "type": "captcha",
+ "description": "Captcha generator",
+ "keywords": ["captcha", "spam", "bot"],
+ "homepage": "https://github.com/Gregwar/Captcha",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Grégoire Passault",
+ "email": "g.passault@gmail.com",
+ "homepage": "http://www.gregwar.com/"
+ },
+ {
+ "name": "Jeremy Livingston",
+ "email": "jeremy.j.livingston@gmail.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.0",
+ "ext-gd": "*"
+ },
+ "autoload": {
+ "psr-4": {
+ "Gregwar\\Captcha\\": "/"
+ }
+ }
+}
diff --git a/vendor/gregwar/captcha/demo/demo.php b/vendor/gregwar/captcha/demo/demo.php
new file mode 100644
index 00000000..7852745f
--- /dev/null
+++ b/vendor/gregwar/captcha/demo/demo.php
@@ -0,0 +1,14 @@
+<?php
+
+include(__DIR__.'/../CaptchaBuilderInterface.php');
+include(__DIR__.'/../PhraseBuilderInterface.php');
+include(__DIR__.'/../CaptchaBuilder.php');
+include(__DIR__.'/../PhraseBuilder.php');
+
+use Gregwar\Captcha\CaptchaBuilder;
+
+$captcha = new CaptchaBuilder;
+$captcha
+ ->build()
+ ->save('out.jpg')
+;
diff --git a/vendor/gregwar/captcha/demo/fingerprint.php b/vendor/gregwar/captcha/demo/fingerprint.php
new file mode 100644
index 00000000..ce30d991
--- /dev/null
+++ b/vendor/gregwar/captcha/demo/fingerprint.php
@@ -0,0 +1,15 @@
+<?php
+
+include(__DIR__.'/../CaptchaBuilderInterface.php');
+include(__DIR__.'/../PhraseBuilderInterface.php');
+include(__DIR__.'/../CaptchaBuilder.php');
+include(__DIR__.'/../PhraseBuilder.php');
+
+use Gregwar\Captcha\CaptchaBuilder;
+
+echo count(CaptchaBuilder::create()
+ ->build()
+ ->getFingerprint()
+);
+
+echo "\n";
diff --git a/vendor/gregwar/captcha/demo/index.php b/vendor/gregwar/captcha/demo/index.php
new file mode 100644
index 00000000..e543883b
--- /dev/null
+++ b/vendor/gregwar/captcha/demo/index.php
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<body>
+ <html>
+ <meta charset="utf-8" />
+ </html>
+ <body>
+ <h1>Captchas gallery</h1>
+ <?php for ($x=0; $x<8; $x++) { ?>
+ <?php for ($y=0; $y<5; $y++) { ?>
+ <img src="output.php?n=<?php echo 5*$x+$y; ?>" />
+ <?php } ?>
+ <br />
+ <?php } ?>
+ </body>
+</body>
diff --git a/vendor/gregwar/captcha/demo/ocr.php b/vendor/gregwar/captcha/demo/ocr.php
new file mode 100644
index 00000000..3d745f65
--- /dev/null
+++ b/vendor/gregwar/captcha/demo/ocr.php
@@ -0,0 +1,42 @@
+<?php
+
+include(__DIR__.'/../CaptchaBuilderInterface.php');
+include(__DIR__.'/../PhraseBuilderInterface.php');
+include(__DIR__.'/../CaptchaBuilder.php');
+include(__DIR__.'/../PhraseBuilder.php');
+
+use Gregwar\Captcha\CaptchaBuilder;
+
+/**
+ * Generates 1000 captchas and try to read their code with the
+ * ocrad OCR
+ */
+
+$tests = 10000;
+$passed = 0;
+
+shell_exec('rm passed*.jpg');
+
+for ($i=0; $i<$tests; $i++) {
+ echo "Captcha $i/$tests... ";
+
+ $captcha = new CaptchaBuilder;
+
+ $captcha
+ ->setDistortion(false)
+ ->build()
+ ;
+
+ if ($captcha->isOCRReadable()) {
+ $passed++;
+ $captcha->save("passed$passed.jpg");
+ echo "passed at ocr... ";
+ } else {
+ echo "failed... ";
+ }
+
+ echo "pass rate: ".round(100*$passed/($i+1),2)."%\n";
+}
+
+echo "\n";
+echo "Over, $passed/$tests readed with OCR\n";
diff --git a/vendor/gregwar/captcha/demo/output.php b/vendor/gregwar/captcha/demo/output.php
new file mode 100644
index 00000000..2a4f3303
--- /dev/null
+++ b/vendor/gregwar/captcha/demo/output.php
@@ -0,0 +1,15 @@
+<?php
+
+include(__DIR__.'/../CaptchaBuilderInterface.php');
+include(__DIR__.'/../PhraseBuilderInterface.php');
+include(__DIR__.'/../CaptchaBuilder.php');
+include(__DIR__.'/../PhraseBuilder.php');
+
+use Gregwar\Captcha\CaptchaBuilder;
+
+header('Content-type: image/jpeg');
+
+CaptchaBuilder::create()
+ ->build()
+ ->output()
+;