Changeset 26554
- Timestamp:
- Jan 9, 2014, 1:36:32 PM (10 years ago)
- Location:
- extensions/CryptograPHP
- Files:
-
- 4 added
- 1 deleted
- 12 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
extensions/CryptograPHP/admin.php
r26072 r26554 34 34 'height' => (int)$_POST['height'], 35 35 'perturbation' => (float)$_POST['perturbation'], 36 'image_bg_color' => $_POST['image_bg_color'], 36 'background' => $_POST['background'], 37 'bg_color' => $_POST['bg_color'], 38 'bg_image' => $_POST['bg_image'], 37 39 'code_length' => (int)$_POST['code_length'], 38 40 'text_color' => $_POST['text_color'], … … 50 52 51 53 $presets = array( 52 'bluenoise' => array('perturbation'=>0.25, 'image_bg_color'=>'ffffff', 'text_color'=>'0000ff', 'num_lines'=>2, 'line_color'=>'0000ff', 'noise_level'=>2, 'noise_color'=>'0000ff', 'ttf_file'=>'AlteHassGroteskB'), 53 'gray' => array('perturbation'=>1, 'image_bg_color'=>'ffffff', 'text_color'=>'8a8a8a', 'num_lines'=>2, 'line_color'=>'8a8a8a', 'noise_level'=>0.1, 'noise_color'=>'8a8a8a', 'ttf_file'=>'TopSecret'), 54 'xcolor' => array('perturbation'=>0.5, 'image_bg_color'=>'ffffff', 'text_color'=>'random', 'num_lines'=>1, 'line_color'=>'ffffff', 'noise_level'=>2, 'noise_color'=>'ffffff', 'ttf_file'=>'Dread'), 55 'pencil' => array('perturbation'=>0.8, 'image_bg_color'=>'9e9e9e', 'text_color'=>'363636', 'num_lines'=>0, 'line_color'=>'ffffff', 'noise_level'=>0, 'noise_color'=>'ffffff', 'ttf_file'=>'AllStar'), 54 'bluenoise' => array('perturbation'=>0.25, 'background'=>'color', 'bg_image'=>'', 'bg_color'=>'ffffff', 'text_color'=>'0000ff', 'num_lines'=>2, 'line_color'=>'0000ff', 'noise_level'=>2, 'noise_color'=>'0000ff', 'ttf_file'=>'AlteHassGroteskB'), 55 'gray' => array('perturbation'=>1, 'background'=>'color', 'bg_image'=>'', 'bg_color'=>'ffffff', 'text_color'=>'8a8a8a', 'num_lines'=>2, 'line_color'=>'8a8a8a', 'noise_level'=>0.1, 'noise_color'=>'8a8a8a', 'ttf_file'=>'TopSecret'), 56 'xcolor' => array('perturbation'=>0.5, 'background'=>'color', 'bg_image'=>'', 'bg_color'=>'ffffff', 'text_color'=>'random', 'num_lines'=>1, 'line_color'=>'ffffff', 'noise_level'=>2, 'noise_color'=>'ffffff', 'ttf_file'=>'Dread'), 57 'pencil' => array('perturbation'=>0.8, 'background'=>'color', 'bg_image'=>'', 'bg_color'=>'9e9e9e', 'text_color'=>'363636', 'num_lines'=>0, 'line_color'=>'ffffff', 'noise_level'=>0, 'noise_color'=>'ffffff', 'ttf_file'=>'AllStar'), 58 'ransom' => array('perturbation'=>0, 'background'=>'image', 'bg_image'=>'bg1.jpg', 'bg_color'=>'ffffff', 'text_color'=>'4a003a', 'num_lines'=>0, 'line_color'=>'ffffff', 'noise_level'=>0, 'noise_color'=>'ffffff', 'ttf_file'=>'ransom'), 56 59 ); 57 60 61 62 $template->assign(array( 63 'crypto' => $conf['cryptographp'], 64 'loaded' => $loaded, 65 'fonts' => list_fonts(CRYPTO_PATH.'securimage/fonts'), 66 'backgrounds' => list_backgrounds(CRYPTO_PATH.'securimage/backgrounds'), 67 'PRESETS' => $presets, 68 'CRYPTO_PATH' => CRYPTO_PATH, 69 )); 70 71 $template->set_filename('plugin_admin_content', realpath(CRYPTO_PATH . 'template/admin.tpl')); 72 $template->assign_var_from_handle('ADMIN_CONTENT', 'plugin_admin_content'); 73 74 75 58 76 function list_fonts($dir) 59 77 { … … 65 83 { 66 84 if ($file !== '.' && $file !== '..' && get_extension($file)=='ttf') 67 $fonts[] = get_filename_wo_extension($file); 85 { 86 $fonts[get_filename_wo_extension($file)] = $dir . '/' . $file; 87 } 68 88 } 69 89 … … 72 92 } 73 93 74 $template->assign(array( 75 'crypto' => $conf['cryptographp'], 76 'loaded' => $loaded, 77 'fonts' => list_fonts(CRYPTO_PATH.'securimage/fonts'), 78 'PRESETS' => $presets, 79 'CRYPTO_PATH' => CRYPTO_PATH, 80 )); 81 82 $template->set_filename('plugin_admin_content', dirname(__FILE__).'/template/admin.tpl'); 83 $template->assign_var_from_handle('ADMIN_CONTENT', 'plugin_admin_content'); 94 function list_backgrounds($dir) 95 { 96 $dir = rtrim($dir, '/'); 97 $dh = opendir($dir); 98 $backgrounds = array(); 99 100 while (($file = readdir($dh)) !== false ) 101 { 102 if ($file !== '.' && $file !== '..') 103 { 104 $ext = get_extension($file); 105 if ($ext=='jpg' || $ext=='png' || $ext=='jpeg' || $ext=='gif') 106 { 107 $backgrounds[$file] = $dir . '/' . $file; 108 } 109 } 110 } 111 112 closedir($dh); 113 return $backgrounds; 114 } -
extensions/CryptograPHP/language/en_UK/plugin.lang.php
r26041 r26554 5 5 $lang['Solve equation'] = 'Solve equation'; 6 6 $lang['Button color'] = 'Button color'; 7 8 7 $lang['Comments action'] = 'Comments action'; 9 8 $lang['Moderate'] = 'Moderate'; … … 21 20 $lang['Contact form'] = 'Contact form'; 22 21 $lang['Guestbook'] = 'Guestbook'; 23 24 22 $lang['Perturbation'] = 'Perturbation'; 25 23 $lang['range:'] = 'range:'; … … 33 31 $lang['Font'] = 'Font'; 34 32 $lang['Preview'] = 'Preview'; 33 $lang['Background'] = 'Background'; 34 $lang['Background image'] = 'Background image'; 35 $lang['Color'] = 'Color'; 36 $lang['Image'] = 'Image'; 35 37 $lang['Tip: type "random" on a color field to have a random color'] = 'Tip: type "random" on a color field to have a random color'; 36 38 $lang['We detected that EasyCaptcha plugin is available on your gallery. Both plugins can be used at the same time, but you should not under any circumstances activate both of them on the same page.'] = 'We detected that EasyCaptcha plugin is available in your gallery. Both plugins can be used at the same time, but you should not under any circumstances activate both of them on the same page.'; -
extensions/CryptograPHP/language/fr_FR/plugin.lang.php
r26041 r26554 5 5 $lang['Solve equation'] = 'Resolvez l\'équation'; 6 6 $lang['Button color'] = 'Couleur du bouton'; 7 8 7 $lang['Comments action'] = 'Action pour les commentaires'; 9 8 $lang['Moderate'] = 'Modérer'; … … 21 20 $lang['Contact form'] = 'Formulaire de contact'; 22 21 $lang['Guestbook'] = 'Livre d\'or'; 23 24 22 $lang['Perturbation'] = 'Perturbation'; 25 23 $lang['range:'] = 'plage:'; … … 33 31 $lang['Font'] = 'Police'; 34 32 $lang['Preview'] = 'Prévisualisation'; 33 $lang['Background'] = 'Fond'; 34 $lang['Background image'] = 'Image de fond'; 35 $lang['Color'] = 'Couleur'; 36 $lang['Image'] = 'Image'; 35 37 $lang['Tip: type "random" on a color field to have a random color'] = 'Astuce: inscrivez "random" dans un champs de couleur pour avoir une couleur aléatoire'; 36 38 $lang['We detected that EasyCaptcha plugin is available on your gallery. Both plugins can be used at the same time, but you should not under any circumstances activate both of them on the same page.'] = 'Nous avons détecté que EasyCaptcha est activé sur votre galerie. Les deux plugins peuvent fonctionner en même temps, mais sous aucun prétexte ils ne doivent être activés sur les mêmes pages.'; -
extensions/CryptograPHP/maintain.inc.php
r26072 r26554 32 32 'width' => 180, 33 33 'height' => 70, 34 'perturbation' => 1, 35 'image_bg_color' => 'ffffff', 34 'perturbation' => 1, 35 'background' => 'color', 36 'bg_color' => 'ffffff', 37 'bg_image' => '', 36 38 'text_color' => '8a8a8a', 37 39 'num_lines' => 2, … … 64 66 $old_conf['button_color'] = 'dark'; 65 67 } 68 if (!isset($old_conf['background'])) 69 { 70 $old_conf['background'] = 'color'; 71 $old_conf['bg_color'] = $old_conf['image_bg_color']; 72 $old_conf['bg_image'] = ''; 73 unset($old_conf['image_bg_color']); 74 } 66 75 67 76 $conf['cryptographp'] = serialize($old_conf); -
extensions/CryptograPHP/securimage/README.txt
r12617 r26554 3 3 Securimage - A PHP class for creating captcha images and audio with many options. 4 4 5 VERSION: 3. 05 VERSION: 3.5.1 6 6 7 7 AUTHOR: … … 23 23 GD 2.0 24 24 FreeType (Required, for TTF fonts) 25 PDO (if using Sqlite, MySQL, or PostgreSQL) 25 26 26 27 SYNOPSIS: … … 53 54 54 55 COPYRIGHT: 55 Copyright (c) 201 1Drew Phillips56 Copyright (c) 2013 Drew Phillips 56 57 All rights reserved. 57 58 … … 78 79 79 80 ----------------------------------------------------------------------------- 80 Flash code created for Securimage by Mario Romero (animario@hotmail.com) 81 The WavFile.php class used in Securimage by Drew Phillips and Paul Voegler is 82 used under the BSD License. See WavFile.php for details. 83 Many thanks to Paul Voegler (http://www.voegler.eu/) for contributing to 84 Securimage. 85 86 ----------------------------------------------------------------------------- 87 Flash code created for Securimage by Age Bosma & Mario Romero (animario@hotmail.com) 81 88 Many thanks for releasing this to the project! 82 89 … … 107 114 yann@lecoroller.com 108 115 116 ------------------------------------------------------------------------------- 117 Portions of securimage_play.swf use the PopForge flash library for playing audio 118 119 /** 120 * Copyright(C) 2007 Andre Michelle and Joa Ebert 121 * 122 * PopForge is an ActionScript3 code sandbox developed by Andre Michelle and Joa Ebert 123 * http://sandbox.popforge.de 124 * 125 * PopforgeAS3Audio is free software; you can redistribute it and/or modify 126 * it under the terms of the GNU General Public License as published by 127 * the Free Software Foundation; either version 3 of the License, or 128 * (at your option) any later version. 129 * 130 * PopforgeAS3Audio is distributed in the hope that it will be useful, 131 * but WITHOUT ANY WARRANTY; without even the implied warranty of 132 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 133 * GNU General Public License for more details. 134 * 135 * You should have received a copy of the GNU General Public License 136 * along with this program. If not, see <http://www.gnu.org/licenses/> 137 */ 138 139 ------------------------------------------------------------------------------- 140 Some graphics used are from the Humility Icon Pack by WorLord 141 142 License: GNU/GPL (http://findicons.com/pack/1723/humility) 143 http://findicons.com/icon/192558/gnome_volume_control 144 http://findicons.com/icon/192562/gtk_refresh 145 146 ------------------------------------------------------------------------------- 147 Background noise sound files are from SoundJay.com 148 http://www.soundjay.com/tos.html 149 150 All sound effects on this website are created by us and protected under 151 the copyright laws, international treaty provisions and other applicable 152 laws. By downloading sounds, music or any material from this site implies 153 that you have read and accepted these terms and conditions: 154 155 Sound Effects 156 You are allowed to use the sounds free of charge and royalty free in your 157 projects (such as films, videos, games, presentations, animations, stage 158 plays, radio plays, audio books, apps) be it for commercial or 159 non-commercial purposes. 160 161 But you are NOT allowed to 162 - post the sounds (as sound effects or ringtones) on any website for 163 others to download, copy or use 164 - use them as a raw material to create sound effects or ringtones that 165 you will sell, distribute or offer for downloading 166 - sell, re-sell, license or re-license the sounds (as individual sound 167 effects or as a sound effects library) to anyone else 168 - claim the sounds as yours 169 - link directly to individual sound files 170 - distribute the sounds in apps or computer programs that are clearly 171 sound related in nature (such as sound machine, sound effect 172 generator, ringtone maker, funny sounds app, sound therapy app, etc.) 173 or in apps or computer programs that use the sounds as the program's 174 sound resource library for other people's use (such as animation 175 creator, digital book creator, song maker software, etc.). If you are 176 developing such computer programs, contact us for licensing options. 177 178 If you use the sound effects, please consider giving us a credit and 179 linking back to us but it's not required. 180 181 -
extensions/CryptograPHP/securimage/securimage.php
r12617 r26554 1 1 <?php 2 3 // error_reporting(E_ALL); ini_set('display_errors', 1); // uncomment this line for debugging 4 2 5 /** 3 * Project: Securimage: A PHP class for creating and managing form CAPTCHA images 4 * File: securimage.php 6 * Project: Securimage: A PHP class for creating and managing form CAPTCHA images<br /> 7 * File: securimage.php<br /> 5 8 * 6 * Copyright (c) 201 1, Drew Phillips9 * Copyright (c) 2013, Drew Phillips 7 10 * All rights reserved. 8 * 11 * 9 12 * Redistribution and use in source and binary forms, with or without modification, 10 13 * are permitted provided that the following conditions are met: 11 * 14 * 12 15 * - Redistributions of source code must retain the above copyright notice, 13 16 * this list of conditions and the following disclaimer. … … 15 18 * this list of conditions and the following disclaimer in the documentation 16 19 * and/or other materials provided with the distribution. 17 * 20 * 18 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE … … 29 32 * 30 33 * Any modifications to the library should be indicated clearly in the source code 31 * to inform users that the changes are not a part of the original software. 34 * to inform users that the changes are not a part of the original software.<br /><br /> 32 35 * 33 * If you found this script useful, please take a quick moment to rate it. 36 * If you found this script useful, please take a quick moment to rate it.<br /> 34 37 * http://www.hotscripts.com/rate/49400.html Thanks. 35 38 * … … 37 40 * @link http://www.phpcaptcha.org/latest.zip Download Latest Version 38 41 * @link http://www.phpcaptcha.org/Securimage_Docs/ Online Documentation 39 * @copyright 201 1Drew Phillips42 * @copyright 2013 Drew Phillips 40 43 * @author Drew Phillips <drew@drew-phillips.com> 41 * @version 3. 0 (October 2011)44 * @version 3.5.1 (June 21, 2013) 42 45 * @package Securimage 43 46 * … … 46 49 /** 47 50 ChangeLog 48 51 52 3.5.1 53 - Fix XSS vulnerability in example_form.php (discovered by Gjoko Krstic - <gjoko@zeroscience.mk>) 54 55 3.5 56 - Release new version 57 - MB string support for charlist 58 - Modify audio file path to use language directories 59 - Changed default captcha appearance 60 61 3.2RC4 62 - Add MySQL, PostgreSQL, and SQLite3 support for database storage 63 - Deprecate "use_sqlite_db" option and remove SQLite2/sqlite_* functions 64 - Add new captcha type that displays 2 dictionary words on one image 65 - Update examples 66 67 3.2RC3 68 - Fix canSendHeaders() check which was breaking if a PHP startup error was issued 69 70 3.2RC2 71 - Add error handler (https://github.com/dapphp/securimage/issues/15) 72 - Fix flash examples to use the correct value name for audio parameter 73 74 3.2RC1 75 - New audio captcha code. Faster, fully dynamic audio, full WAV support 76 (Paul Voegler, Drew Phillips) <http://voegler.eu/pub/audio> 77 - New Flash audio streaming button. User defined image and size supported 78 - Additional options for customizing captcha (noise_level, send_headers, 79 no_exit, no_session, display_value 80 - Add captcha ID support. Uses sqlite and unique captcha IDs to track captchas, 81 no session used 82 - Add static methods for creating and validating captcha by ID 83 - Automatic clearing of old codes from SQLite database 84 85 3.0.3Beta 86 - Add improved mixing function to WavFile class (Paul Voegler) 87 - Improve performance and security of captcha audio (Paul Voegler, Drew Phillips) 88 - Add option to use random file as background noise in captcha audio 89 - Add new securimage options for audio files 90 91 3.0.2Beta 92 - Fix issue with session variables when upgrading from 2.0 - 3.0 93 - Improve audio captcha, switch to use WavFile class, make mathematical captcha audio work 94 95 3.0.1 96 - Bugfix: removed use of deprecated variable in addSignature method that would cause errors with display_errors on 97 49 98 3.0 50 99 - Rewrite class using PHP5 OOP … … 78 127 - Audio output is mp3 format by default 79 128 - Change font to AlteHaasGrotesk by yann le coroller 80 - Some code cleanup 129 - Some code cleanup 81 130 82 131 1.0.4 (unreleased) … … 108 157 * Securimage CAPTCHA Class. 109 158 * 110 * @version 3. 0159 * @version 3.5 111 160 * @package Securimage 112 161 * @subpackage classes … … 116 165 class Securimage 117 166 { 118 119 120 121 167 // All of the public variables below are securimage options 168 // They can be passed as an array to the Securimage constructor, set below, 169 // or set from securimage_show.php and securimage_play.php 170 122 171 /** 123 172 * Renders captcha as a JPEG image … … 135 184 */ 136 185 const SI_IMAGE_GIF = 3; 137 186 138 187 /** 139 188 * Create a normal alphanumeric captcha … … 146 195 */ 147 196 const SI_CAPTCHA_MATHEMATIC = 1; 148 197 /** 198 * Create a word based captcha using 2 words 199 * @var int 200 */ 201 const SI_CAPTCHA_WORDS = 2; 202 203 /** 204 * MySQL option identifier for database storage option 205 * 206 * @var string 207 */ 208 const SI_DRIVER_MYSQL = 'mysql'; 209 210 /** 211 * PostgreSQL option identifier for database storage option 212 * 213 * @var string 214 */ 215 const SI_DRIVER_PGSQL = 'pgsql'; 216 217 /** 218 * SQLite option identifier for database storage option 219 * 220 * @var string 221 */ 222 const SI_DRIVER_SQLITE3 = 'sqlite'; 223 224 /*%*********************************************************************%*/ 225 // Properties 226 149 227 /** 150 228 * The width of the captcha image … … 180 258 /** 181 259 * The color of the noise that is drawn 182 * @var Securimage_Color 260 * @var Securimage_Color 183 261 */ 184 262 public $noise_color = '#707070'; 185 263 186 264 /** 187 265 * How transparent to make the text 0 = completely opaque, 100 = invisible 188 266 * @var int 189 267 */ 190 public $text_transparency_percentage = 50;268 public $text_transparency_percentage = 20; 191 269 /** 192 270 * Whether or not to draw the text transparently, true = use transparency, false = no transparency 193 271 * @var bool 194 272 */ 195 public $use_transparent_text = false;196 273 public $use_transparent_text = true; 274 197 275 /** 198 276 * The length of the captcha code … … 215 293 */ 216 294 public $expiry_time = 900; 217 295 218 296 /** 219 297 * The session name securimage should use, only set this if your application uses a custom session name … … 222 300 */ 223 301 public $session_name = null; 224 302 225 303 /** 226 304 * true to use the wordlist file, false to generate random captcha codes … … 233 311 * @var double 234 312 */ 235 public $perturbation = 0. 75;313 public $perturbation = 0.85; 236 314 /** 237 315 * How many lines to draw over the captcha code to increase security 238 316 * @var int 239 317 */ 240 public $num_lines = 8;318 public $num_lines = 5; 241 319 /** 242 320 * The level of noise (random dots) to place on the image, 0-10 243 321 * @var int 244 322 */ 245 public $noise_level = 0;246 323 public $noise_level = 2; 324 247 325 /** 248 326 * The signature text to draw on the bottom corner of the image … … 260 338 */ 261 339 public $signature_font; 262 263 /** 340 341 /** 342 * DO NOT USE!!! 264 343 * Use an SQLite database to store data (for users that do not support cookies) 265 344 * @var bool 345 * @see Securimage::$use_sqlite_db 346 * @deprecated 3.2RC4 266 347 */ 267 348 public $use_sqlite_db = false; 268 349 350 /** 351 * Use a database backend for code storage. 352 * Provides a fallback to users with cookies disabled. 353 * Required when using captcha IDs. 354 * 355 * @see Securimage::$database_driver 356 * @var bool 357 */ 358 public $use_database = false; 359 360 /** 361 * Database driver to use for database support. 362 * Allowable values: 'mysql', 'pgsql', 'sqlite'. 363 * Default: sqlite 364 * 365 * @var string 366 */ 367 public $database_driver = self::SI_DRIVER_SQLITE3; 368 369 /** 370 * Database host to connect to when using mysql or postgres 371 * On Linux use "localhost" for Unix domain socket, otherwise uses TCP/IP 372 * Does not apply to SQLite 373 * 374 * @var string 375 */ 376 public $database_host = 'localhost'; 377 378 /** 379 * Database username for connection (mysql, postgres only) 380 * Default is an empty string 381 * 382 * @var string 383 */ 384 public $database_user = ''; 385 386 /** 387 * Database password for connection (mysql, postgres only) 388 * Default is empty string 389 * 390 * @var string 391 */ 392 public $database_pass = ''; 393 394 /** 395 * Name of the database to select (mysql, postgres only) 396 * 397 * @see Securimage::$database_file for SQLite 398 * @var string 399 */ 400 public $database_name = ''; 401 402 /** 403 * Database table where captcha codes are stored 404 * Note: Securimage will attempt to create this table for you if it does 405 * not exist. If the table cannot be created, an E_USER_WARNING is emitted. 406 * 407 * @var string 408 */ 409 public $database_table = 'captcha_codes'; 410 411 /** 412 * Fully qualified path to the database file when using SQLite3. 413 * This value is only used when $database_driver == sqlite3 and does 414 * not apply when no database is used, or when using MySQL or PostgreSQL. 415 * 416 * @var string 417 */ 418 public $database_file; 419 269 420 /** 270 421 * The type of captcha to create, either alphanumeric, or a math problem<br /> … … 272 423 * @var int 273 424 */ 274 public $captcha_type = self::SI_CAPTCHA_STRING; 275 425 public $captcha_type = self::SI_CAPTCHA_STRING; // or self::SI_CAPTCHA_MATHEMATIC; 426 276 427 /** 277 428 * The captcha namespace, use this if you have multiple forms on a single page, blank if you do not use multiple forms on one page … … 281 432 * // in securimage_show.php (create one show script for each form) 282 433 * $img->namespace = 'contact_form'; 283 * 434 * 284 435 * // in form validator 285 436 * $img->namespace = 'contact_form'; … … 290 441 */ 291 442 public $namespace; 292 443 293 444 /** 294 445 * The font file to use to draw the captcha code, leave blank for default font AHGBold.ttf … … 308 459 /** 309 460 * The path to the SQLite database file to use, if $use_sqlite_database = true, should be chmod 666 461 * @deprecated 3.2RC4 310 462 * @var string 311 463 */ … … 315 467 * @var string 316 468 * <code> 317 * $img->audio_path = '/home/yoursite/public_html/securimage/audio/ ';469 * $img->audio_path = '/home/yoursite/public_html/securimage/audio/en/'; 318 470 * </code> 319 471 */ 320 472 public $audio_path; 321 322 323 473 /** 474 * The path to the directory containing audio files that will be selected 475 * randomly and mixed with the captcha audio. 476 * 477 * @var string 478 */ 479 public $audio_noise_path; 480 /** 481 * Whether or not to mix background noise files into captcha audio (true = mix, false = no) 482 * Mixing random background audio with noise can help improve security of audio captcha. 483 * Default: securimage/audio/noise 484 * 485 * @since 3.0.3 486 * @see Securimage::$audio_noise_path 487 * @var bool 488 */ 489 public $audio_use_noise; 490 /** 491 * The method and threshold (or gain factor) used to normalize the mixing with background noise. 492 * See http://www.voegler.eu/pub/audio/ for more information. 493 * 494 * Valid: <ul> 495 * <li> >= 1 - Normalize by multiplying by the threshold (boost - positive gain). <br /> 496 * A value of 1 in effect means no normalization (and results in clipping). </li> 497 * <li> <= -1 - Normalize by dividing by the the absolute value of threshold (attenuate - negative gain). <br /> 498 * A factor of 2 (-2) is about 6dB reduction in volume.</li> 499 * <li> [0, 1) - (open inverval - not including 1) - The threshold 500 * above which amplitudes are comressed logarithmically. <br /> 501 * e.g. 0.6 to leave amplitudes up to 60% "as is" and compress above. </li> 502 * <li> (-1, 0) - (open inverval - not including -1 and 0) - The threshold 503 * above which amplitudes are comressed linearly. <br /> 504 * e.g. -0.6 to leave amplitudes up to 60% "as is" and compress above. </li></ul> 505 * 506 * Default: 0.6 507 * 508 * @since 3.0.4 509 * @var float 510 */ 511 public $audio_mix_normalization = 0.6; 512 /** 513 * Whether or not to degrade audio by introducing random noise (improves security of audio captcha) 514 * Default: true 515 * 516 * @since 3.0.3 517 * @var bool 518 */ 519 public $degrade_audio; 520 /** 521 * Minimum delay to insert between captcha audio letters in milliseconds 522 * 523 * @since 3.0.3 524 * @var float 525 */ 526 public $audio_gap_min = 0; 527 /** 528 * Maximum delay to insert between captcha audio letters in milliseconds 529 * 530 * @since 3.0.3 531 * @var float 532 */ 533 public $audio_gap_max = 600; 534 535 /** 536 * Captcha ID if using static captcha 537 * @var string Unique captcha id 538 */ 539 protected static $_captchaId = null; 540 324 541 protected $im; 325 542 protected $tmpimg; 326 543 protected $bgimg; 327 544 protected $iscale = 5; 328 329 protected $securimage_path = null; 330 545 546 public $securimage_path = null; 547 548 /** 549 * The captcha challenge value (either the case-sensitive/insensitive word captcha, or the solution to the math captcha) 550 * 551 * @var string Captcha challenge value 552 */ 331 553 protected $code; 554 555 /** 556 * The display value of the captcha to draw on the image (the word captcha, or the math equation to present to the user) 557 * 558 * @var string Captcha display value to draw on the image 559 */ 332 560 protected $code_display; 333 561 562 /** 563 * A value that can be passed to the constructor that can be used to generate a captcha image with a given value 564 * This value does not get stored in the session or database and is only used when calling Securimage::show(). 565 * If a display_value was passed to the constructor and the captcha image is generated, the display_value will be used 566 * as the string to draw on the captcha image. Used only if captcha codes are generated and managed by a 3rd party app/library 567 * 568 * @var string Captcha code value to display on the image 569 */ 570 public $display_value; 571 572 /** 573 * Captcha code supplied by user [set from Securimage::check()] 574 * 575 * @var string 576 */ 334 577 protected $captcha_code; 335 protected $sqlite_handle; 336 578 579 /** 580 * Flag that can be specified telling securimage not to call exit after generating a captcha image or audio file 581 * 582 * @var bool If true, script will not terminate; if false script will terminate (default) 583 */ 584 protected $no_exit; 585 586 /** 587 * Flag indicating whether or not a PHP session should be started and used 588 * 589 * @var bool If true, no session will be started; if false, session will be started and used to store data (default) 590 */ 591 protected $no_session; 592 593 /** 594 * Flag indicating whether or not HTTP headers will be sent when outputting captcha image/audio 595 * 596 * @var bool If true (default) headers will be sent, if false, no headers are sent 597 */ 598 protected $send_headers; 599 600 /** 601 * PDO connection when a database is used 602 * 603 * @var resource 604 */ 605 protected $pdo_conn; 606 607 // gd color resources that are allocated for drawing the image 337 608 protected $gdbgcolor; 338 609 protected $gdtextcolor; 339 610 protected $gdlinecolor; 340 611 protected $gdsignaturecolor; 341 612 342 613 /** 343 614 * Create a new securimage object, pass options to set in the constructor.<br /> … … 352 623 * 'font_file' => Securimage::getPath() . '/custom.ttf' 353 624 * ); 354 * 625 * 355 626 * $img = new Securimage($options); 356 627 * </code> … … 359 630 { 360 631 $this->securimage_path = dirname(__FILE__); 361 632 362 633 if (is_array($options) && sizeof($options) > 0) { 363 634 foreach($options as $prop => $val) { 364 $this->$prop = $val; 635 if ($prop == 'captchaId') { 636 Securimage::$_captchaId = $val; 637 $this->use_database = true; 638 } else if ($prop == 'use_sqlite_db') { 639 trigger_error("The use_sqlite_db option is deprecated, use 'use_database' instead", E_USER_NOTICE); 640 } else { 641 $this->$prop = $val; 642 } 365 643 } 366 644 } … … 372 650 $this->signature_color = $this->initColor($this->signature_color, '#616161'); 373 651 374 if ( $this->ttf_file == null) {652 if (is_null($this->ttf_file)) { 375 653 $this->ttf_file = $this->securimage_path . '/AHGBold.ttf'; 376 654 } 377 655 378 656 $this->signature_font = $this->ttf_file; 379 380 if ( $this->wordlist_file == null) {657 658 if (is_null($this->wordlist_file)) { 381 659 $this->wordlist_file = $this->securimage_path . '/words/words.txt'; 382 660 } 383 384 if ($this->sqlite_database == null) { 385 $this->sqlite_database = $this->securimage_path . '/database/securimage.sqlite'; 386 } 387 388 if ($this->audio_path == null) { 389 $this->audio_path = $this->securimage_path . '/audio/'; 390 } 391 392 if ($this->code_length == null || $this->code_length < 1) { 661 662 if (is_null($this->database_file)) { 663 $this->database_file = $this->securimage_path . '/database/securimage.sq3'; 664 } 665 666 if (is_null($this->audio_path)) { 667 $this->audio_path = $this->securimage_path . '/audio/en/'; 668 } 669 670 if (is_null($this->audio_noise_path)) { 671 $this->audio_noise_path = $this->securimage_path . '/audio/noise/'; 672 } 673 674 if (is_null($this->audio_use_noise)) { 675 $this->audio_use_noise = true; 676 } 677 678 if (is_null($this->degrade_audio)) { 679 $this->degrade_audio = true; 680 } 681 682 if (is_null($this->code_length) || (int)$this->code_length < 1) { 393 683 $this->code_length = 6; 394 684 } 395 396 if ( $this->perturbation == null|| !is_numeric($this->perturbation)) {685 686 if (is_null($this->perturbation) || !is_numeric($this->perturbation)) { 397 687 $this->perturbation = 0.75; 398 688 } 399 400 if ( $this->namespace == null|| !is_string($this->namespace)) {689 690 if (is_null($this->namespace) || !is_string($this->namespace)) { 401 691 $this->namespace = 'default'; 402 692 } 403 693 404 // Initialize session or attach to existing 405 if ( session_id() == '' ) { // no session has been started yet, which is needed for validation 406 if ($this->session_name != null && trim($this->session_name) != '') { 407 session_name(trim($this->session_name)); // set session name if provided 408 } 409 session_start(); 410 } 411 } 412 694 if (is_null($this->no_exit)) { 695 $this->no_exit = false; 696 } 697 698 if (is_null($this->no_session)) { 699 $this->no_session = false; 700 } 701 702 if (is_null($this->send_headers)) { 703 $this->send_headers = true; 704 } 705 706 if ($this->no_session != true) { 707 // Initialize session or attach to existing 708 if ( session_id() == '' ) { // no session has been started yet, which is needed for validation 709 if (!is_null($this->session_name) && trim($this->session_name) != '') { 710 session_name(trim($this->session_name)); // set session name if provided 711 } 712 session_start(); 713 } 714 } 715 } 716 413 717 /** 414 718 * Return the absolute path to the Securimage directory … … 419 723 return dirname(__FILE__); 420 724 } 421 725 726 /** 727 * Generate a new captcha ID or retrieve the current ID 728 * 729 * @param $new bool If true, generates a new challenge and returns and ID 730 * @param $options array Additional options to be passed to Securimage. 731 * Must include database options if not set directly in securimage.php 732 * 733 * @return null|string Returns null if no captcha id set and new was false, or string captcha ID 734 */ 735 public static function getCaptchaId($new = true, array $options = array()) 736 { 737 if (is_null($new) || (bool)$new == true) { 738 $id = sha1(uniqid($_SERVER['REMOTE_ADDR'], true)); 739 $opts = array('no_session' => true, 740 'use_database' => true); 741 if (sizeof($options) > 0) $opts = array_merge($options, $opts); 742 $si = new self($opts); 743 Securimage::$_captchaId = $id; 744 $si->createCode(); 745 746 return $id; 747 } else { 748 return Securimage::$_captchaId; 749 } 750 } 751 752 /** 753 * Validate a captcha code input against a captcha ID 754 * 755 * @param string $id The captcha ID to check 756 * @param string $value The captcha value supplied by the user 757 * @param array $options Array of options to construct Securimage with. 758 * Options must include database options if they are not set in securimage.php 759 * 760 * @see Securimage::$database_driver 761 * @return bool true if the code was valid for the given captcha ID, false if not or if database failed to open 762 */ 763 public static function checkByCaptchaId($id, $value, array $options = array()) 764 { 765 $opts = array('captchaId' => $id, 766 'no_session' => true, 767 'use_database' => true); 768 769 if (sizeof($options) > 0) $opts = array_merge($options, $opts); 770 771 $si = new self($opts); 772 773 if ($si->openDatabase()) { 774 $code = $si->getCodeFromDatabase(); 775 776 if (is_array($code)) { 777 $si->code = $code['code']; 778 $si->code_display = $code['code_disp']; 779 } 780 781 if ($si->check($value)) { 782 $si->clearCodeFromDatabase(); 783 784 return true; 785 } else { 786 return false; 787 } 788 } else { 789 return false; 790 } 791 } 792 793 422 794 /** 423 795 * Used to serve a captcha image to the browser 424 796 * @param string $background_image The path to the background image to use 425 * <code> 797 * <code> 426 798 * $img = new Securimage(); 427 799 * $img->code_length = 6; 428 800 * $img->num_lines = 5; 429 801 * $img->noise_level = 5; 430 * 802 * 431 803 * $img->show(); // sends the image to browser 432 804 * exit; … … 435 807 public function show($background_image = '') 436 808 { 809 set_error_handler(array(&$this, 'errorHandler')); 810 437 811 if($background_image != '' && is_readable($background_image)) { 438 812 $this->bgimg = $background_image; … … 441 815 $this->doImage(); 442 816 } 443 817 444 818 /** 445 819 * Check a submitted code against the stored value … … 461 835 return $this->correct_code; 462 836 } 463 837 464 838 /** 465 839 * Output a wav file of the captcha code to the browser 466 * 840 * 467 841 * <code> 468 842 * $img = new Securimage(); … … 473 847 public function outputAudioFile() 474 848 { 475 $ext = 'wav'; // force wav - mp3 is insecure 476 477 header("Content-Disposition: attachment; filename=\"securimage_audio.{$ext}\""); 478 header('Cache-Control: no-store, no-cache, must-revalidate'); 479 header('Expires: Sun, 1 Jan 2000 12:00:00 GMT'); 480 header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT'); 481 header('Content-type: audio/x-wav'); 482 483 $audio = $this->getAudibleCode($ext); 484 485 header('Content-Length: ' . strlen($audio)); 486 487 echo $audio; 488 exit; 489 } 490 849 set_error_handler(array(&$this, 'errorHandler')); 850 851 require_once dirname(__FILE__) . '/WavFile.php'; 852 853 try { 854 $audio = $this->getAudibleCode(); 855 } catch (Exception $ex) { 856 if (($fp = @fopen(dirname(__FILE__) . '/si.error_log', 'a+')) !== false) { 857 fwrite($fp, date('Y-m-d H:i:s') . ': Securimage audio error "' . $ex->getMessage() . '"' . "\n"); 858 fclose($fp); 859 } 860 861 $audio = $this->audioError(); 862 } 863 864 if ($this->canSendHeaders() || $this->send_headers == false) { 865 if ($this->send_headers) { 866 $uniq = md5(uniqid(microtime())); 867 header("Content-Disposition: attachment; filename=\"securimage_audio-{$uniq}.wav\""); 868 header('Cache-Control: no-store, no-cache, must-revalidate'); 869 header('Expires: Sun, 1 Jan 2000 12:00:00 GMT'); 870 header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT'); 871 header('Content-type: audio/x-wav'); 872 873 if (extension_loaded('zlib')) { 874 ini_set('zlib.output_compression', true); // compress output if supported by browser 875 } else { 876 header('Content-Length: ' . strlen($audio)); 877 } 878 } 879 880 echo $audio; 881 } else { 882 echo '<hr /><strong>' 883 .'Failed to generate audio file, content has already been ' 884 .'output.<br />This is most likely due to misconfiguration or ' 885 .'a PHP error was sent to the browser.</strong>'; 886 } 887 888 restore_error_handler(); 889 890 if (!$this->no_exit) exit; 891 } 892 893 /** 894 * Return the code from the session or sqlite database if used. If none exists yet, an empty string is returned 895 * 896 * @param $array bool True to receive an array containing the code and properties 897 * @return array|string Array if $array = true, otherwise a string containing the code 898 */ 899 public function getCode($array = false, $returnExisting = false) 900 { 901 $code = ''; 902 $time = 0; 903 $disp = 'error'; 904 905 if ($returnExisting && strlen($this->code) > 0) { 906 if ($array) { 907 return array('code' => $this->code, 908 'display' => $this->code_display, 909 'code_display' => $this->code_display, 910 'time' => 0); 911 } else { 912 return $this->code; 913 } 914 } 915 916 if ($this->no_session != true) { 917 if (isset($_SESSION['securimage_code_value'][$this->namespace]) && 918 trim($_SESSION['securimage_code_value'][$this->namespace]) != '') { 919 if ($this->isCodeExpired( 920 $_SESSION['securimage_code_ctime'][$this->namespace]) == false) { 921 $code = $_SESSION['securimage_code_value'][$this->namespace]; 922 $time = $_SESSION['securimage_code_ctime'][$this->namespace]; 923 $disp = $_SESSION['securimage_code_disp'] [$this->namespace]; 924 } 925 } 926 } 927 928 if (empty($code) && $this->use_database) { 929 // no code in session - may mean user has cookies turned off 930 $this->openDatabase(); 931 $code = $this->getCodeFromDatabase(); 932 } else { /* no code stored in session or sqlite database, validation will fail */ } 933 934 if ($array == true) { 935 return array('code' => $code, 'ctime' => $time, 'display' => $disp); 936 } else { 937 return $code; 938 } 939 } 940 491 941 /** 492 942 * The main image drawing routing, responsible for constructing the entire image and serving it … … 499 949 $imagecreate = 'imagecreate'; 500 950 } 501 951 502 952 $this->im = $imagecreate($this->image_width, $this->image_height); 503 953 $this->tmpimg = $imagecreate($this->image_width * $this->iscale, $this->image_height * $this->iscale); 504 954 505 955 $this->allocateColors(); 506 956 imagepalettecopy($this->tmpimg, $this->im); … … 508 958 $this->setBackground(); 509 959 510 $this->createCode(); 511 512 $this->drawWord(); 960 $code = ''; 961 962 if ($this->getCaptchaId(false) !== null) { 963 // a captcha Id was supplied 964 965 // check to see if a display_value for the captcha image was set 966 if (is_string($this->display_value) && strlen($this->display_value) > 0) { 967 $this->code_display = $this->display_value; 968 $this->code = ($this->case_sensitive) ? 969 $this->display_value : 970 strtolower($this->display_value); 971 $code = $this->code; 972 } else if ($this->openDatabase()) { 973 // no display_value, check the database for existing captchaId 974 $code = $this->getCodeFromDatabase(); 975 976 // got back a result from the database with a valid code for captchaId 977 if (is_array($code)) { 978 $this->code = $code['code']; 979 $this->code_display = $code['code_disp']; 980 $code = $code['code']; 981 } 982 } 983 } 984 985 if ($code == '') { 986 // if the code was not set using display_value or was not found in 987 // the database, create a new code 988 $this->createCode(); 989 } 513 990 514 991 if ($this->noise_level > 0) { 515 992 $this->drawNoise(); 516 993 } 517 994 995 $this->drawWord(); 996 518 997 if ($this->perturbation > 0 && is_readable($this->ttf_file)) { 519 998 $this->distortedCopy(); … … 530 1009 $this->output(); 531 1010 } 532 1011 533 1012 /** 534 1013 * Allocate the colors to be used for the image … … 541 1020 $this->image_bg_color->g, 542 1021 $this->image_bg_color->b); 543 1022 544 1023 $alpha = intval($this->text_transparency_percentage / 100 * 127); 545 1024 546 1025 if ($this->use_transparent_text == true) { 547 1026 $this->gdtextcolor = imagecolorallocatealpha($this->im, … … 574 1053 $this->noise_color->b); 575 1054 } 576 1055 577 1056 $this->gdsignaturecolor = imagecolorallocate($this->im, 578 1057 $this->signature_color->r, … … 581 1060 582 1061 } 583 1062 584 1063 /** 585 1064 * The the background color, or background image to be used … … 594 1073 $this->image_width * $this->iscale, $this->image_height * $this->iscale, 595 1074 $this->gdbgcolor); 596 1075 597 1076 if ($this->bgimg == '') { 598 if ($this->background_directory != null && 1077 if ($this->background_directory != null && 599 1078 is_dir($this->background_directory) && 600 1079 is_readable($this->background_directory)) … … 606 1085 } 607 1086 } 608 1087 609 1088 if ($this->bgimg == '') { 610 1089 return; … … 612 1091 613 1092 $dat = @getimagesize($this->bgimg); 614 if($dat == false) { 1093 if($dat == false) { 615 1094 return; 616 1095 } … … 629 1108 imagesx($newim), imagesy($newim)); 630 1109 } 631 1110 632 1111 /** 633 1112 * Scan the directory for a background image to use … … 645 1124 646 1125 if (sizeof($images) > 0) { 647 return rtrim($this->background_directory, '/') . '/' . $images[ rand(0, sizeof($images)-1)];1126 return rtrim($this->background_directory, '/') . '/' . $images[mt_rand(0, sizeof($images)-1)]; 648 1127 } 649 1128 } … … 651 1130 return false; 652 1131 } 653 1132 654 1133 /** 655 1134 * Generates the code or math problem and saves the value to the session 656 1135 */ 657 p rotectedfunction createCode()1136 public function createCode() 658 1137 { 659 1138 $this->code = false; … … 662 1141 case self::SI_CAPTCHA_MATHEMATIC: 663 1142 { 664 $signs = array('+', '-', 'x'); 665 $left = rand(1, 10); 666 $right = rand(1, 5); 667 $sign = $signs[rand(0, 2)]; 668 669 switch($sign) { 670 case 'x': $c = $left * $right; break; 671 case '-': $c = $left - $right; break; 672 default: $c = $left + $right; break; 673 } 674 1143 do { 1144 $signs = array('+', '-', 'x'); 1145 $left = mt_rand(1, 10); 1146 $right = mt_rand(1, 5); 1147 $sign = $signs[mt_rand(0, 2)]; 1148 1149 switch($sign) { 1150 case 'x': $c = $left * $right; break; 1151 case '-': $c = $left - $right; break; 1152 default: $c = $left + $right; break; 1153 } 1154 } while ($c <= 0); // no negative #'s or 0 1155 675 1156 $this->code = $c; 676 1157 $this->code_display = "$left $sign $right"; 677 1158 break; 678 1159 } 679 1160 1161 case self::SI_CAPTCHA_WORDS: 1162 $words = $this->readCodeFromFile(2); 1163 $this->code = implode(' ', $words); 1164 $this->code_display = $this->code; 1165 break; 1166 680 1167 default: 681 1168 { … … 687 1174 $this->code = $this->generateCode($this->code_length); 688 1175 } 689 1176 690 1177 $this->code_display = $this->code; 691 1178 $this->code = ($this->case_sensitive) ? $this->code : strtolower($this->code); 692 1179 } // default 693 1180 } 694 1181 695 1182 $this->saveData(); 696 1183 } 697 1184 698 1185 /** 699 1186 * Draws the captcha code on the image … … 703 1190 $width2 = $this->image_width * $this->iscale; 704 1191 $height2 = $this->image_height * $this->iscale; 705 1192 706 1193 if (!is_readable($this->ttf_file)) { 707 1194 imagestring($this->im, 4, 10, ($this->image_height / 2) - 5, 'Failed to load TTF font file!', $this->gdtextcolor); … … 727 1214 } 728 1215 } 729 1216 730 1217 // DEBUG 731 1218 //$this->im = $this->tmpimg; 732 1219 //$this->output(); 733 734 } 735 1220 1221 } 1222 736 1223 /** 737 1224 * Copies the captcha image to the final image with distortion applied … … 742 1229 // make array of poles AKA attractor points 743 1230 for ($i = 0; $i < $numpoles; ++ $i) { 744 $px[$i] = rand($this->image_width * 0.2, $this->image_width * 0.8);745 $py[$i] = rand($this->image_height * 0.2, $this->image_height * 0.8);746 $rad[$i] = rand($this->image_height * 0.2, $this->image_height * 0.8);1231 $px[$i] = mt_rand($this->image_width * 0.2, $this->image_width * 0.8); 1232 $py[$i] = mt_rand($this->image_height * 0.2, $this->image_height * 0.8); 1233 $rad[$i] = mt_rand($this->image_height * 0.2, $this->image_height * 0.8); 747 1234 $tmp = ((- $this->frand()) * 0.15) - .15; 748 1235 $amp[$i] = $this->perturbation * $tmp; 749 1236 } 750 1237 751 1238 $bgCol = imagecolorat($this->tmpimg, 0, 0); 752 1239 $width2 = $this->iscale * $this->image_width; … … 784 1271 } 785 1272 } 786 1273 787 1274 /** 788 1275 * Draws distorted lines on the image … … 793 1280 $x = $this->image_width * (1 + $line) / ($this->num_lines + 1); 794 1281 $x += (0.5 - $this->frand()) * $this->image_width / $this->num_lines; 795 $y = rand($this->image_height * 0.1, $this->image_height * 0.9);796 1282 $y = mt_rand($this->image_height * 0.1, $this->image_height * 0.9); 1283 797 1284 $theta = ($this->frand() - 0.5) * M_PI * 0.7; 798 1285 $w = $this->image_width; 799 $len = rand($w * 0.4, $w * 0.7);800 $lwid = rand(0, 2);801 1286 $len = mt_rand($w * 0.4, $w * 0.7); 1287 $lwid = mt_rand(0, 2); 1288 802 1289 $k = $this->frand() * 0.6 + 0.2; 803 1290 $k = $k * $k * 0.5; … … 810 1297 $x0 = $x - 0.5 * $len * cos($theta); 811 1298 $y0 = $y - 0.5 * $len * sin($theta); 812 1299 813 1300 $ldx = round(- $dy * $lwid); 814 1301 $ldy = round($dx * $lwid); 815 1302 816 1303 for ($i = 0; $i < $n; ++ $i) { 817 1304 $x = $x0 + $i * $dx + $amp * $dy * sin($k * $i * $step + $phi); … … 821 1308 } 822 1309 } 823 1310 824 1311 /** 825 1312 * Draws random noise on the image … … 834 1321 835 1322 $t0 = microtime(true); 836 1323 837 1324 $noise_level *= 125; // an arbitrary number that works well on a 1-10 scale 838 1325 839 1326 $points = $this->image_width * $this->image_height * $this->iscale; 840 1327 $height = $this->image_height * $this->iscale; 841 1328 $width = $this->image_width * $this->iscale; 842 1329 for ($i = 0; $i < $noise_level; ++$i) { 843 $x = rand(10, $width);844 $y = rand(10, $height);845 $size = rand(7, 10);1330 $x = mt_rand(10, $width); 1331 $y = mt_rand(10, $height); 1332 $size = mt_rand(7, 10); 846 1333 if ($x - $size <= 0 && $y - $size <= 0) continue; // dont cover 0,0 since it is used by imagedistortedcopy 847 1334 imagefilledarc($this->tmpimg, $x, $y, $size, $size, 0, 360, $this->gdnoisecolor, IMG_ARC_PIE); 848 1335 } 849 1336 850 1337 $t1 = microtime(true); 851 1338 852 1339 $t = $t1 - $t0; 853 1340 854 1341 /* 855 1342 // DEBUG … … 860 1347 */ 861 1348 } 862 863 864 865 1349 1350 /** 1351 * Print signature text on image 1352 */ 866 1353 protected function addSignature() 867 1354 { 868 if ($this->use_gd_font) { 869 imagestring($this->im, 5, $this->image_width - (strlen($this->image_signature) * 10), $this->image_height - 20, $this->image_signature, $this->gdsignaturecolor); 1355 $bbox = imagettfbbox(10, 0, $this->signature_font, $this->image_signature); 1356 $textlen = $bbox[2] - $bbox[0]; 1357 $x = $this->image_width - $textlen - 5; 1358 $y = $this->image_height - 3; 1359 1360 imagettftext($this->im, 10, 0, $x, $y, $this->gdsignaturecolor, $this->signature_font, $this->image_signature); 1361 } 1362 1363 /** 1364 * Sends the appropriate image and cache headers and outputs image to the browser 1365 */ 1366 protected function output() 1367 { 1368 if ($this->canSendHeaders() || $this->send_headers == false) { 1369 if ($this->send_headers) { 1370 // only send the content-type headers if no headers have been output 1371 // this will ease debugging on misconfigured servers where warnings 1372 // may have been output which break the image and prevent easily viewing 1373 // source to see the error. 1374 header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); 1375 header("Last-Modified: " . gmdate("D, d M Y H:i:s") . "GMT"); 1376 header("Cache-Control: no-store, no-cache, must-revalidate"); 1377 header("Cache-Control: post-check=0, pre-check=0", false); 1378 header("Pragma: no-cache"); 1379 } 1380 1381 switch ($this->image_type) { 1382 case self::SI_IMAGE_JPEG: 1383 if ($this->send_headers) header("Content-Type: image/jpeg"); 1384 imagejpeg($this->im, null, 90); 1385 break; 1386 case self::SI_IMAGE_GIF: 1387 if ($this->send_headers) header("Content-Type: image/gif"); 1388 imagegif($this->im); 1389 break; 1390 default: 1391 if ($this->send_headers) header("Content-Type: image/png"); 1392 imagepng($this->im); 1393 break; 1394 } 870 1395 } else { 871 872 $bbox = imagettfbbox(10, 0, $this->signature_font, $this->image_signature); 873 $textlen = $bbox[2] - $bbox[0]; 874 $x = $this->image_width - $textlen - 5; 875 $y = $this->image_height - 3; 876 877 imagettftext($this->im, 10, 0, $x, $y, $this->gdsignaturecolor, $this->signature_font, $this->image_signature); 878 } 879 } 880 881 /** 882 * Sends the appropriate image and cache headers and outputs image to the browser 883 */ 884 protected function output() 885 { 886 header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); 887 header("Last-Modified: " . gmdate("D, d M Y H:i:s") . "GMT"); 888 header("Cache-Control: no-store, no-cache, must-revalidate"); 889 header("Cache-Control: post-check=0, pre-check=0", false); 890 header("Pragma: no-cache"); 891 892 switch ($this->image_type) { 893 case self::SI_IMAGE_JPEG: 894 header("Content-Type: image/jpeg"); 895 imagejpeg($this->im, null, 90); 896 break; 897 case self::SI_IMAGE_GIF: 898 header("Content-Type: image/gif"); 899 imagegif($this->im); 900 break; 901 default: 902 header("Content-Type: image/png"); 903 imagepng($this->im); 904 break; 905 } 906 1396 echo '<hr /><strong>' 1397 .'Failed to generate captcha image, content has already been ' 1398 .'output.<br />This is most likely due to misconfiguration or ' 1399 .'a PHP error was sent to the browser.</strong>'; 1400 } 1401 907 1402 imagedestroy($this->im); 908 exit(); 909 } 910 1403 restore_error_handler(); 1404 1405 if (!$this->no_exit) exit; 1406 } 1407 911 1408 /** 912 1409 * Gets the code and returns the binary audio file for the stored captcha code 913 * @param string $format WAV only 914 */ 915 protected function getAudibleCode($format = 'wav') 916 { 917 // override any format other than wav for now 918 // this is due to security issues with MP3 files 919 $format = 'wav'; 920 1410 * 1411 * @return The audio representation of the captcha in Wav format 1412 */ 1413 protected function getAudibleCode() 1414 { 921 1415 $letters = array(); 922 $code = $this->getCode(); 923 924 if ($code == '') { 925 $this->createCode(); 926 $code = $this->getCode(); 927 } 928 929 for($i = 0; $i < strlen($code); ++$i) { 930 $letters[] = $code{$i}; 931 } 932 933 if ($format == 'mp3') { 934 return $this->generateMP3($letters); 1416 $code = $this->getCode(true, true); 1417 1418 if ($code['code'] == '') { 1419 if (strlen($this->display_value) > 0) { 1420 $code = array('code' => $this->display_value, 'display' => $this->display_value); 1421 } else { 1422 $this->createCode(); 1423 $code = $this->getCode(true); 1424 } 1425 } 1426 1427 if (preg_match('/(\d+) (\+|-|x) (\d+)/i', $code['display'], $eq)) { 1428 $math = true; 1429 1430 $left = $eq[1]; 1431 $sign = str_replace(array('+', '-', 'x'), array('plus', 'minus', 'times'), $eq[2]); 1432 $right = $eq[3]; 1433 1434 $letters = array($left, $sign, $right); 935 1435 } else { 1436 $math = false; 1437 1438 $length = strlen($code['display']); 1439 1440 for($i = 0; $i < $length; ++$i) { 1441 $letter = $code['display']{$i}; 1442 $letters[] = $letter; 1443 } 1444 } 1445 1446 try { 936 1447 return $this->generateWAV($letters); 1448 } catch(Exception $ex) { 1449 throw $ex; 937 1450 } 938 1451 } … … 941 1454 * Gets a captcha code from a wordlist 942 1455 */ 943 protected function readCodeFromFile( )944 { 945 $fp = @fopen($this->wordlist_file, 'rb');1456 protected function readCodeFromFile($numWords = 1) 1457 { 1458 $fp = fopen($this->wordlist_file, 'rb'); 946 1459 if (!$fp) return false; 947 1460 … … 949 1462 if ($fsize < 128) return false; // too small of a list to be effective 950 1463 951 fseek($fp, rand(0, $fsize - 64), SEEK_SET); // seek to a random position of file from 0 to filesize-64 952 $data = fread($fp, 64); // read a chunk from our random position 1464 if ((int)$numWords < 1 || (int)$numWords > 5) $numWords = 1; 1465 1466 $words = array(); 1467 $i = 0; 1468 do { 1469 fseek($fp, mt_rand(0, $fsize - 64), SEEK_SET); // seek to a random position of file from 0 to filesize-64 1470 $data = fread($fp, 64); // read a chunk from our random position 1471 $data = preg_replace("/\r?\n/", "\n", $data); 1472 1473 $start = @strpos($data, "\n", mt_rand(0, 56)) + 1; // random start position 1474 $end = @strpos($data, "\n", $start); // find end of word 1475 1476 if ($start === false) { 1477 // picked start position at end of file 1478 continue; 1479 } else if ($end === false) { 1480 $end = strlen($data); 1481 } 1482 1483 $word = strtolower(substr($data, $start, $end - $start)); // return a line of the file 1484 $words[] = $word; 1485 } while (++$i < $numWords); 1486 953 1487 fclose($fp); 954 $data = preg_replace("/\r?\n/", "\n", $data); 955 956 $start = @strpos($data, "\n", rand(0, 56)) + 1; // random start position 957 $end = @strpos($data, "\n", $start); // find end of word 958 959 if ($start === false) { 960 return false; 961 } else if ($end === false) { 962 $end = strlen($data); 963 } 964 965 return strtolower(substr($data, $start, $end - $start)); // return a line of the file 966 } 967 1488 1489 if ($numWords < 2) { 1490 return $words[0]; 1491 } else { 1492 return $words; 1493 } 1494 } 1495 968 1496 /** 969 1497 * Generates a random captcha code from the set character set … … 973 1501 $code = ''; 974 1502 975 for($i = 1, $cslen = strlen($this->charset); $i <= $this->code_length; ++$i) { 976 $code .= $this->charset{rand(0, $cslen - 1)}; 977 } 978 979 //return 'testing'; // debug, set the code to given string 980 1503 if (function_exists('mb_strlen')) { 1504 for($i = 1, $cslen = mb_strlen($this->charset); $i <= $this->code_length; ++$i) { 1505 $code .= mb_substr($this->charset, mt_rand(0, $cslen - 1), 1, 'UTF-8'); 1506 } 1507 } else { 1508 for($i = 1, $cslen = strlen($this->charset); $i <= $this->code_length; ++$i) { 1509 $code .= substr($this->charset, mt_rand(0, $cslen - 1), 1); 1510 } 1511 } 1512 981 1513 return $code; 982 1514 } 983 1515 984 1516 /** 985 1517 * Checks the entered code against the value stored in the session or sqlite database, handles case sensitivity … … 988 1520 protected function validate() 989 1521 { 990 $code = $this->getCode(); 991 // returns stored code, or an empty string if no stored code was found 992 // checks the session and sqlite database if enabled 993 1522 if (!is_string($this->code) || strlen($this->code) == 0) { 1523 $code = $this->getCode(); 1524 // returns stored code, or an empty string if no stored code was found 1525 // checks the session and database if enabled 1526 } else { 1527 $code = $this->code; 1528 } 1529 994 1530 if ($this->case_sensitive == false && preg_match('/[A-Z]/', $code)) { 995 1531 // case sensitive was set from securimage_show.php but not in class … … 997 1533 $this->case_sensitive = true; 998 1534 } 999 1535 1000 1536 $code_entered = trim( (($this->case_sensitive) ? $this->code_entered 1001 1537 : strtolower($this->code_entered)) 1002 1538 ); 1003 1539 $this->correct_code = false; 1004 1540 1005 1541 if ($code != '') { 1542 if (strpos($code, ' ') !== false) { 1543 // for multi word captchas, remove more than once space from input 1544 $code_entered = preg_replace('/\s+/', ' ', $code_entered); 1545 $code_entered = strtolower($code_entered); 1546 } 1547 1006 1548 if ($code == $code_entered) { 1007 1549 $this->correct_code = true; 1008 $_SESSION['securimage_code_value'][$this->namespace] = ''; 1009 $_SESSION['securimage_code_ctime'][$this->namespace] = ''; 1550 if ($this->no_session != true) { 1551 $_SESSION['securimage_code_value'][$this->namespace] = ''; 1552 $_SESSION['securimage_code_ctime'][$this->namespace] = ''; 1553 } 1010 1554 $this->clearCodeFromDatabase(); 1011 1555 } 1012 1556 } 1013 1557 } 1014 1015 /** 1016 * Return the code from the session or sqlite database if used. If none exists yet, an empty string is returned 1017 */ 1018 protected function getCode() 1558 1559 /** 1560 * Save data to session namespace and database if used 1561 */ 1562 protected function saveData() 1563 { 1564 if ($this->no_session != true) { 1565 if (isset($_SESSION['securimage_code_value']) && is_scalar($_SESSION['securimage_code_value'])) { 1566 // fix for migration from v2 - v3 1567 unset($_SESSION['securimage_code_value']); 1568 unset($_SESSION['securimage_code_ctime']); 1569 } 1570 1571 $_SESSION['securimage_code_disp'] [$this->namespace] = $this->code_display; 1572 $_SESSION['securimage_code_value'][$this->namespace] = $this->code; 1573 $_SESSION['securimage_code_ctime'][$this->namespace] = time(); 1574 } 1575 1576 if ($this->use_database) { 1577 $this->saveCodeToDatabase(); 1578 } 1579 } 1580 1581 /** 1582 * Saves the code to the sqlite database 1583 */ 1584 protected function saveCodeToDatabase() 1585 { 1586 $success = false; 1587 $this->openDatabase(); 1588 1589 if ($this->use_database && $this->pdo_conn) { 1590 $id = $this->getCaptchaId(false); 1591 $ip = $_SERVER['REMOTE_ADDR']; 1592 1593 if (empty($id)) { 1594 $id = $ip; 1595 } 1596 1597 $time = time(); 1598 $code = $this->code; 1599 $code_disp = $this->code_display; 1600 1601 // This is somewhat expensive in PDO Sqlite3 (when there is something to delete) 1602 $this->clearCodeFromDatabase(); 1603 1604 $query = "INSERT INTO {$this->database_table} (" 1605 ."id, code, code_display, namespace, created) " 1606 ."VALUES(?, ?, ?, ?, ?)"; 1607 1608 $stmt = $this->pdo_conn->prepare($query); 1609 $success = $stmt->execute(array($id, $code, $code_disp, $this->namespace, $time)); 1610 1611 if (!$success) { 1612 $err = $stmt->errorInfo(); 1613 trigger_error("Failed to insert code into database. {$err[1]}: {$err[2]}", E_USER_WARNING); 1614 } 1615 } 1616 1617 return $success !== false; 1618 } 1619 1620 /** 1621 * Open sqlite database 1622 */ 1623 protected function openDatabase() 1624 { 1625 $this->pdo_conn = false; 1626 1627 if ($this->use_database) { 1628 $pdo_extension = 'PDO_' . strtoupper($this->database_driver); 1629 1630 if (!extension_loaded($pdo_extension)) { 1631 trigger_error("Database support is turned on in Securimage, but the chosen extension $pdo_extension is not loaded in PHP.", E_USER_WARNING); 1632 return false; 1633 } 1634 } 1635 1636 if ($this->database_driver == self::SI_DRIVER_SQLITE3) { 1637 if (!file_exists($this->database_file)) { 1638 $fp = fopen($this->database_file, 'w+'); 1639 if (!$fp) { 1640 $err = error_get_last(); 1641 trigger_error("Securimage failed to create SQLite3 database file '{$this->database_file}'. Reason: {$err['message']}", E_USER_WARNING); 1642 return false; 1643 } 1644 fclose($fp); 1645 chmod($this->database_file, 0666); 1646 } else if (!is_writeable($this->database_file)) { 1647 trigger_error("Securimage does not have read/write access to database file '{$this->database_file}. Make sure permissions are 0666 and writeable by user '" . get_current_user() . "'", E_USER_WARNING); 1648 return false; 1649 } 1650 } 1651 1652 $dsn = $this->getDsn(); 1653 1654 try { 1655 $options = array(); 1656 $this->pdo_conn = new PDO($dsn, $this->database_user, $this->database_pass, $options); 1657 } catch (PDOException $pdoex) { 1658 trigger_error("Database connection failed: " . $pdoex->getMessage(), E_USER_WARNING); 1659 return false; 1660 } 1661 1662 try { 1663 if (!$this->checkTablesExist()) { 1664 // create tables... 1665 $this->createDatabaseTables(); 1666 } 1667 } catch (Exception $ex) { 1668 trigger_error($ex->getMessage(), E_USER_WARNING); 1669 $this->pdo_conn = null; 1670 return false; 1671 } 1672 1673 if (mt_rand(0, 100) / 100.0 == 1.0) { 1674 $this->purgeOldCodesFromDatabase(); 1675 } 1676 1677 return $this->pdo_conn; 1678 } 1679 1680 protected function getDsn() 1681 { 1682 $dsn = sprintf('%s:', $this->database_driver); 1683 1684 switch($this->database_driver) { 1685 case self::SI_DRIVER_SQLITE3: 1686 $dsn .= $this->database_file; 1687 break; 1688 1689 case self::SI_DRIVER_MYSQL: 1690 case self::SI_DRIVER_PGSQL: 1691 $dsn .= sprintf('host=%s;dbname=%s', 1692 $this->database_host, 1693 $this->database_name); 1694 break; 1695 1696 } 1697 1698 return $dsn; 1699 } 1700 1701 protected function checkTablesExist() 1702 { 1703 $table = $this->pdo_conn->quote($this->database_table); 1704 1705 switch($this->database_driver) { 1706 case self::SI_DRIVER_SQLITE3: 1707 // query row count for sqlite, PRAGMA queries seem to return no 1708 // rowCount using PDO even if there are rows returned 1709 $query = "SELECT COUNT(id) FROM $table"; 1710 break; 1711 1712 case self::SI_DRIVER_MYSQL: 1713 $query = "SHOW TABLES LIKE $table"; 1714 break; 1715 1716 case self::SI_DRIVER_PGSQL: 1717 $query = "SELECT * FROM information_schema.columns WHERE table_name = $table;"; 1718 break; 1719 } 1720 1721 $result = $this->pdo_conn->query($query); 1722 1723 if (!$result) { 1724 $err = $this->pdo_conn->errorInfo(); 1725 1726 if ($this->database_driver == self::SI_DRIVER_SQLITE3 && 1727 $err[1] === 1 && strpos($err[2], 'no such table') !== false) 1728 { 1729 return false; 1730 } 1731 1732 throw new Exception("Failed to check tables: {$err[0]} - {$err[1]}: {$err[2]}"); 1733 } else if ($this->database_driver == self::SI_DRIVER_SQLITE3) { 1734 // successful here regardless of row count for sqlite 1735 return true; 1736 } else if ($result->rowCount() == 0) { 1737 return false; 1738 } else { 1739 return true; 1740 } 1741 } 1742 1743 protected function createDatabaseTables() 1744 { 1745 $queries = array(); 1746 1747 switch($this->database_driver) { 1748 case self::SI_DRIVER_SQLITE3: 1749 $queries[] = "CREATE TABLE \"{$this->database_table}\" ( 1750 id VARCHAR(40), 1751 namespace VARCHAR(32) NOT NULL, 1752 code VARCHAR(32) NOT NULL, 1753 code_display VARCHAR(32) NOT NULL, 1754 created INTEGER NOT NULL, 1755 PRIMARY KEY(id, namespace) 1756 )"; 1757 1758 $queries[] = "CREATE INDEX ndx_created ON {$this->database_table} (created)"; 1759 break; 1760 1761 case self::SI_DRIVER_MYSQL: 1762 $queries[] = "CREATE TABLE `{$this->database_table}` ( 1763 `id` VARCHAR(40) NOT NULL, 1764 `namespace` VARCHAR(32) NOT NULL, 1765 `code` VARCHAR(32) NOT NULL, 1766 `code_display` VARCHAR(32) NOT NULL, 1767 `created` INT NOT NULL, 1768 PRIMARY KEY(id, namespace), 1769 INDEX(created) 1770 )"; 1771 break; 1772 1773 case self::SI_DRIVER_PGSQL: 1774 $queries[] = "CREATE TABLE {$this->database_table} ( 1775 id character varying(40) NOT NULL, 1776 namespace character varying(32) NOT NULL, 1777 code character varying(32) NOT NULL, 1778 code_display character varying(32) NOT NULL, 1779 created integer NOT NULL, 1780 CONSTRAINT pkey_id_namespace PRIMARY KEY (id, namespace) 1781 )"; 1782 1783 $queries[] = "CREATE INDEX ndx_created ON {$this->database_table} (created);"; 1784 break; 1785 } 1786 1787 $this->pdo_conn->beginTransaction(); 1788 1789 foreach($queries as $query) { 1790 $result = $this->pdo_conn->query($query); 1791 1792 if (!$result) { 1793 $err = $this->pdo_conn->errorInfo(); 1794 trigger_error("Failed to create table. {$err[1]}: {$err[2]}", E_USER_WARNING); 1795 $this->pdo_conn->rollBack(); 1796 $this->pdo_conn = false; 1797 return false; 1798 } 1799 } 1800 1801 $this->pdo_conn->commit(); 1802 1803 return true; 1804 } 1805 1806 /** 1807 * Get a code from the sqlite database for ip address/captchaId. 1808 * 1809 * @return string|array Empty string if no code was found or has expired, 1810 * otherwise returns the stored captcha code. If a captchaId is set, this 1811 * returns an array with indices "code" and "code_disp" 1812 */ 1813 protected function getCodeFromDatabase() 1019 1814 { 1020 1815 $code = ''; 1021 1022 if (isset($_SESSION['securimage_code_value'][$this->namespace]) && 1023 trim($_SESSION['securimage_code_value'][$this->namespace]) != '') { 1024 if ($this->isCodeExpired( 1025 $_SESSION['securimage_code_ctime'][$this->namespace]) == false) { 1026 $code = $_SESSION['securimage_code_value'][$this->namespace]; 1027 } 1028 } else if ($this->use_sqlite_db == true && function_exists('sqlite_open')) { 1029 // no code in session - may mean user has cookies turned off 1030 $this->openDatabase(); 1031 $code = $this->getCodeFromDatabase(); 1032 } else { /* no code stored in session or sqlite database, validation will fail */ } 1033 1816 1817 if ($this->use_database == true && $this->pdo_conn) { 1818 if (Securimage::$_captchaId !== null) { 1819 $query = "SELECT * FROM {$this->database_table} WHERE id = ?"; 1820 $stmt = $this->pdo_conn->prepare($query); 1821 $result = $stmt->execute(array(Securimage::$_captchaId)); 1822 } else { 1823 $ip = $_SERVER['REMOTE_ADDR']; 1824 $ns = $this->namespace; 1825 1826 // ip is stored in id column when no captchaId 1827 $query = "SELECT * FROM {$this->database_table} WHERE id = ? AND namespace = ?"; 1828 $stmt = $this->pdo_conn->prepare($query); 1829 $result = $stmt->execute(array($ip, $ns)); 1830 } 1831 1832 if (!$result) { 1833 $err = $this->pdo_conn->errorInfo(); 1834 trigger_error("Failed to select code from database. {$err[0]}: {$err[1]}", E_USER_WARNING); 1835 } else { 1836 if ( ($row = $stmt->fetch()) !== false ) { 1837 if (false == $this->isCodeExpired($row['created'])) { 1838 if (Securimage::$_captchaId !== null) { 1839 // return an array when using captchaId 1840 $code = array('code' => $row['code'], 1841 'code_disp' => $row['code_display']); 1842 } else { 1843 $code = $row['code']; 1844 } 1845 } 1846 } 1847 } 1848 } 1849 1034 1850 return $code; 1035 1851 } 1036 1037 /** 1038 * Save data to session namespace and database if used 1039 */ 1040 protected function saveData() 1041 { 1042 $_SESSION['securimage_code_value'][$this->namespace] = $this->code; 1043 $_SESSION['securimage_code_ctime'][$this->namespace] = time(); 1044 1045 $this->saveCodeToDatabase(); 1046 } 1047 1048 /** 1049 * Saves the code to the sqlite database 1050 */ 1051 protected function saveCodeToDatabase() 1052 { 1053 $success = false; 1054 1055 $this->openDatabase(); 1056 1057 if ($this->use_sqlite_db && $this->sqlite_handle !== false) { 1058 $ip = $_SERVER['REMOTE_ADDR']; 1059 $time = time(); 1060 $code = $_SESSION['securimage_code_value'][$this->namespace]; // if cookies are disabled the session still exists at this point 1061 $success = sqlite_query($this->sqlite_handle, 1062 "INSERT OR REPLACE INTO codes(ip, code, namespace, created) 1063 VALUES('$ip', '$code', '{$this->namespace}', $time)"); 1064 } 1065 1066 return $success !== false; 1067 } 1068 1069 /** 1070 * Open sqlite database 1071 */ 1072 protected function openDatabase() 1073 { 1074 $this->sqlite_handle = false; 1075 1076 if ($this->use_sqlite_db && function_exists('sqlite_open')) { 1077 $this->sqlite_handle = sqlite_open($this->sqlite_database, 0666, $error); 1078 1079 if ($this->sqlite_handle !== false) { 1080 $res = sqlite_query($this->sqlite_handle, "PRAGMA table_info(codes)"); 1081 if (sqlite_num_rows($res) == 0) { 1082 sqlite_query($this->sqlite_handle, "CREATE TABLE codes (ip VARCHAR(32) PRIMARY KEY, code VARCHAR(32) NOT NULL, namespace VARCHAR(32) NOT NULL, created INTEGER)"); 1083 } 1084 } 1085 1086 return $this->sqlite_handle != false; 1087 } 1088 1089 return $this->sqlite_handle; 1090 } 1091 1092 /** 1093 * Get a code from the sqlite database for ip address 1094 */ 1095 protected function getCodeFromDatabase() 1096 { 1097 $code = ''; 1098 1099 if ($this->use_sqlite_db && $this->sqlite_handle !== false) { 1852 1853 /** 1854 * Remove an entered code from the database 1855 */ 1856 protected function clearCodeFromDatabase() 1857 { 1858 if ($this->pdo_conn) { 1100 1859 $ip = $_SERVER['REMOTE_ADDR']; 1101 $ns = sqlite_escape_string($this->namespace); 1102 1103 $res = sqlite_query($this->sqlite_handle, "SELECT * FROM codes WHERE ip = '$ip' AND namespace = '$ns'"); 1104 if ($res && sqlite_num_rows($res) > 0) { 1105 $res = sqlite_fetch_array($res); 1106 1107 if ($this->isCodeExpired($res['created']) == false) { 1108 $code = $res['code']; 1109 } 1110 } 1111 } 1112 return $code; 1113 } 1114 1115 /** 1116 * Remove an entered code from the database 1117 */ 1118 protected function clearCodeFromDatabase() 1119 { 1120 if (is_resource($this->sqlite_handle)) { 1121 $ip = $_SERVER['REMOTE_ADDR']; 1122 $ns = sqlite_escape_string($this->namespace); 1123 1124 sqlite_query($this->sqlite_handle, "DELETE FROM codes WHERE ip = '$ip' AND namespace = '$ns'"); 1125 } 1126 } 1127 1860 $ns = $this->pdo_conn->quote($this->namespace); 1861 $id = Securimage::$_captchaId; 1862 1863 if (empty($id)) { 1864 $id = $ip; // if no captchaId set, IP address is captchaId. 1865 } 1866 1867 $id = $this->pdo_conn->quote($id); 1868 1869 $query = sprintf("DELETE FROM %s WHERE id = %s AND namespace = %s", 1870 $this->database_table, $id, $ns); 1871 1872 $result = $this->pdo_conn->query($query); 1873 if (!$result) { 1874 trigger_error("Failed to delete code from database.", E_USER_WARNING); 1875 } 1876 } 1877 } 1878 1128 1879 /** 1129 1880 * Deletes old codes from sqlite database … … 1131 1882 protected function purgeOldCodesFromDatabase() 1132 1883 { 1133 if ($this->use_ sqlite_db && $this->sqlite_handle !== false) {1884 if ($this->use_database && $this->pdo_conn) { 1134 1885 $now = time(); 1135 1886 $limit = (!is_numeric($this->expiry_time) || $this->expiry_time < 1) ? 86400 : $this->expiry_time; 1136 1137 sqlite_query($this->sqlite_handle, "DELETE FROM codes WHERE $now - created > $limit"); 1138 } 1139 } 1140 1887 1888 $query = sprintf("DELETE FROM %s WHERE %s - created > %s", 1889 $this->database_table, 1890 $this->pdo_conn->quote($now, PDO::PARAM_INT), 1891 $this->pdo_conn->quote($limit, PDO::PARAM_INT)); 1892 1893 $result = $this->pdo_conn->query($query); 1894 } 1895 } 1896 1141 1897 /** 1142 1898 * Checks to see if the captcha code has expired and cannot be used … … 1146 1902 { 1147 1903 $expired = true; 1148 1904 1149 1905 if (!is_numeric($this->expiry_time) || $this->expiry_time < 1) { 1150 1906 $expired = false; … … 1152 1908 $expired = false; 1153 1909 } 1154 1910 1155 1911 return $expired; 1156 1912 } 1157 1158 /** 1159 * 1160 * Generate an MP3 audio file of the captcha image 1161 * 1162 * @deprecated 3.0 1163 */ 1164 protected function generateMP3() 1165 { 1166 return false; 1167 } 1168 1913 1169 1914 /** 1170 1915 * Generate a wav file given the $letters in the code … … 1175 1920 protected function generateWAV($letters) 1176 1921 { 1177 $data_len = 0; 1178 $files = array(); 1179 $out_data = ''; 1180 $out_channels = 0; 1181 $out_samplert = 0; 1182 $out_bpersample = 0; 1183 $numSamples = 0; 1184 $removeChunks = array('LIST', 'DISP', 'NOTE'); 1185 1186 for ($i = 0; $i < sizeof($letters); ++$i) { 1187 $letter = $letters[$i]; 1188 $filename = $this->audio_path . strtoupper($letter) . '.wav'; 1189 $file = array(); 1190 $data = @file_get_contents($filename); 1191 1192 if ($data === false) { 1193 // echo "Failed to read $filename"; 1194 return $this->audioError(); 1195 } 1196 1197 $header = substr($data, 0, 36); 1198 $info = unpack('NChunkID/VChunkSize/NFormat/NSubChunk1ID/' 1199 .'VSubChunk1Size/vAudioFormat/vNumChannels/' 1200 .'VSampleRate/VByteRate/vBlockAlign/vBitsPerSample', 1201 $header); 1202 1203 $dataPos = strpos($data, 'data'); 1204 $out_channels = $info['NumChannels']; 1205 $out_samplert = $info['SampleRate']; 1206 $out_bpersample = $info['BitsPerSample']; 1207 1208 if ($dataPos === false) { 1209 // wav file with no data? 1210 // echo "Failed to find DATA segment in $filename"; 1211 return $this->audioError(); 1212 } 1213 1214 if ($info['AudioFormat'] != 1) { 1215 // only work with PCM audio 1216 // echo "$filename was not PCM audio, only PCM is supported"; 1217 return $this->audioError(); 1218 } 1219 1220 if ($info['SubChunk1Size'] != 16 && $info['SubChunk1Size'] != 18) { 1221 // probably unsupported extension 1222 // echo "Bad SubChunk1Size in $filename - Size was {$info['SubChunk1Size']}"; 1223 return $this->audioError(); 1224 } 1225 1226 if ($info['SubChunk1Size'] > 16) { 1227 $header .= substr($data, 36, $info['SubChunk1Size'] - 16); 1228 } 1229 1230 if ($i == 0) { 1231 // create the final file's header, size will be adjusted later 1232 $out_data = $header . 'data'; 1233 } 1234 1235 $removed = 0; 1236 1237 foreach($removeChunks as $chunk) { 1238 $chunkPos = strpos($data, $chunk); 1239 if ($chunkPos !== false) { 1240 $listSize = unpack('VSize', substr($data, $chunkPos + 4, 4)); 1241 1242 $data = substr($data, 0, $chunkPos) . 1243 substr($data, $chunkPos + 8 + $listSize['Size']); 1244 1245 $removed += $listSize['Size'] + 8; 1922 $wavCaptcha = new WavFile(); 1923 $first = true; // reading first wav file 1924 1925 foreach ($letters as $letter) { 1926 $letter = strtoupper($letter); 1927 1928 try { 1929 $l = new WavFile($this->audio_path . '/' . $letter . '.wav'); 1930 1931 if ($first) { 1932 // set sample rate, bits/sample, and # of channels for file based on first letter 1933 $wavCaptcha->setSampleRate($l->getSampleRate()) 1934 ->setBitsPerSample($l->getBitsPerSample()) 1935 ->setNumChannels($l->getNumChannels()); 1936 $first = false; 1246 1937 } 1247 } 1248 1249 $dataSize = unpack('VSubchunk2Size', substr($data, $dataPos + 4, 4)); 1250 $dataSize['Subchunk2Size'] -= $removed; 1251 $out_data .= substr($data, $dataPos + 8, $dataSize['Subchunk2Size'] * ($out_bpersample / 8)); 1252 $numSamples += $dataSize['Subchunk2Size']; 1253 } 1254 1255 $filesize = strlen($out_data); 1256 $chunkSize = $filesize - 8; 1257 $dataCSize = $numSamples; 1258 1259 $out_data = substr_replace($out_data, pack('V', $chunkSize), 4, 4); 1260 $out_data = substr_replace($out_data, pack('V', $numSamples), 40 + ($info['SubChunk1Size'] - 16), 4); 1261 1262 $this->scrambleAudioData($out_data, 'wav'); 1263 1264 return $out_data; 1265 } 1266 1267 /** 1268 * Randomizes the audio data to add noise and prevent binary recognition 1269 * @param string $data The binary audio file data 1270 * @param string $format The format of the sound file (wav only) 1271 */ 1272 protected function scrambleAudioData(&$data, $format) 1273 { 1274 $start = strpos($data, 'data') + 4; // look for "data" indicator 1275 if ($start === false) $start = 44; // if not found assume 44 byte header 1276 1277 $start += rand(1, 4); // randomize starting offset 1278 $datalen = strlen($data) - $start; 1279 $step = 1; 1280 1281 for ($i = $start; $i < $datalen; $i += $step) { 1282 $ch = ord($data{$i}); 1283 if ($ch == 0 || $ch == 255) continue; 1284 1285 if ($ch < 16 || $ch > 239) { 1286 $ch += rand(-6, 6); 1287 } else { 1288 $ch += rand(-12, 12); 1289 } 1290 1291 if ($ch < 0) $ch = 0; else if ($ch > 255) $ch = 255; 1292 1293 $data{$i} = chr($ch); 1294 1295 $step = rand(1,4); 1296 } 1297 1298 return $data; 1299 } 1300 1938 1939 // append letter to the captcha audio 1940 $wavCaptcha->appendWav($l); 1941 1942 // random length of silence between $audio_gap_min and $audio_gap_max 1943 if ($this->audio_gap_max > 0 && $this->audio_gap_max > $this->audio_gap_min) { 1944 $wavCaptcha->insertSilence( mt_rand($this->audio_gap_min, $this->audio_gap_max) / 1000.0 ); 1945 } 1946 } catch (Exception $ex) { 1947 // failed to open file, or the wav file is broken or not supported 1948 // 2 wav files were not compatible, different # channels, bits/sample, or sample rate 1949 throw $ex; 1950 } 1951 } 1952 1953 /********* Set up audio filters *****************************/ 1954 $filters = array(); 1955 1956 if ($this->audio_use_noise == true) { 1957 // use background audio - find random file 1958 $noiseFile = $this->getRandomNoiseFile(); 1959 1960 if ($noiseFile !== false && is_readable($noiseFile)) { 1961 try { 1962 $wavNoise = new WavFile($noiseFile, false); 1963 } catch(Exception $ex) { 1964 throw $ex; 1965 } 1966 1967 // start at a random offset from the beginning of the wavfile 1968 // in order to add more randomness 1969 $randOffset = 0; 1970 if ($wavNoise->getNumBlocks() > 2 * $wavCaptcha->getNumBlocks()) { 1971 $randBlock = mt_rand(0, $wavNoise->getNumBlocks() - $wavCaptcha->getNumBlocks()); 1972 $wavNoise->readWavData($randBlock * $wavNoise->getBlockAlign(), $wavCaptcha->getNumBlocks() * $wavNoise->getBlockAlign()); 1973 } else { 1974 $wavNoise->readWavData(); 1975 $randOffset = mt_rand(0, $wavNoise->getNumBlocks() - 1); 1976 } 1977 1978 1979 $mixOpts = array('wav' => $wavNoise, 1980 'loop' => true, 1981 'blockOffset' => $randOffset); 1982 1983 $filters[WavFile::FILTER_MIX] = $mixOpts; 1984 $filters[WavFile::FILTER_NORMALIZE] = $this->audio_mix_normalization; 1985 } 1986 } 1987 1988 if ($this->degrade_audio == true) { 1989 // add random noise. 1990 // any noise level below 95% is intensely distorted and not pleasant to the ear 1991 $filters[WavFile::FILTER_DEGRADE] = mt_rand(95, 98) / 100.0; 1992 } 1993 1994 if (!empty($filters)) { 1995 $wavCaptcha->filter($filters); // apply filters to captcha audio 1996 } 1997 1998 return $wavCaptcha->__toString(); 1999 } 2000 2001 public function getRandomNoiseFile() 2002 { 2003 $return = false; 2004 2005 if ( ($dh = opendir($this->audio_noise_path)) !== false ) { 2006 $list = array(); 2007 2008 while ( ($file = readdir($dh)) !== false ) { 2009 if ($file == '.' || $file == '..') continue; 2010 if (strtolower(substr($file, -4)) != '.wav') continue; 2011 2012 $list[] = $file; 2013 } 2014 2015 closedir($dh); 2016 2017 if (sizeof($list) > 0) { 2018 $file = $list[array_rand($list, 1)]; 2019 $return = $this->audio_noise_path . DIRECTORY_SEPARATOR . $file; 2020 } 2021 } 2022 2023 return $return; 2024 } 2025 1301 2026 /** 1302 2027 * Return a wav file saying there was an error generating file 1303 * 2028 * 1304 2029 * @return string The binary audio contents 1305 2030 */ 1306 2031 protected function audioError() 1307 2032 { 1308 return @file_get_contents(dirname(__FILE__) . '/audio/error.wav'); 1309 } 1310 2033 return @file_get_contents(dirname(__FILE__) . '/audio/en/error.wav'); 2034 } 2035 2036 /** 2037 * Checks to see if headers can be sent and if any error has been output to the browser 2038 * 2039 * @return bool true if headers haven't been sent and no output/errors will break audio/images, false if unsafe 2040 */ 2041 protected function canSendHeaders() 2042 { 2043 if (headers_sent()) { 2044 // output has been flushed and headers have already been sent 2045 return false; 2046 } else if (strlen((string)ob_get_contents()) > 0) { 2047 // headers haven't been sent, but there is data in the buffer that will break image and audio data 2048 return false; 2049 } 2050 2051 return true; 2052 } 2053 2054 /** 2055 * Return a random float between 0 and 0.9999 2056 * 2057 * @return float Random float between 0 and 0.9999 2058 */ 1311 2059 function frand() 1312 2060 { 1313 return 0.0001 * rand(0,9999);1314 } 1315 2061 return 0.0001 * mt_rand(0,9999); 2062 } 2063 1316 2064 /** 1317 2065 * Convert an html color code to a Securimage_Color … … 1334 2082 return new Securimage_Color($default); 1335 2083 } 2084 } 2085 2086 /** 2087 * Error handler used when outputting captcha image or audio. 2088 * This error handler helps determine if any errors raised would 2089 * prevent captcha image or audio from displaying. If they have 2090 * no effect on the output buffer or headers, true is returned so 2091 * the script can continue processing. 2092 * See https://github.com/dapphp/securimage/issues/15 2093 * 2094 * @param int $errno 2095 * @param string $errstr 2096 * @param string $errfile 2097 * @param int $errline 2098 * @param array $errcontext 2099 * @return boolean true if handled, false if PHP should handle 2100 */ 2101 public function errorHandler($errno, $errstr, $errfile = '', $errline = 0, $errcontext = array()) 2102 { 2103 // get the current error reporting level 2104 $level = error_reporting(); 2105 2106 // if error was supressed or $errno not set in current error level 2107 if ($level == 0 || ($level & $errno) == 0) { 2108 return true; 2109 } 2110 2111 return false; 1336 2112 } 1337 2113 } … … 1360 2136 * $color = new Securimage_Color('#0080FF') or <br /> 1361 2137 * $color = new Securimage_Color(0, 128, 255) 1362 * 2138 * 1363 2139 * @param string $color 1364 2140 * @throws Exception … … 1367 2143 { 1368 2144 $args = func_get_args(); 1369 2145 1370 2146 if (sizeof($args) == 0) { 1371 2147 $this->r = 255; … … 1377 2153 $color = substr($color, 1); 1378 2154 } 1379 2155 1380 2156 if (strlen($color) != 3 && strlen($color) != 6) { 1381 2157 throw new InvalidArgumentException( … … 1383 2159 ); 1384 2160 } 1385 2161 1386 2162 $this->constructHTML($color); 1387 2163 } else if (sizeof($args) == 3) { … … 1393 2169 } 1394 2170 } 1395 2171 1396 2172 /** 1397 2173 * Construct from an rgb triplet … … 1408 2184 if ($blue < 0) $blue = 0; 1409 2185 if ($blue > 255) $blue = 255; 1410 2186 1411 2187 $this->r = $red; 1412 2188 $this->g = $green; 1413 2189 $this->b = $blue; 1414 2190 } 1415 2191 1416 2192 /** 1417 2193 * Construct from an html hex color code … … 1427 2203 $red = substr($color, 0, 2); 1428 2204 $green = substr($color, 2, 2); 1429 $blue = substr($color, 4, 2); 1430 } 1431 2205 $blue = substr($color, 4, 2); 2206 } 2207 1432 2208 $this->r = hexdec($red); 1433 2209 $this->g = hexdec($green); … … 1435 2211 } 1436 2212 } 1437 ?> -
extensions/CryptograPHP/securimage/securimage_preview.php
r26041 r26554 15 15 'height' => (int)$_GET['height'], 16 16 'perturbation' => (float)$_GET['perturbation'], 17 'image_bg_color' => $_GET['image_bg_color'], 17 'background' => $_GET['background'], 18 'bg_color' => $_GET['bg_color'], 19 'bg_image' => $_GET['bg_image'], 18 20 'code_length' => (int)$_GET['code_length'], 19 21 'text_color' => $_GET['text_color'], … … 38 40 } 39 41 40 foreach (array(' image_bg_color','text_color','line_color','noise_color') as $color)42 foreach (array('bg_color','text_color','line_color','noise_color') as $color) 41 43 { 42 44 if ($temp_conf[$color] == 'random') $temp_conf[$color] = randomColor(); … … 53 55 $img->image_height = $temp_conf['height']; 54 56 $img->perturbation = $temp_conf['perturbation']; 55 $img->image_bg_color = new Securimage_Color('#'.$temp_conf['image_bg_color']);56 57 $img->text_color = new Securimage_Color('#'.$temp_conf['text_color']); 57 58 $img->num_lines = $temp_conf['num_lines']; … … 61 62 $img->code_length = $temp_conf['code_length']; 62 63 63 $img->show(); 64 65 ?> 64 if ($temp_conf['background'] == 'image') 65 { 66 if ($temp_conf['bg_image'] == 'random') 67 { 68 $img->background_directory = realpath(CRYPTO_PATH . 'securimage/backgrounds/'); 69 $img->show(); 70 } 71 else 72 { 73 $img->show(realpath(CRYPTO_PATH . 'securimage/backgrounds/' . $temp_conf['bg_image'])); 74 } 75 } 76 else 77 { 78 $img->image_bg_color = new Securimage_Color('#'.$temp_conf['bg_color']); 79 $img->show(); 80 } -
extensions/CryptograPHP/securimage/securimage_show.php
r19428 r26554 60 60 } 61 61 62 foreach (array(' image_bg_color','text_color','line_color','noise_color') as $color)62 foreach (array('bg_color','text_color','line_color','noise_color') as $color) 63 63 { 64 64 if ($conf['cryptographp'][$color] == 'random') $conf['cryptographp'][$color] = randomColor(); … … 75 75 $img->image_height = $conf['cryptographp']['height']; 76 76 $img->perturbation = $conf['cryptographp']['perturbation']; 77 $img->image_bg_color = new Securimage_Color('#'.$conf['cryptographp']['image_bg_color']);78 77 $img->text_color = new Securimage_Color('#'.$conf['cryptographp']['text_color']); 79 78 $img->num_lines = $conf['cryptographp']['num_lines']; … … 83 82 $img->code_length = $conf['cryptographp']['code_length']; 84 83 85 $img->show(); 86 87 ?> 84 if ($conf['cryptographp']['background'] == 'image') 85 { 86 if ($conf['cryptographp']['bg_image'] == 'random') 87 { 88 $img->background_directory = realpath(CRYPTO_PATH . 'securimage/backgrounds/'); 89 $img->show(); 90 } 91 else 92 { 93 $img->show(realpath(CRYPTO_PATH . 'securimage/backgrounds/' . $conf['cryptographp']['bg_image'])); 94 } 95 } 96 else 97 { 98 $img->image_bg_color = new Securimage_Color('#'.$conf['cryptographp']['bg_color']); 99 $img->show(); 100 } -
extensions/CryptograPHP/template/admin.tpl
r26041 r26554 9 9 10 10 {footer_script} 11 var time = 0; 12 11 13 // colorpicker 12 14 $('.colorpicker-input') … … 17 19 }, 18 20 onChange: function(hsb, hex, rgb, el) { 19 $(el).val(hex) ;21 $(el).val(hex).trigger('change'); 20 22 changeColor(el, hex); 21 changePreview();22 setThemeCutom();23 23 }, 24 24 onBeforeShow: function () { … … 33 33 changeColor(this, $(this).val()); 34 34 }); 35 36 37 $('.button').click(function() { 38 $(this).siblings('.button').removeClass('selected'); 39 $(this).addClass('selected'); 40 $('input[name='+ $(this).data('input') +']').val($(this).data('val')).trigger('change'); 41 }); 35 42 36 43 // change button 37 $('.button').click(function() { 38 $('.button').removeClass('selected'); 39 $(this).addClass('selected'); 40 $('input[name=button_color]').val($(this).attr('title')); 41 $('#reload').attr('src', '{$CRYPTO_PATH}template/refresh_'+ $(this).attr('title') +'.png'); 44 $('input[name=button_color]').change(function() { 45 $('#reload').attr('src', '{$CRYPTO_PATH}template/refresh_'+ $(this).val() +'.png'); 42 46 }); 43 47 44 48 // apply a preset 45 $('.preset').click(function() { 46 $('.preset').removeClass('selected'); 47 $(this).addClass('selected'); 48 49 var id = $(this).attr("title"); 49 $('input[name=theme]').change(function() { 50 var id = $(this).val(); 50 51 51 52 for (key in presets[id]) { 52 $('input[name="'+ key +'"]').val([presets[id][key]]); 53 if ($('input[name="'+ key +'"]').attr('type') == 'radio') { 54 $('input[name="'+ key +'"][value="'+ presets[id][key] +'"]').prop('checked', true).trigger('change', false); 55 } 56 else { 57 $('input[name="'+ key +'"]').val(presets[id][key]).trigger('change', false); 58 } 53 59 } 54 60 … … 56 62 changeColor(this, $(this).val()); 57 63 }); 58 $('input[name="theme"]').val($(this).attr('title')); 64 59 65 changePreview(); 66 }); 67 68 // toggle background type 69 $('input[name=background]').change(function() { 70 $('li[id^=background]').hide().filter('#background-'+$(this).val()).show(); 60 71 }); 61 72 … … 66 77 67 78 // change theme to 'custom' if a parameter is changed 68 $('input.istheme').change(function( ) {69 setThemeCutom();79 $('input.istheme').change(function(e, p) { 80 if (p!==false) setThemeCustom(); 70 81 }); 71 82 72 83 // update the preview 73 $('input. istheme, input.preview').change(function() {74 changePreview();84 $('input.preview').change(function(e, p) { 85 if (p!==false) changePreview(); 75 86 }); 76 87 $('#reload').click(function() { … … 80 91 // links for random color 81 92 $('a.random').click(function() { 82 $(this).prev('label').children('input').val('random') ;93 $(this).prev('label').children('input').val('random').trigger('change'); 83 94 changeColor($(this).prev('label').children('input'), 'random'); 84 changePreview();85 setThemeCutom();86 95 }); 87 96 … … 93 102 }); 94 103 95 function setThemeCu tom() {96 $('. preset').removeClass('selected');104 function setThemeCustom() { 105 $('.button[data-input=theme]').removeClass('selected'); 97 106 $('input[name=theme]').val('custom'); 98 107 } 99 108 100 109 function changePreview() { 110 var now = (new Date()).getTime(); 111 112 if (now-time < 1000) { 113 return; 114 } 115 time = now; 116 101 117 options = new Array(); 102 118 str = ''; 103 119 104 $('input [type="text"], input[type="radio"]:checked').each(function() {120 $('input.preview:not([type=radio]), input[type=radio].preview:checked').each(function() { 105 121 options[$(this).attr('name')] = $(this).val(); 106 122 }); … … 113 129 114 130 function changeColor(target, color) { 115 if (color == 'random') color = '808080'; 131 if (color == 'random') { 132 color = '808080'; 133 } 116 134 if (parseInt(color, 16) > 16777215/2) { 117 135 $(target).css('color', '#222'); … … 136 154 137 155 {html_style} 138 {foreach from=$fonts item= font}156 {foreach from=$fonts item=path key=font} 139 157 @font-face { 140 158 font-family: '{$font}'; 141 src: url({$ CRYPTO_PATH}securimage/fonts/{$font}.ttf) format("truetype");159 src: url({$path}) format("truetype"); 142 160 } 143 161 {/foreach} … … 193 211 <li> 194 212 <b>{'Button color'|translate}</b> 195 <a class="button {if $crypto.button_color == 'dark'}selected{/if}" title="dark"><img src="{$CRYPTO_PATH}template/refresh_dark.png" alt="dark"></a>196 <a class="button {if $crypto.button_color == 'light'}selected{/if}" title="light"><img src="{$CRYPTO_PATH}template/refresh_light.png" alt="light"></a>213 <a class="button {if $crypto.button_color == 'dark'}selected{/if}" data-val="dark" data-input="button_color"><img src="{$CRYPTO_PATH}template/refresh_dark.png" alt="dark"></a> 214 <a class="button {if $crypto.button_color == 'light'}selected{/if}" data-val="light" data-input="button_color"><img src="{$CRYPTO_PATH}template/refresh_light.png" alt="light"></a> 197 215 <input type="hidden" name="button_color" value="{$crypto.button_color}"> 198 216 </li> 199 217 <li> 200 218 <b>{'Captcha theme'|translate}</b> 201 202 <a class=" preset {if $crypto.theme == $preset}selected{/if}" title="{$preset}"><img src="{$CRYPTO_PATH}template/presets/{$preset}.png" alt="{$preset}"></a>203 219 {foreach from=$PRESETS key=preset item=params} 220 <a class="button {if $crypto.theme == $preset}selected{/if}" data-val="{$preset}" data-input="theme"><img src="{$CRYPTO_PATH}template/presets/{$preset}.png" alt="{$preset}"></a> 221 {/foreach} 204 222 <input type="hidden" name="theme" value="{$crypto.theme}"> 205 223 <a class="customize">{'Customize'|translate}</a> … … 213 231 <li> 214 232 <b>{'Perturbation'|translate}</b> 215 <label><input type="text" name="perturbation" value="{$crypto.perturbation}" class="istheme" size="6" maxlength="4"> {'range:'|translate} 0 - 1</label> 216 </li> 217 <li> 233 <label><input type="text" name="perturbation" value="{$crypto.perturbation}" class="istheme preview" size="6" maxlength="4"> {'range:'|translate} 0 - 1</label> 234 </li> 235 <li> 236 <b>{'Background'|translate}</b> 237 <label><input type="radio" name="background" class="istheme preview" value="color" {if $crypto.background == 'color'}checked="checked"{/if}> {'Color'|translate}</label> 238 <label><input type="radio" name="background" class="istheme preview" value="image" {if $crypto.background == 'image'}checked="checked"{/if}> {'Image'|translate}</label> 239 </li> 240 <li id="background-color" {if $crypto.background != 'color'}style="display:none;"{/if}> 218 241 <b>{'Background color'|translate}</b> 219 <label><input type="text" name=" image_bg_color" value="{$crypto.image_bg_color}" class="colorpicker-input istheme" size="6" maxlength="6"></label>242 <label><input type="text" name="bg_color" value="{$crypto.bg_color}" class="colorpicker-input istheme preview" size="6" maxlength="6"></label> 220 243 <a class="random" title="{'random'|translate}"><img src="{$CRYPTO_PATH}/template/arrow_switch.png"></a> 221 244 </li> 245 <li id="background-image" {if $crypto.background != 'image'}style="display:none;"{/if}> 246 <b>{'Background image'|translate}</b> 247 {foreach from=$backgrounds item=path key=background} 248 <a class="button {if $crypto.bg_image == $background}selected{/if}" data-val="{$background}" data-input="bg_image"><img src="{$path}" alt="{$background}" style="width:120px;height:40px;"></a> 249 {/foreach} 250 <!-- <a class="button {if $crypto.bg_image == 'random'}selected{/if}" title="{'random'|translate}" data-val="random" data-input="bg_image"><img src="{$CRYPTO_PATH}/template/arrow_switch.png"></a> --> 251 <input type="hidden" name="bg_image" value="{$crypto.bg_image}" class="istheme preview"> 252 </li> 222 253 <li> 223 254 <b>{'Text color'|translate}</b> 224 <label><input type="text" name="text_color" value="{$crypto.text_color}" class="colorpicker-input istheme " size="6" maxlength="6"></label>255 <label><input type="text" name="text_color" value="{$crypto.text_color}" class="colorpicker-input istheme preview" size="6" maxlength="6"></label> 225 256 <a class="random" title="{'random'|translate}"><img src="{$CRYPTO_PATH}/template/arrow_switch.png"></a> 226 257 </li> 227 258 <li> 228 259 <b>{'Lines density'|translate}</b> 229 <label><input type="text" name="num_lines" value="{$crypto.num_lines}" class="istheme " size="6" maxlength="4"> {'range:'|translate} 0 - 10</label>260 <label><input type="text" name="num_lines" value="{$crypto.num_lines}" class="istheme preview" size="6" maxlength="4"> {'range:'|translate} 0 - 10</label> 230 261 </li> 231 262 <li> 232 263 <b>{'Lines color'|translate}</b> 233 <label><input type="text" name="line_color" value="{$crypto.line_color}" class="colorpicker-input istheme " size="6" maxlength="6"></label>264 <label><input type="text" name="line_color" value="{$crypto.line_color}" class="colorpicker-input istheme preview" size="6" maxlength="6"></label> 234 265 <a class="random" title="{'random'|translate}"><img src="{$CRYPTO_PATH}/template/arrow_switch.png"></a> 235 266 </li> 236 267 <li> 237 268 <b>{'Noise level'|translate}</b> 238 <label><input type="text" name="noise_level" value="{$crypto.noise_level}" class="istheme " size="6" maxlength="4"> {'range:'|translate} 0 - 10</label>269 <label><input type="text" name="noise_level" value="{$crypto.noise_level}" class="istheme preview" size="6" maxlength="4"> {'range:'|translate} 0 - 10</label> 239 270 </li> 240 271 <li> 241 272 <b>{'Noise color'|translate}</b> 242 <label><input type="text" name="noise_color" value="{$crypto.noise_color}" class="colorpicker-input istheme " size="6" maxlength="6"></label>273 <label><input type="text" name="noise_color" value="{$crypto.noise_color}" class="colorpicker-input istheme preview" size="6" maxlength="6"></label> 243 274 <a class="random" title="{'random'|translate}"><img src="{$CRYPTO_PATH}/template/arrow_switch.png"></a> 244 275 </li> 245 276 <li> 246 277 <b>{'Font'|translate}</b> 247 {foreach from=$fonts item=font}248 <label style="font-family:{$font};" title="{$font}"><input type="radio" name="ttf_file" value="{$font}" {if $crypto.ttf_file == $font}checked="checked"{/if} class="istheme "> {$font}</label>249 278 {foreach from=$fonts item=path key=font} 279 <label style="font-family:{$font};" title="{$font}"><input type="radio" name="ttf_file" value="{$font}" {if $crypto.ttf_file == $font}checked="checked"{/if} class="istheme preview"> {$font}</label> 280 {/foreach} 250 281 </li> 251 282 </ul> -
extensions/CryptograPHP/template/style.css
r23209 r26554 1 . preset img, .button img {1 .button img { 2 2 margin:1px; 3 3 padding:3px; 4 4 border:1px solid #999; 5 5 } 6 . preset.selected img, .button.selected img {6 .button.selected img { 7 7 border-color:#f70; 8 8 }
Note: See TracChangeset
for help on using the changeset viewer.