PageRenderTime 133ms CodeModel.GetById 50ms app.highlight 73ms RepoModel.GetById 1ms app.codeStats 0ms

/src/apps/passport/libraries/securimage/securimage.php

https://github.com/42Team-itslove/passport
PHP | 1683 lines | 827 code | 221 blank | 635 comment | 202 complexity | 68a9f2af346e32c9f2e392d8de3199cb MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2/**
   3 * Securimage CAPTCHA Class.
   4 *
   5 * A class for creating and validating secure CAPTCHA images and audio.
   6 *
   7 * The class contains many options regarding appearance, security, storage of
   8 * captcha data and image/audio generation options.
   9 *
  10 * @version    3.5.2
  11 * @package    Securimage
  12 * @subpackage classes
  13 * @author     Drew Phillips <drew@drew-phillips.com>
  14 *
  15 */
  16class Securimage
  17{
  18    // All of the public variables below are securimage options
  19    // They can be passed as an array to the Securimage constructor, set below,
  20    // or set from securimage_show.php and securimage_play.php
  21
  22    /**
  23     * Constant for rendering captcha as a JPEG image
  24     * @var int
  25     */
  26    const SI_IMAGE_JPEG = 1;
  27
  28    /**
  29     * Constant for rendering captcha as a PNG image (default)
  30     * @var int
  31     */
  32
  33    const SI_IMAGE_PNG  = 2;
  34    /**
  35     * Constant for rendering captcha as a GIF image
  36     * @var int
  37     */
  38    const SI_IMAGE_GIF  = 3;
  39
  40    /**
  41     * Constant for generating a normal alphanumeric captcha based on the
  42     * character set
  43     *
  44     * @see Securimage::$charset charset property
  45     * @var int
  46     */
  47    const SI_CAPTCHA_STRING     = 0;
  48
  49    /**
  50     * Constant for generating a captcha consisting of a simple math problem
  51     *
  52     * @var int
  53     */
  54    const SI_CAPTCHA_MATHEMATIC = 1;
  55
  56    /**
  57     * Constant for generating a word based captcha using 2 words from a list
  58     *
  59     * @var int
  60     */
  61    const SI_CAPTCHA_WORDS      = 2;
  62
  63    /*%*********************************************************************%*/
  64    // Properties
  65
  66    /**
  67     * The width of the captcha image
  68     * @var int
  69     */
  70    public $image_width = 215;
  71
  72    /**
  73     * The height of the captcha image
  74     * @var int
  75     */
  76    public $image_height = 80;
  77
  78    /**
  79     * Font size is calculated by image height and this ratio.  Leave blank for
  80     * default ratio of 0.4.
  81     *
  82     * Valid range: 0.1 - 0.99.
  83     *
  84     * Depending on image_width, values > 0.6 are probably too large and
  85     * values < 0.3 are too small.
  86     *
  87     * @var float
  88     */
  89    public $font_ratio;
  90
  91    /**
  92     * The type of the image, default = png
  93     *
  94     * @see Securimage::SI_IMAGE_PNG SI_IMAGE_PNG
  95     * @see Securimage::SI_IMAGE_JPEG SI_IMAGE_JPEG
  96     * @see Securimage::SI_IMAGE_GIF SI_IMAGE_GIF
  97     * @var int
  98     */
  99    public $image_type   = self::SI_IMAGE_PNG;
 100
 101    /**
 102     * The background color of the captcha
 103     * @var Securimage_Color
 104     */
 105    public $image_bg_color = '#ffffff';
 106
 107    /**
 108     * The color of the captcha text
 109     * @var Securimage_Color
 110     */
 111    public $text_color     = '#707070';
 112
 113    /**
 114     * The color of the lines over the captcha
 115     * @var Securimage_Color
 116     */
 117    public $line_color     = '#707070';
 118
 119    /**
 120     * The color of the noise that is drawn
 121     * @var Securimage_Color
 122     */
 123    public $noise_color    = '#707070';
 124
 125    /**
 126     * How transparent to make the text.
 127     *
 128     * 0 = completely opaque, 100 = invisible
 129     *
 130     * @var int
 131     */
 132    public $text_transparency_percentage = 20;
 133
 134    /**
 135     * Whether or not to draw the text transparently.
 136     *
 137     * true = use transparency, false = no transparency
 138     *
 139     * @var bool
 140     */
 141    public $use_transparent_text         = true;
 142
 143    /**
 144     * The length of the captcha code
 145     * @var int
 146     */
 147    public $code_length    = 6;
 148
 149    /**
 150     * Whether the captcha should be case sensitive or not.
 151     *
 152     * Not recommended, use only for maximum protection.
 153     *
 154     * @var bool
 155     */
 156    public $case_sensitive = false;
 157
 158    /**
 159     * The character set to use for generating the captcha code
 160     * @var string
 161     */
 162    public $charset        = 'ABCDEFGHKLMNPRSTUVWYZabcdefghklmnprstuvwyz23456789';
 163
 164    /**
 165     * How long in seconds a captcha remains valid, after this time it will be
 166     * considered incorrect.
 167     *
 168     * @var int
 169     */
 170    public $expiry_time    = 900;
 171
 172    /**
 173     * The session name securimage should use.
 174     *
 175     * Only use if your application uses a custom session name (e.g. Joomla).
 176     * It is recommended to set this value here so it is used by all securimage
 177     * scripts (i.e. securimage_show.php)
 178     *
 179     * @var string
 180     */
 181    public $session_name   = null;
 182
 183    /**
 184     * true to use the wordlist file, false to generate random captcha codes
 185     * @var bool
 186     */
 187    public $use_wordlist   = false;
 188
 189    /**
 190     * The level of distortion.
 191     *
 192     * 0.75 = normal, 1.0 = very high distortion
 193     *
 194     * @var double
 195     */
 196    public $perturbation = 0.85;
 197
 198    /**
 199     * How many lines to draw over the captcha code to increase security
 200     * @var int
 201     */
 202    public $num_lines    = 5;
 203
 204    /**
 205     * The level of noise (random dots) to place on the image, 0-10
 206     * @var int
 207     */
 208    public $noise_level  = 2;
 209
 210    /**
 211     * The signature text to draw on the bottom corner of the image
 212     * @var string
 213     */
 214    public $image_signature = '';
 215
 216    /**
 217     * The color of the signature text
 218     * @var Securimage_Color
 219     */
 220    public $signature_color = '#707070';
 221
 222    /**
 223     * The path to the ttf font file to use for the signature text.
 224     * Defaults to $ttf_file (AHGBold.ttf)
 225     *
 226     * @see Securimage::$ttf_file
 227     * @var string
 228     */
 229    public $signature_font;
 230
 231    /**
 232     * The type of captcha to create.
 233     *
 234     * Either alphanumeric based on *charset*, a simple math problem, or an
 235     * image consisting of 2 words from the word list.
 236     *
 237     * @see Securimage::SI_CAPTCHA_STRING SI_CAPTCHA_STRING
 238     * @see Securimage::SI_CAPTCHA_MATHEMATIC SI_CAPTCHA_MATHEMATIC
 239     * @see Securimage::SI_CAPTCHA_WORDS SI_CAPTCHA_WORDS
 240     * @see Securimage::$charset charset property
 241     * @see Securimage::$wordlist_file wordlist_file property
 242     * @var int
 243     */
 244    public $captcha_type  = self::SI_CAPTCHA_STRING; // or self::SI_CAPTCHA_MATHEMATIC, or self::SI_CAPTCHA_WORDS;
 245
 246    /**
 247     * The captcha namespace used for having multiple captchas on a page or
 248     * to separate captchas from differen forms on your site.
 249     * Example:
 250     *
 251     *     <?php
 252     *     // use <img src="securimage_show.php?namespace=contact_form">
 253     *     // or manually in securimage_show.php
 254     *     $img->setNamespace('contact_form');
 255     *
 256     *     // in form validator
 257     *     $img->setNamespace('contact_form');
 258     *     if ($img->check($code) == true) {
 259     *         echo "Valid!";
 260     *     }
 261     *
 262     * @var string
 263     */
 264    public $namespace;
 265
 266    /**
 267     * The TTF font file to use to draw the captcha code.
 268     *
 269     * Leave blank for default font AHGBold.ttf
 270     *
 271     * @var string
 272     */
 273    public $ttf_file;
 274
 275    /**
 276     * The path to the wordlist file to use.
 277     *
 278     * Leave blank for default words/words.txt
 279     *
 280     * @var string
 281     */
 282    public $wordlist_file;
 283
 284    /**
 285     * The directory to scan for background images, if set a random background
 286     * will be chosen from this folder
 287     *
 288     * @var string
 289     */
 290    public $background_directory;
 291
 292    /**
 293     * Captcha ID if using static captcha
 294     * @var string Unique captcha id
 295     */
 296    protected static $_captchaId = null;
 297
 298    /**
 299     * The GD image resource of the captcha image
 300     *
 301     * @var resource
 302     */
 303    protected $im;
 304
 305    /**
 306     * A temporary GD image resource of the captcha image for distortion
 307     *
 308     * @var resource
 309     */
 310    protected $tmpimg;
 311
 312    /**
 313     * The background image GD resource
 314     * @var resource
 315     */
 316    protected $bgimg;
 317
 318    /**
 319     * Scale factor for magnification of distorted captcha image
 320     *
 321     * @var int
 322     */
 323    protected $iscale = 5;
 324
 325    /**
 326     * Absolute path to securimage directory.
 327     *
 328     * This is calculated at runtime
 329     *
 330     * @var string
 331     */
 332    public $securimage_path = null;
 333
 334    /**
 335     * The captcha challenge value.
 336     *
 337     * Either the case-sensitive/insensitive word captcha, or the solution to
 338     * the math captcha.
 339     *
 340     * @var string Captcha challenge value
 341     */
 342    protected $code;
 343
 344    /**
 345     * The display value of the captcha to draw on the image
 346     *
 347     * Either the word captcha or the math equation to present to the user
 348     *
 349     * @var string Captcha display value to draw on the image
 350     */
 351    protected $code_display;
 352
 353    /**
 354     * Alternate text to draw as the captcha image text
 355     *
 356     * A value that can be passed to the constructor that can be used to
 357     * generate a captcha image with a given value.
 358     *
 359     * This value does not get stored in the session or database and is only
 360     * used when calling Securimage::show().
 361     *
 362     * If a display_value was passed to the constructor and the captcha image
 363     * is generated, the display_value will be used as the string to draw on
 364     * the captcha image.
 365     *
 366     * Used only if captcha codes are generated and managed by a 3rd party
 367     * app/library
 368     *
 369     * @var string Captcha code value to display on the image
 370     */
 371    public $display_value;
 372
 373    /**
 374     * Captcha code supplied by user [set from Securimage::check()]
 375     *
 376     * @var string
 377     */
 378    protected $captcha_code;
 379
 380    /**
 381     * Time (in seconds) that the captcha was solved in (correctly or incorrectly).
 382     *
 383     * This is from the time of code creation, to when validation was attempted.
 384     *
 385     * @var int
 386     */
 387    protected $_timeToSolve = 0;
 388
 389    /**
 390     * Flag that can be specified telling securimage not to call exit after
 391     * generating a captcha image or audio file
 392     *
 393     * @var bool If true, script will not terminate; if false script will terminate (default)
 394     */
 395    protected $no_exit;
 396
 397
 398    /**
 399     * Flag indicating whether or not HTTP headers will be sent when outputting
 400     * captcha image/audio
 401     *
 402     * @var bool If true (default) headers will be sent, if false, no headers are sent
 403     */
 404    protected $send_headers;
 405
 406
 407    /**
 408     * The GD color resource for the background color
 409     *
 410     * @var resource
 411     */
 412    protected $gdbgcolor;
 413
 414    /**
 415     * The GD color resource for the text color
 416     *
 417     * @var resource
 418     */
 419    protected $gdtextcolor;
 420
 421    /**
 422     * The GD color resource for the line color
 423     *
 424     * @var resource
 425     */
 426    protected $gdlinecolor;
 427
 428    /**
 429     * The GD color resource for the signature text color
 430     *
 431     * @var resource
 432     */
 433    protected $gdsignaturecolor;
 434
 435	/**
 436	 * The Placon Session
 437	 * @var
 438	 */
 439	protected $session;
 440
 441    /**
 442     * Create a new securimage object, pass options to set in the constructor.
 443     *
 444     * The object can then be used to display a captcha, play an audible captcha, or validate a submission.
 445     *
 446     * @param array $options  Options to initialize the class.  May be any class property.
 447     *
 448     *     $options = array(
 449     *         'text_color' => new Securimage_Color('#013020'),
 450     *         'code_length' => 5,
 451     *         'num_lines' => 5,
 452     *         'noise_level' => 3,
 453     *         'font_file' => Securimage::getPath() . '/custom.ttf'
 454     *     );
 455     *
 456     *     $img = new Securimage($options);
 457     *
 458     */
 459    public function __construct($options = array())
 460    {
 461        $this->securimage_path = dirname(__FILE__);
 462
 463        if (is_array($options) && sizeof($options) > 0) {
 464            foreach($options as $prop => $val) {
 465                if ($prop == 'captchaId') {
 466                    Securimage::$_captchaId = $val;
 467                    $this->use_database     = true;
 468                } else if ($prop == 'use_sqlite_db') {
 469                    trigger_error("The use_sqlite_db option is deprecated, use 'use_database' instead", E_USER_NOTICE);
 470                } else {
 471                    $this->$prop = $val;
 472                }
 473            }
 474        }
 475
 476        $this->image_bg_color  = $this->initColor($this->image_bg_color,  '#ffffff');
 477        $this->text_color      = $this->initColor($this->text_color,      '#616161');
 478        $this->line_color      = $this->initColor($this->line_color,      '#616161');
 479        $this->noise_color     = $this->initColor($this->noise_color,     '#616161');
 480        $this->signature_color = $this->initColor($this->signature_color, '#616161');
 481
 482        if (is_null($this->ttf_file)) {
 483            $this->ttf_file = $this->securimage_path . '/AHGBold.ttf';
 484        }
 485
 486        $this->signature_font = $this->ttf_file;
 487
 488        if (is_null($this->wordlist_file)) {
 489            $this->wordlist_file = $this->securimage_path . '/words/words.txt';
 490        }
 491
 492
 493        if (is_null($this->code_length) || (int)$this->code_length < 1) {
 494            $this->code_length = 6;
 495        }
 496
 497        if (is_null($this->perturbation) || !is_numeric($this->perturbation)) {
 498            $this->perturbation = 0.75;
 499        }
 500
 501        if (is_null($this->namespace) || !is_string($this->namespace)) {
 502            $this->namespace = 'default';
 503        }
 504
 505        if (is_null($this->no_exit)) {
 506            $this->no_exit = false;
 507        }
 508
 509        if (is_null($this->send_headers)) {
 510            $this->send_headers = true;
 511        }
 512
 513    }
 514
 515    /**
 516     * Return the absolute path to the Securimage directory.
 517     *
 518     * @return string The path to the securimage base directory
 519     */
 520    public static function getPath()
 521    {
 522        return dirname(__FILE__);
 523    }
 524
 525    /**
 526     * Generate a new captcha ID or retrieve the current ID (if exists).
 527     *
 528     * @param bool $new If true, generates a new challenge and returns and ID.  If false, the existing captcha ID is returned, or null if none exists.
 529     * @param array $options Additional options to be passed to Securimage.
 530     *   $options must include database settings if they are not set directly in securimage.php
 531     *
 532     * @return null|string Returns null if no captcha id set and new was false, or the captcha ID
 533     */
 534    public static function getCaptchaId($new = true, array $options = array())
 535    {
 536        if (is_null($new) || (bool)$new == true) {
 537            $id = sha1(uniqid($_SERVER['REMOTE_ADDR'], true));
 538            $opts = array('no_session'    => true,
 539                          'use_database'  => true);
 540            if (sizeof($options) > 0) $opts = array_merge($options, $opts);
 541            $si = new self($opts);
 542            Securimage::$_captchaId = $id;
 543            $si->createCode();
 544
 545            return $id;
 546        } else {
 547            return Securimage::$_captchaId;
 548        }
 549    }
 550
 551    /**
 552     * Validate a captcha code input against a captcha ID
 553     *
 554     * @param string $id       The captcha ID to check
 555     * @param string $value    The captcha value supplied by the user
 556     * @param array  $options  Array of options to construct Securimage with.
 557     *   Options must include database options if they are not set in securimage.php
 558     *
 559     * @see Securimage::$database_driver
 560     * @return bool true if the code was valid for the given captcha ID, false if not or if database failed to open
 561     */
 562    public static function checkByCaptchaId($id, $value, array $options = array())
 563    {
 564        $opts = array('captchaId'    => $id,
 565                      'no_session'   => true,
 566                      'use_database' => true);
 567
 568        if (sizeof($options) > 0) $opts = array_merge($options, $opts);
 569
 570        $si = new self($opts);
 571    }
 572
 573
 574    /**
 575     * Generates a new challenge and serves a captcha image.
 576     *
 577     * Appropriate headers will be sent to the browser unless the *send_headers* option is false.
 578     *
 579     * @param string $background_image The absolute or relative path to the background image to use as the background of the captcha image.
 580     *
 581     *     $img = new Securimage();
 582     *     $img->code_length = 6;
 583     *     $img->num_lines   = 5;
 584     *     $img->noise_level = 5;
 585     *
 586     *     $img->show(); // sends the image and appropriate headers to browser
 587     *     exit;
 588     */
 589    public function show($background_image = '')
 590    {
 591        set_error_handler(array(&$this, 'errorHandler'));
 592
 593        if($background_image != '' && is_readable($background_image)) {
 594            $this->bgimg = $background_image;
 595        }
 596
 597        $this->doImage();
 598    }
 599
 600    /**
 601     * Checks a given code against the correct value from the session and/or database.
 602     *
 603     * @param string $code  The captcha code to check
 604     *
 605     *     $code = $_POST['code'];
 606     *     $img  = new Securimage();
 607     *     if ($img->check($code) == true) {
 608     *         $captcha_valid = true;
 609     *     } else {
 610     *         $captcha_valid = false;
 611     *     }
 612     *
 613     * @return bool true if the given code was correct, false if not.
 614     */
 615    public function check($code)
 616    {
 617        $this->code_entered = $code;
 618        $this->validate();
 619        return $this->correct_code;
 620    }
 621
 622
 623    /**
 624     * Get the time in seconds that it took to solve the captcha.
 625     *
 626     * @return int The time in seconds from when the code was created, to when it was solved
 627     */
 628    public function getTimeToSolve()
 629    {
 630        return $this->_timeToSolve;
 631    }
 632
 633    /**
 634     * Set the namespace for the captcha being stored in the session or database.
 635     *
 636     * Namespaces are useful when multiple captchas need to be displayed on a single page.
 637     *
 638     * @param string $namespace  Namespace value, String consisting of characters "a-zA-Z0-9_-"
 639     */
 640    public function setNamespace($namespace)
 641    {
 642        $namespace = preg_replace('/[^a-z0-9-_]/i', '', $namespace);
 643        $namespace = substr($namespace, 0, 64);
 644
 645        if (!empty($namespace)) {
 646            $this->namespace = $namespace;
 647        } else {
 648            $this->namespace = 'default';
 649        }
 650    }
 651
 652    /**
 653     * Return the code from the session or database (if configured).  If none exists or was found, an empty string is returned.
 654     *
 655     * @param bool $array  true to receive an array containing the code and properties, false to receive just the code.
 656     * @param bool $returnExisting If true, and the class property *code* is set, it will be returned instead of getting the code from the session or database.
 657     * @return array|string Return is an array if $array = true, otherwise a string containing the code
 658     */
 659    public function getCode($array = false, $returnExisting = false)
 660    {
 661        $code = array();
 662        $time = 0;
 663        $disp = 'error';
 664
 665        if ($returnExisting && strlen($this->code) > 0) {
 666            if ($array) {
 667                return array(
 668                    'code'         => $this->code,
 669                    'display'      => $this->code_display,
 670                    'code_display' => $this->code_display,
 671                    'time'         => 0);
 672            } else {
 673                return $this->code;
 674            }
 675        }
 676
 677        if ($this->session->has('securimage') && isset($this->session->securimage[$this->namespace]) &&
 678                trim($this->session->securimage[$this->namespace]['code_value']) != '') {
 679            if ($this->isCodeExpired(
 680                    $this->session->securimage[$this->namespace]['code_ctime'] == false)) {
 681                $code['code'] = $this->session->securimage[$this->namespace]['code_value'];
 682                $code['time'] = $this->session->securimage[$this->namespace]['code_ctime'];
 683                $code['display'] = $this->session->securimage[$this->namespace]['code_disp'];
 684            }
 685        }
 686
 687        if ($array == true) {
 688            return $code;
 689        } else {
 690            return isset($code['code']) ? $code['code'] : false;
 691        }
 692    }
 693
 694    /**
 695     * The main image drawing routing, responsible for constructing the entire image and serving it
 696     */
 697    protected function doImage()
 698    {
 699        if( ($this->use_transparent_text == true || $this->bgimg != '') && function_exists('imagecreatetruecolor')) {
 700            $imagecreate = 'imagecreatetruecolor';
 701        } else {
 702            $imagecreate = 'imagecreate';
 703        }
 704
 705        $this->im     = $imagecreate($this->image_width, $this->image_height);
 706        $this->tmpimg = $imagecreate($this->image_width * $this->iscale, $this->image_height * $this->iscale);
 707
 708        $this->allocateColors();
 709        imagepalettecopy($this->tmpimg, $this->im);
 710
 711        $this->setBackground();
 712
 713        $code = '';
 714
 715        if ($this->getCaptchaId(false) !== null) {
 716            // a captcha Id was supplied
 717
 718            // check to see if a display_value for the captcha image was set
 719            if (is_string($this->display_value) && strlen($this->display_value) > 0) {
 720                $this->code_display = $this->display_value;
 721                $this->code         = ($this->case_sensitive) ?
 722                                       $this->display_value   :
 723                                       strtolower($this->display_value);
 724                $code = $this->code;
 725            }
 726        }
 727
 728        if ($code == '') {
 729            // if the code was not set using display_value or was not found in
 730            // the database, create a new code
 731            $this->createCode();
 732        }
 733
 734        if ($this->noise_level > 0) {
 735            $this->drawNoise();
 736        }
 737
 738        $this->drawWord();
 739
 740        if ($this->perturbation > 0 && is_readable($this->ttf_file)) {
 741            $this->distortedCopy();
 742        }
 743
 744        if ($this->num_lines > 0) {
 745            $this->drawLines();
 746        }
 747
 748        if (trim($this->image_signature) != '') {
 749            $this->addSignature();
 750        }
 751
 752        $this->output();
 753    }
 754
 755    /**
 756     * Allocate the colors to be used for the image
 757     */
 758    protected function allocateColors()
 759    {
 760        // allocate bg color first for imagecreate
 761        $this->gdbgcolor = imagecolorallocate($this->im,
 762                                              $this->image_bg_color->r,
 763                                              $this->image_bg_color->g,
 764                                              $this->image_bg_color->b);
 765
 766        $alpha = intval($this->text_transparency_percentage / 100 * 127);
 767
 768        if ($this->use_transparent_text == true) {
 769            $this->gdtextcolor = imagecolorallocatealpha($this->im,
 770                                                         $this->text_color->r,
 771                                                         $this->text_color->g,
 772                                                         $this->text_color->b,
 773                                                         $alpha);
 774            $this->gdlinecolor = imagecolorallocatealpha($this->im,
 775                                                         $this->line_color->r,
 776                                                         $this->line_color->g,
 777                                                         $this->line_color->b,
 778                                                         $alpha);
 779            $this->gdnoisecolor = imagecolorallocatealpha($this->im,
 780                                                          $this->noise_color->r,
 781                                                          $this->noise_color->g,
 782                                                          $this->noise_color->b,
 783                                                          $alpha);
 784        } else {
 785            $this->gdtextcolor = imagecolorallocate($this->im,
 786                                                    $this->text_color->r,
 787                                                    $this->text_color->g,
 788                                                    $this->text_color->b);
 789            $this->gdlinecolor = imagecolorallocate($this->im,
 790                                                    $this->line_color->r,
 791                                                    $this->line_color->g,
 792                                                    $this->line_color->b);
 793            $this->gdnoisecolor = imagecolorallocate($this->im,
 794                                                          $this->noise_color->r,
 795                                                          $this->noise_color->g,
 796                                                          $this->noise_color->b);
 797        }
 798
 799        $this->gdsignaturecolor = imagecolorallocate($this->im,
 800                                                     $this->signature_color->r,
 801                                                     $this->signature_color->g,
 802                                                     $this->signature_color->b);
 803
 804    }
 805
 806    /**
 807     * The the background color, or background image to be used
 808     */
 809    protected function setBackground()
 810    {
 811        // set background color of image by drawing a rectangle since imagecreatetruecolor doesn't set a bg color
 812        imagefilledrectangle($this->im, 0, 0,
 813                             $this->image_width, $this->image_height,
 814                             $this->gdbgcolor);
 815        imagefilledrectangle($this->tmpimg, 0, 0,
 816                             $this->image_width * $this->iscale, $this->image_height * $this->iscale,
 817                             $this->gdbgcolor);
 818
 819        if ($this->bgimg == '') {
 820            if ($this->background_directory != null &&
 821                is_dir($this->background_directory) &&
 822                is_readable($this->background_directory))
 823            {
 824                $img = $this->getBackgroundFromDirectory();
 825                if ($img != false) {
 826                    $this->bgimg = $img;
 827                }
 828            }
 829        }
 830
 831        if ($this->bgimg == '') {
 832            return;
 833        }
 834
 835        $dat = @getimagesize($this->bgimg);
 836        if($dat == false) {
 837            return;
 838        }
 839
 840        switch($dat[2]) {
 841            case 1:  $newim = @imagecreatefromgif($this->bgimg); break;
 842            case 2:  $newim = @imagecreatefromjpeg($this->bgimg); break;
 843            case 3:  $newim = @imagecreatefrompng($this->bgimg); break;
 844            default: return;
 845        }
 846
 847        if(!$newim) return;
 848
 849        imagecopyresized($this->im, $newim, 0, 0, 0, 0,
 850                         $this->image_width, $this->image_height,
 851                         imagesx($newim), imagesy($newim));
 852    }
 853
 854    /**
 855     * Scan the directory for a background image to use
 856     */
 857    protected function getBackgroundFromDirectory()
 858    {
 859        $images = array();
 860
 861        if ( ($dh = opendir($this->background_directory)) !== false) {
 862            while (($file = readdir($dh)) !== false) {
 863                if (preg_match('/(jpg|gif|png)$/i', $file)) $images[] = $file;
 864            }
 865
 866            closedir($dh);
 867
 868            if (sizeof($images) > 0) {
 869                return rtrim($this->background_directory, '/') . '/' . $images[mt_rand(0, sizeof($images)-1)];
 870            }
 871        }
 872
 873        return false;
 874    }
 875
 876    /**
 877     * This method generates a new captcha code.
 878     *
 879     * Generates a random captcha code based on *charset*, math problem, or captcha from the wordlist and saves the value to the session and/or database.
 880     */
 881    public function createCode()
 882    {
 883        $this->code = false;
 884
 885        switch($this->captcha_type) {
 886            case self::SI_CAPTCHA_MATHEMATIC:
 887            {
 888                do {
 889                    $signs = array('+', '-', 'x');
 890                    $left  = mt_rand(1, 10);
 891                    $right = mt_rand(1, 5);
 892                    $sign  = $signs[mt_rand(0, 2)];
 893
 894                    switch($sign) {
 895                        case 'x': $c = $left * $right; break;
 896                        case '-': $c = $left - $right; break;
 897                        default:  $c = $left + $right; break;
 898                    }
 899                } while ($c <= 0); // no negative #'s or 0
 900
 901                $this->code         = $c;
 902                $this->code_display = "$left $sign $right";
 903                break;
 904            }
 905
 906            case self::SI_CAPTCHA_WORDS:
 907                $words = $this->readCodeFromFile(2);
 908                $this->code = implode(' ', $words);
 909                $this->code_display = $this->code;
 910                break;
 911
 912            default:
 913            {
 914                if ($this->use_wordlist && is_readable($this->wordlist_file)) {
 915                    $this->code = $this->readCodeFromFile();
 916                }
 917
 918                if ($this->code == false) {
 919                    $this->code = $this->generateCode($this->code_length);
 920                }
 921
 922                $this->code_display = $this->code;
 923                $this->code         = ($this->case_sensitive) ? $this->code : strtolower($this->code);
 924            } // default
 925        }
 926
 927        $this->saveData();
 928    }
 929
 930    /**
 931     * Draws the captcha code on the image
 932     */
 933    protected function drawWord()
 934    {
 935        $width2  = $this->image_width * $this->iscale;
 936        $height2 = $this->image_height * $this->iscale;
 937        $ratio   = ($this->font_ratio) ? $this->font_ratio : 0.4;
 938
 939        if ((float)$ratio < 0.1 || (float)$ratio >= 1) {
 940            $ratio = 0.4;
 941        }
 942
 943        if (!is_readable($this->ttf_file)) {
 944            imagestring($this->im, 4, 10, ($this->image_height / 2) - 5, 'Failed to load TTF font file!', $this->gdtextcolor);
 945        } else {
 946            if ($this->perturbation > 0) {
 947                $font_size = $height2 * $ratio;
 948                $bb = imageftbbox($font_size, 0, $this->ttf_file, $this->code_display);
 949                $tx = $bb[4] - $bb[0];
 950                $ty = $bb[5] - $bb[1];
 951                $x  = floor($width2 / 2 - $tx / 2 - $bb[0]);
 952                $y  = round($height2 / 2 - $ty / 2 - $bb[1]);
 953
 954                imagettftext($this->tmpimg, $font_size, 0, $x, $y, $this->gdtextcolor, $this->ttf_file, $this->code_display);
 955            } else {
 956                $font_size = $this->image_height * $ratio;
 957                $bb = imageftbbox($font_size, 0, $this->ttf_file, $this->code_display);
 958                $tx = $bb[4] - $bb[0];
 959                $ty = $bb[5] - $bb[1];
 960                $x  = floor($this->image_width / 2 - $tx / 2 - $bb[0]);
 961                $y  = round($this->image_height / 2 - $ty / 2 - $bb[1]);
 962
 963                imagettftext($this->im, $font_size, 0, $x, $y, $this->gdtextcolor, $this->ttf_file, $this->code_display);
 964            }
 965        }
 966
 967        // DEBUG
 968        //$this->im = $this->tmpimg;
 969        //$this->output();
 970
 971    }
 972
 973    /**
 974     * Copies the captcha image to the final image with distortion applied
 975     */
 976    protected function distortedCopy()
 977    {
 978        $numpoles = 3; // distortion factor
 979        // make array of poles AKA attractor points
 980        for ($i = 0; $i < $numpoles; ++ $i) {
 981            $px[$i]  = mt_rand($this->image_width  * 0.2, $this->image_width  * 0.8);
 982            $py[$i]  = mt_rand($this->image_height * 0.2, $this->image_height * 0.8);
 983            $rad[$i] = mt_rand($this->image_height * 0.2, $this->image_height * 0.8);
 984            $tmp     = ((- $this->frand()) * 0.15) - .15;
 985            $amp[$i] = $this->perturbation * $tmp;
 986        }
 987
 988        $bgCol = imagecolorat($this->tmpimg, 0, 0);
 989        $width2 = $this->iscale * $this->image_width;
 990        $height2 = $this->iscale * $this->image_height;
 991        imagepalettecopy($this->im, $this->tmpimg); // copy palette to final image so text colors come across
 992        // loop over $img pixels, take pixels from $tmpimg with distortion field
 993        for ($ix = 0; $ix < $this->image_width; ++ $ix) {
 994            for ($iy = 0; $iy < $this->image_height; ++ $iy) {
 995                $x = $ix;
 996                $y = $iy;
 997                for ($i = 0; $i < $numpoles; ++ $i) {
 998                    $dx = $ix - $px[$i];
 999                    $dy = $iy - $py[$i];
1000                    if ($dx == 0 && $dy == 0) {
1001                        continue;
1002                    }
1003                    $r = sqrt($dx * $dx + $dy * $dy);
1004                    if ($r > $rad[$i]) {
1005                        continue;
1006                    }
1007                    $rscale = $amp[$i] * sin(3.14 * $r / $rad[$i]);
1008                    $x += $dx * $rscale;
1009                    $y += $dy * $rscale;
1010                }
1011                $c = $bgCol;
1012                $x *= $this->iscale;
1013                $y *= $this->iscale;
1014                if ($x >= 0 && $x < $width2 && $y >= 0 && $y < $height2) {
1015                    $c = imagecolorat($this->tmpimg, $x, $y);
1016                }
1017                if ($c != $bgCol) { // only copy pixels of letters to preserve any background image
1018                    imagesetpixel($this->im, $ix, $iy, $c);
1019                }
1020            }
1021        }
1022    }
1023
1024    /**
1025     * Draws distorted lines on the image
1026     */
1027    protected function drawLines()
1028    {
1029        for ($line = 0; $line < $this->num_lines; ++ $line) {
1030            $x = $this->image_width * (1 + $line) / ($this->num_lines + 1);
1031            $x += (0.5 - $this->frand()) * $this->image_width / $this->num_lines;
1032            $y = mt_rand($this->image_height * 0.1, $this->image_height * 0.9);
1033
1034            $theta = ($this->frand() - 0.5) * M_PI * 0.7;
1035            $w = $this->image_width;
1036            $len = mt_rand($w * 0.4, $w * 0.7);
1037            $lwid = mt_rand(0, 2);
1038
1039            $k = $this->frand() * 0.6 + 0.2;
1040            $k = $k * $k * 0.5;
1041            $phi = $this->frand() * 6.28;
1042            $step = 0.5;
1043            $dx = $step * cos($theta);
1044            $dy = $step * sin($theta);
1045            $n = $len / $step;
1046            $amp = 1.5 * $this->frand() / ($k + 5.0 / $len);
1047            $x0 = $x - 0.5 * $len * cos($theta);
1048            $y0 = $y - 0.5 * $len * sin($theta);
1049
1050            $ldx = round(- $dy * $lwid);
1051            $ldy = round($dx * $lwid);
1052
1053            for ($i = 0; $i < $n; ++ $i) {
1054                $x = $x0 + $i * $dx + $amp * $dy * sin($k * $i * $step + $phi);
1055                $y = $y0 + $i * $dy - $amp * $dx * sin($k * $i * $step + $phi);
1056                imagefilledrectangle($this->im, $x, $y, $x + $lwid, $y + $lwid, $this->gdlinecolor);
1057            }
1058        }
1059    }
1060
1061    /**
1062     * Draws random noise on the image
1063     */
1064    protected function drawNoise()
1065    {
1066        if ($this->noise_level > 10) {
1067            $noise_level = 10;
1068        } else {
1069            $noise_level = $this->noise_level;
1070        }
1071
1072        $t0 = microtime(true);
1073
1074        $noise_level *= 125; // an arbitrary number that works well on a 1-10 scale
1075
1076        $points = $this->image_width * $this->image_height * $this->iscale;
1077        $height = $this->image_height * $this->iscale;
1078        $width  = $this->image_width * $this->iscale;
1079        for ($i = 0; $i < $noise_level; ++$i) {
1080            $x = mt_rand(10, $width);
1081            $y = mt_rand(10, $height);
1082            $size = mt_rand(7, 10);
1083            if ($x - $size <= 0 && $y - $size <= 0) continue; // dont cover 0,0 since it is used by imagedistortedcopy
1084            imagefilledarc($this->tmpimg, $x, $y, $size, $size, 0, 360, $this->gdnoisecolor, IMG_ARC_PIE);
1085        }
1086
1087        $t1 = microtime(true);
1088
1089        $t = $t1 - $t0;
1090
1091        /*
1092        // DEBUG
1093        imagestring($this->tmpimg, 5, 25, 30, "$t", $this->gdnoisecolor);
1094        header('content-type: image/png');
1095        imagepng($this->tmpimg);
1096        exit;
1097        */
1098    }
1099
1100    /**
1101    * Print signature text on image
1102    */
1103    protected function addSignature()
1104    {
1105        $bbox = imagettfbbox(10, 0, $this->signature_font, $this->image_signature);
1106        $textlen = $bbox[2] - $bbox[0];
1107        $x = $this->image_width - $textlen - 5;
1108        $y = $this->image_height - 3;
1109
1110        imagettftext($this->im, 10, 0, $x, $y, $this->gdsignaturecolor, $this->signature_font, $this->image_signature);
1111    }
1112
1113    /**
1114     * Sends the appropriate image and cache headers and outputs image to the browser
1115     */
1116    protected function output()
1117    {
1118        if ($this->canSendHeaders() || $this->send_headers == false) {
1119            if ($this->send_headers) {
1120                // only send the content-type headers if no headers have been output
1121                // this will ease debugging on misconfigured servers where warnings
1122                // may have been output which break the image and prevent easily viewing
1123                // source to see the error.
1124                header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
1125                header("Last-Modified: " . gmdate("D, d M Y H:i:s") . "GMT");
1126                header("Cache-Control: no-store, no-cache, must-revalidate");
1127                header("Cache-Control: post-check=0, pre-check=0", false);
1128                header("Pragma: no-cache");
1129            }
1130
1131            switch ($this->image_type) {
1132                case self::SI_IMAGE_JPEG:
1133                    if ($this->send_headers) header("Content-Type: image/jpeg");
1134                    imagejpeg($this->im, null, 90);
1135                    break;
1136                case self::SI_IMAGE_GIF:
1137                    if ($this->send_headers) header("Content-Type: image/gif");
1138                    imagegif($this->im);
1139                    break;
1140                default:
1141                    if ($this->send_headers) header("Content-Type: image/png");
1142                    imagepng($this->im);
1143                    break;
1144            }
1145        } else {
1146            echo '<hr /><strong>'
1147                .'Failed to generate captcha image, content has already been '
1148                .'output.<br />This is most likely due to misconfiguration or '
1149                .'a PHP error was sent to the browser.</strong>';
1150        }
1151
1152        imagedestroy($this->im);
1153        restore_error_handler();
1154
1155        if (!$this->no_exit) exit;
1156    }
1157
1158
1159    /**
1160     * Gets a captcha code from a file containing a list of words.
1161     *
1162     * Seek to a random offset in the file and reads a block of data and returns a line from the file.
1163     *
1164     * @param int $numWords Number of words (lines) to read from the file
1165     * @return string|array  Returns a string if only one word is to be read, or an array of words
1166     */
1167    protected function readCodeFromFile($numWords = 1)
1168    {
1169        $fp = fopen($this->wordlist_file, 'rb');
1170        if (!$fp) return false;
1171
1172        $fsize = filesize($this->wordlist_file);
1173        if ($fsize < 128) return false; // too small of a list to be effective
1174
1175        if ((int)$numWords < 1 || (int)$numWords > 5) $numWords = 1;
1176
1177        $words = array();
1178        $i = 0;
1179        do {
1180            fseek($fp, mt_rand(0, $fsize - 64), SEEK_SET); // seek to a random position of file from 0 to filesize-64
1181            $data = fread($fp, 64); // read a chunk from our random position
1182            $data = preg_replace("/\r?\n/", "\n", $data);
1183
1184            $start = @strpos($data, "\n", mt_rand(0, 56)) + 1; // random start position
1185            $end   = @strpos($data, "\n", $start);          // find end of word
1186
1187            if ($start === false) {
1188                // picked start position at end of file
1189                continue;
1190            } else if ($end === false) {
1191                $end = strlen($data);
1192            }
1193
1194            $word = strtolower(substr($data, $start, $end - $start)); // return a line of the file
1195            $words[] = $word;
1196        } while (++$i < $numWords);
1197
1198        fclose($fp);
1199
1200        if ($numWords < 2) {
1201            return $words[0];
1202        } else {
1203            return $words;
1204        }
1205    }
1206
1207    /**
1208     * Generates a random captcha code from the set character set
1209     *
1210     * @see Securimage::$charset  Charset option
1211     * @return string A randomly generated CAPTCHA code
1212     */
1213    protected function generateCode()
1214    {
1215        $code = '';
1216
1217        if (function_exists('mb_strlen')) {
1218            for($i = 1, $cslen = mb_strlen($this->charset); $i <= $this->code_length; ++$i) {
1219                $code .= mb_substr($this->charset, mt_rand(0, $cslen - 1), 1, 'UTF-8');
1220            }
1221        } else {
1222            for($i = 1, $cslen = strlen($this->charset); $i <= $this->code_length; ++$i) {
1223                $code .= substr($this->charset, mt_rand(0, $cslen - 1), 1);
1224            }
1225        }
1226
1227        return $code;
1228    }
1229
1230    /**
1231     * Validate a code supplied by the user
1232     *
1233     * Checks the entered code against the value stored in the session and/or database (if configured).  Handles case sensitivity.
1234     * Also removes the code from session/database if the code was entered correctly to prevent re-use attack.
1235     *
1236     * This function does not return a value.
1237     *
1238     * @see Securimage::$correct_code 'correct_code' property
1239     */
1240    protected function validate()
1241    {
1242        if (!is_string($this->code) || strlen($this->code) == 0) {
1243            $code = $this->getCode(true);
1244            // returns stored code, or an empty string if no stored code was found
1245            // checks the session and database if enabled
1246        } else {
1247            $code = $this->code;
1248        }
1249
1250        if (is_array($code)) {
1251            if (!empty($code)) {
1252                $ctime = $code['time'];
1253                $code  = $code['code'];
1254
1255                $this->_timeToSolve = time() - $ctime;
1256            } else {
1257                $code = '';
1258            }
1259        }
1260
1261        if ($this->case_sensitive == false && preg_match('/[A-Z]/', $code)) {
1262            // case sensitive was set from securimage_show.php but not in class
1263            // the code saved in the session has capitals so set case sensitive to true
1264            $this->case_sensitive = true;
1265        }
1266
1267        $code_entered = trim( (($this->case_sensitive) ? $this->code_entered
1268                                                       : strtolower($this->code_entered))
1269                        );
1270        $this->correct_code = false;
1271
1272        if ($code != '') {
1273            if (strpos($code, ' ') !== false) {
1274                // for multi word captchas, remove more than once space from input
1275                $code_entered = preg_replace('/\s+/', ' ', $code_entered);
1276                $code_entered = strtolower($code_entered);
1277            }
1278
1279            if ((string)$code === (string)$code_entered) {
1280                $this->correct_code = true;
1281	            if ($this->session->has('securimage')) {
1282		            $session_data = $this->session->securimage;
1283	            } else {
1284		            $session_data = array();
1285	            }
1286
1287	            $session_data[$this->namespace] = array(
1288		            'code_disp' => '',
1289		            'code_value' => '',
1290		            'code_ctime' => '',
1291	            );
1292
1293                $this->session->set('securimage', $session_data);
1294            }
1295        }
1296    }
1297
1298    /**
1299     * Save CAPTCHA data to session and database (if configured)
1300     */
1301    protected function saveData()
1302    {
1303        if ($this->session->has('securimage')) {
1304            // fix for migration from v2 - v3
1305            $this->session->remove('securimage');
1306        }
1307
1308	    if ($this->session->has('securimage')) {
1309		    $session_data = $this->session->securimage;
1310	    } else {
1311		    $session_data = array();
1312	    }
1313
1314	    $session_data[$this->namespace] = array(
1315		    'code_disp' => $this->code_display,
1316		    'code_value' => $this->code,
1317		    'code_ctime' => time(),
1318	    );
1319
1320		    $this->session->set('securimage', $session_data);
1321    }
1322
1323    /**
1324     * Checks to see if the captcha code has expired and can no longer be used.
1325     *
1326     * @see Securimage::$expiry_time expiry_time
1327     * @param int $creation_time  The Unix timestamp of when the captcha code was created
1328     * @return bool true if the code is expired, false if it is still valid
1329     */
1330    protected function isCodeExpired($creation_time)
1331    {
1332        $expired = true;
1333
1334        if (!is_numeric($this->expiry_time) || $this->expiry_time < 1) {
1335            $expired = false;
1336        } else if (time() - $creation_time < $this->expiry_time) {
1337            $expired = false;
1338        }
1339
1340        return $expired;
1341    }
1342
1343    /**
1344     * Get a random effect or chain of effects to apply to a segment of the
1345     * audio file.
1346     *
1347     * These effects should increase the randomness of the audio for
1348     * a particular letter/number by modulating the signal.  The SoX effects
1349     * used are *bend*, *chorus*, *overdrive*, *pitch*, *reverb*, *tempo*, and
1350     * *tremolo*.
1351     *
1352     * For each effect selected, random parameters are supplied to the effect.
1353     *
1354     * @param int $numEffects  How many effects to chain together
1355     * @return string  A string of valid SoX effects and their respective options.
1356     */
1357    protected function getSoxEffectChain($numEffects = 2)
1358    {
1359        $effectsList = array('bend', 'chorus', 'overdrive', 'pitch', 'reverb', 'tempo', 'tremolo');
1360        $effects     = array_rand($effectsList, $numEffects);
1361        $outEffects  = array();
1362
1363        if (!is_array($effects)) $effects = array($effects);
1364
1365        foreach($effects as $effect) {
1366            $effect = $effectsList[$effect];
1367
1368            switch($effect)
1369            {
1370                case 'bend':
1371                    $delay = mt_rand(0, 15) / 100.0;
1372                    $cents = mt_rand(-120, 120);
1373                    $dur   = mt_rand(75, 400) / 100.0;
1374                    $outEffects[] = "$effect $delay,$cents,$dur";
1375                    break;
1376
1377                case 'chorus':
1378                    $gainIn  = mt_rand(75, 90) / 100.0;
1379                    $gainOut = mt_rand(70, 95) / 100.0;
1380                    $chorStr = "$effect $gainIn $gainOut";
1381
1382                    for ($i = 0; $i < mt_rand(2, 3); ++$i) {
1383                        $delay = mt_rand(20, 100);
1384                        $decay = mt_rand(10, 100) / 100.0;
1385                        $speed = mt_rand(20, 50) / 100.0;
1386                        $depth = mt_rand(150, 250) / 100.0;
1387
1388                        $chorStr .= " $delay $decay $speed $depth -s";
1389                    }
1390
1391                    $outEffects[] = $chorStr;
1392                    break;
1393
1394                case 'overdrive':
1395                    $gain = mt_rand(5, 25);
1396                    $color = mt_rand(20, 70);
1397                    $outEffects[] = "$effect $gain $color";
1398                    break;
1399
1400                case 'pitch':
1401                    $cents = mt_rand(-300, 300);
1402                    $outEffects[] = "$effect $cents";
1403                    break;
1404
1405                case 'reverb':
1406                    $reverberance = mt_rand(20, 80);
1407                    $damping      = mt_rand(10, 80);
1408                    $scale        = mt_rand(85, 100);
1409                    $depth        = mt_rand(90, 100);
1410                    $predelay     = mt_rand(0, 5);
1411                    $outEffects[] = "$effect $reverberance $damping $scale $depth $predelay";
1412                    break;
1413
1414                case 'tempo':
1415                    $factor = mt_rand(65, 135) / 100.0;
1416                    $outEffects[] = "$effect -s $factor";
1417                    break;
1418
1419                case 'tremolo':
1420                    $hz    = mt_rand(10, 30);
1421                    $depth = mt_rand(40, 85);
1422                    $outEffects[] = "$effect $hz $depth";
1423                    break;
1424            }
1425        }
1426
1427        return implode(' ', $outEffects);
1428    }
1429
1430    /**
1431     * This function is not yet used.
1432     *
1433     * Generate random background noise from sweeping oscillators
1434     *
1435     * @param float $duration  How long in seconds the generated sound will be
1436     * @param int $numChannels Number of channels in output wav
1437     * @param int $sampleRate  Sample rate of output wav
1438     * @param int $bitRate     Bits per sample (8, 16, 24)
1439     * @return string          Audio data in wav format
1440     */
1441    protected function getSoxNoiseData($duration, $numChannels, $sampleRate, $bitRate)
1442    {
1443        $shapes = array('sine', 'square', 'triangle', 'sawtooth', 'trapezium');
1444        $steps  = array(':', '+', '/', '-');
1445        $selShapes = array_rand($shapes, 2);
1446        $selSteps  = array_rand($steps, 2);
1447        $sweep0    = array();
1448        $sweep0[0] = mt_rand(100, 700);
1449        $sweep0[1] = mt_rand(1500, 2500);
1450        $sweep1    = array();
1451        $sweep1[0] = mt_rand(500, 1000);
1452        $sweep1[1] = mt_rand(1200, 2000);
1453
1454        if (mt_rand(0, 10) % 2 == 0)
1455            $sweep0 = array_reverse($sweep0);
1456
1457        if (mt_rand(0, 10) % 2 == 0)
1458            $sweep1 = array_reverse($sweep1);
1459
1460        $cmd = sprintf("%s -c %d -r %d -b %d -n -t wav - synth noise create vol 0.3 synth %.2f %s mix %d%s%d vol 0.3 synth %.2f %s fmod %d%s%d vol 0.3",
1461                       $numChannels,
1462                       $sampleRate,
1463                       $bitRate,
1464                       $duration,
1465                       $shapes[$selShapes[0]],
1466                       $sweep0[0],
1467                       $steps[$selSteps[0]],
1468                       $sweep0[1],
1469                       $duration,
1470                       $shapes[$selShapes[1]],
1471                       $sweep1[0],
1472                       $steps[$selSteps[1]],
1473                       $sweep1[1]
1474                       );
1475        $data = `$cmd`;
1476
1477        return $data;
1478    }
1479
1480
1481    /**
1482     * Checks to see if headers can be sent and if any error has been output
1483     * to the browser
1484     *
1485     * @return bool true if it is safe to send headers, false if not
1486     */
1487    protected function canSendHeaders()
1488    {
1489        if (headers_sent()) {
1490            // output has been flushed and headers have already been sent
1491            return false;
1492        } else if (strlen((string)ob_get_contents()) > 0) {
1493            // headers haven't been sent, but there is data in the buffer that will break image and audio data
1494            return false;
1495        }
1496
1497        return true;
1498    }
1499
1500    /**
1501     * Return a random float between 0 and 0.9999
1502     *
1503     * @return float Random float between 0 and 0.9999
1504     */
1505    function frand()
1506    {
1507        return 0.0001 * mt_rand(0,9999);
1508    }
1509
1510    /**
1511     * Convert an html color code to a Securimage_Color
1512     * @param string $color
1513     * @param Securimage_Color $default The defalt color to use if $color is invalid
1514     */
1515    protected function initColor($color, $default)
1516    {
1517        if ($color == null) {
1518            return new Securimage_Color($default);
1519        } else if (is_string($color)) {
1520            try {
1521  

Large files files are truncated, but you can click here to view the full file