| 1 |
<?php |
<?php |
| 2 |
// $Id: captcha.module,v 1.18 2006/01/12 23:34:58 arnabdotorg Exp $ |
// $Id: captcha.module,v 1.19 2006/01/15 18:51:40 arnabdotorg Exp $ |
| 3 |
|
|
| 4 |
function captcha_help($section = "admin/help#captcha") { |
function captcha_help($section = "admin/help#captcha") { |
| 5 |
$output = ""; |
$output = ""; |
| 30 |
|
|
| 31 |
$suffix = ''; |
$suffix = ''; |
| 32 |
if (arg(2)!=null) $suffix='/'.arg(2); |
if (arg(2)!=null) $suffix='/'.arg(2); |
| 33 |
|
|
| 34 |
$items[] = array('path' => 'captcha/image'.$suffix, 'title' => t('captcha image'), |
$items[] = array('path' => 'captcha/image'.$suffix, 'title' => t('captcha image'), |
| 35 |
'callback' => '_captcha_image', 'access' => user_access('access captchas'), |
'callback' => _captcha_call('_captcha_image'), 'access' => user_access('access captchas'), |
| 36 |
'type' => MENU_CALLBACK); |
'type' => MENU_CALLBACK); |
| 37 |
|
|
| 38 |
return $items; |
return $items; |
| 66 |
|
|
| 67 |
} |
} |
| 68 |
|
|
| 69 |
$form['captcha_user_register'] = array( |
//this is where you can add more captcha points |
| 70 |
'#type' => 'checkbox', |
$captcha_points = array( |
| 71 |
'#title' => t('Check during user registration'), |
'comment_form' => t('Comment Form'), |
| 72 |
'#default_value' => _captcha_istrue("captcha_user_register", "true"), |
'user_login' => t('User Login Form'), |
| 73 |
'#description' => t('If enabled, users will be asked to recognize an image during user registration.'), |
'user_login_block' => t('User Login Form Block'), |
| 74 |
); |
'user_edit' => t('User Edit Form'), |
| 75 |
$form['captcha_comment_anonymous'] = array( |
'user_register' => t('User Registration Form'), |
| 76 |
'#type' => 'checkbox', |
'user_pass' => t('User Forgot Password Form'), |
| 77 |
'#title' => t('Check during anonymous comments.'), |
'contact_mail_user' => t('User Contact Form'), |
| 78 |
'#default_value' => _captcha_istrue("captcha_comment_anonymous", "true"), |
'contact_mail_page' => t('Sitewide Contact Form'), |
| 79 |
'#description' => t('If enabled, anonymous users will be asked to recognize an image while posting .'), |
'node_form' => t('Create a node'), |
| 80 |
); |
); |
| 81 |
|
|
| 82 |
$form['captcha_comment_registered'] = array( |
$roles = user_roles(); |
| 83 |
'#type' => 'checkbox', |
|
| 84 |
'#title' => t('Check during registered user comments.'), |
foreach($roles as $role) { |
| 85 |
'#default_value' => _captcha_istrue("captcha_comment_registered", "true"), |
$varsuffix = strtr($role,' ','_') .'_captcha'; |
| 86 |
'#description' => t('If enabled, registered users will be asked to recognize an image while posting .'), |
$form[$varsuffix] = array('#type' => 'fieldset', '#title' => t('Captcha Points for the role '. $role), '#collapsible' => TRUE, '#collapsed' => TRUE); |
| 87 |
); |
foreach($captcha_points as $captcha_point=>$captcha_point_description) { |
| 88 |
|
$varname = $captcha_point .'_'. $varsuffix; |
| 89 |
|
$form[$varsuffix][$varname] = array( |
| 90 |
|
'#type' => 'checkbox', |
| 91 |
|
'#title' => $captcha_point_description, |
| 92 |
|
'#default_value' => variable_get($varname, NULL) |
| 93 |
|
); |
| 94 |
|
} |
| 95 |
|
} |
| 96 |
|
|
| 97 |
|
$form['captcha_type'] = array( |
| 98 |
|
'#type' => 'select', |
| 99 |
|
'#title' => t('Type of captcha to use'), |
| 100 |
|
'#default_value' => variable_get('captcha_type','image'), |
| 101 |
|
'#options' => _captcha_types(), |
| 102 |
|
'#description' => t('Select what kind of challenge you want to pose to the user') |
| 103 |
|
); |
| 104 |
|
|
| 105 |
$form['captcha_fonts_path'] = array( |
$form['captcha_fonts_path'] = array( |
| 106 |
'#type' => 'textfield', |
'#type' => 'textfield', |
| 111 |
'#description' => t('Location of the directory where the Truetype (.ttf) fonts are stored. If you do not provide any fonts, the module will use the default font for text.'), |
'#description' => t('Location of the directory where the Truetype (.ttf) fonts are stored. If you do not provide any fonts, the module will use the default font for text.'), |
| 112 |
); |
); |
| 113 |
|
|
|
|
|
| 114 |
if (isset($fonts_path)) { |
if (isset($fonts_path)) { |
| 115 |
$imagefontinfo .= t('Number of fonts found: ').count(_captcha_font_list()); |
$imagefontinfo .= t('Number of fonts found: ').count(_captcha_font_list()); |
| 116 |
} |
} |
| 130 |
return $form; |
return $form; |
| 131 |
} |
} |
| 132 |
|
|
|
/** |
|
|
* Implementation of hook_menu(), for adding form elements & validation. |
|
|
*/ |
|
|
function captcha_user($type, &$edit, &$newuser, $category = NULL) { |
|
|
|
|
|
global $user; |
|
|
|
|
|
// What type of registration action are we taking? |
|
|
// make sure this is a registration, and captcha is enabled for registration |
|
|
if (_captcha_istrue("captcha_user_register") && !$newuser->uid && !$user->uid) { |
|
|
switch ($type) { |
|
|
case 'register': |
|
|
// Add two items to the resigtration form. |
|
|
return array( t('Verify Registration') => _captcha_form()); |
|
|
break; |
|
|
|
|
|
case 'validate': |
|
|
// The user has filled out the form and checked the "accept" box. |
|
|
if (_captcha_validate($edit['captcha_word'])) { |
|
|
$_SESSION['captcha']=''; |
|
|
// on success return the values you want to store |
|
|
return array("captcha_correct" => 1); |
|
|
} |
|
|
else { |
|
|
// on error return an error message |
|
|
form_set_error('captcha_word', t("Please re-recognize the word shown in the image.")); |
|
|
return $edit; |
|
|
} |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
/** |
|
|
* Comment callback; adds captcha field to new comment form. |
|
|
*/ |
|
|
function captcha_comment($edit, $op) { |
|
|
|
|
|
switch ($op) { |
|
|
case 'validate': //this is redundant, not followed |
|
|
// only validate captcha once for a comment. |
|
|
// this implementation basically sets a flag when you've successfully validated a captcha; |
|
|
// any successive comment inserted uses and invalidates the set flag. |
|
|
if (!$_SESSION['captcha_comment_correct']) { |
|
|
if (_captcha_validate($edit['captcha_word'])) { |
|
|
$_SESSION['captcha_comment_correct'] = true; |
|
|
//reset captcha variable to prevent session highjacking vulnerability #26741 |
|
|
$_SESSION['captcha']=''; |
|
|
} |
|
|
else { |
|
|
form_set_error('captcha_word', t('The captcha verification code you entered is not correct.')); |
|
|
} |
|
|
} |
|
|
break; |
|
|
case 'insert': |
|
|
//invalidate captcha after one comment insert |
|
|
$_SESSION['captcha_comment_correct'] = false; |
|
|
$_SESSION['captcha']=''; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
function _captcha_form() { |
|
|
|
|
|
$form['captcha_image'] = array ( |
|
|
'#type' => 'item', |
|
|
'#title' => 'captcha image', |
|
|
'#value' => '<img src="' . url('captcha/image/'.time()) . '" alt="Captcha Image: you will need to recognize the text in it."/>', |
|
|
); |
|
|
|
|
|
$form['captcha_word'] = array ( |
|
|
'#type' => 'textfield', |
|
|
'#title' => t('Word'), |
|
|
'#defaultvalue' => '', |
|
|
'#description' => t('Please type in the letters/numbers that are shown in the image above.'), |
|
|
); |
|
|
|
|
|
return $form; |
|
|
} |
|
| 133 |
|
|
| 134 |
|
|
| 135 |
function captcha_form_alter($formid, &$form) { |
function captcha_form_alter($formid, &$form) { |
| 136 |
|
|
| 137 |
global $user; |
global $user; |
| 138 |
|
$captcha_type = variable_get("captcha_type", NULL); |
| 139 |
|
|
| 140 |
switch($formid) { |
if (!$captcha_type) return; |
|
case 'comment_form': |
|
| 141 |
|
|
| 142 |
// check if captcha is enabled for form type |
$flag = true; |
| 143 |
if ($user->uid == 0 && !_captcha_istrue("captcha_comment_anonymous")) return; |
$trigger = NULL; |
| 144 |
if ($user->uid != 0 && !_captcha_istrue("captcha_comment_registered")) return; |
|
| 145 |
|
foreach($user->roles as $role) { |
| 146 |
// include logic to remove captcha if the current entry is a valid captcha |
$candidate_trigger = $formid .'_'. strtr($role,' ','_') .'_captcha'; |
| 147 |
if (!$_SESSION['captcha_comment_correct'] && !($_POST['edit']['captcha_word'] != '' && _captcha_validate($_POST['edit']['captcha_word']))) { |
if (variable_get($candidate_trigger, NULL)) { |
| 148 |
$form['captcha'] = _captcha_form(); |
$trigger = $candidate_trigger; |
| 149 |
} |
} |
| 150 |
else { |
else { |
| 151 |
$_SESSION['captcha']=''; |
$flag = false; |
|
unset($form['captcha']); |
|
|
} |
|
| 152 |
break; |
break; |
| 153 |
|
} |
| 154 |
} |
} |
| 155 |
} |
|
| 156 |
|
if ($flag && isset($trigger)) { |
| 157 |
function _captcha_validate($string) { |
if ($captcha_type = _captcha_load()) { |
| 158 |
|
$form['#submit'] = array('captcha_submit' => array()) + $form['#submit']; |
| 159 |
$captcha_word = drupal_strtolower($string); |
if (!_captcha_validate($_POST['edit']['captcha_response'])) { |
| 160 |
if ($captcha_word != $_SESSION['captcha']) { |
call_user_func_array('_captcha_'. $captcha_type .'_challenge', array(&$form, &$_SESSION['captcha'])); |
| 161 |
return false; |
} |
| 162 |
|
} |
| 163 |
} |
} |
|
|
|
|
return true; |
|
| 164 |
} |
} |
| 165 |
|
|
| 166 |
|
|
| 167 |
/** |
/** |
| 168 |
* Returns a random string for use in a captcha |
* On submit, captcha is reset |
| 169 |
*/ |
*/ |
| 170 |
function _captcha_code() { |
function captcha_submit() { |
| 171 |
|
if($_SESSION['captcha_correct']) { |
| 172 |
$consts='bcdgjxvmnprst'; |
unset($_SESSION['captcha_correct']); |
| 173 |
$vowels='aeiou'; |
unset($_SESSION['captcha']); |
| 174 |
|
} |
| 175 |
for ($x=0; $x < 6; $x++) { |
} |
|
mt_srand ((double) microtime() * 1000000); |
|
|
$const[$x] = drupal_substr($consts,mt_rand(0,drupal_strlen($consts)-1),1); |
|
|
$vow[$x] = drupal_substr($vowels,mt_rand(0,drupal_strlen($vowels)-1),1); |
|
|
} |
|
| 176 |
|
|
|
$string = $const[0] . $vow[0] .$const[2] . $const[1] . $vow[1] . $const[3] . $vow[3] . $const[4]; |
|
|
$string = drupal_substr($string,0,rand(5,8)); |
|
| 177 |
|
|
| 178 |
//everytime we create a new code, we write it to session |
function _captcha_validate($captcha_response) { |
|
$_SESSION['captcha'] = drupal_strtolower($string); |
|
| 179 |
|
|
| 180 |
return $string; |
if ($_SESSION['captcha_correct']) return TRUE; |
| 181 |
|
if (is_array($captcha_response)) $captcha_response = $captcha_response['#value']; |
| 182 |
|
if (trim($captcha_response) == '') return FALSE; |
| 183 |
|
|
| 184 |
|
global $user; |
| 185 |
|
$trigger = NULL; |
| 186 |
|
if ($captcha_type = _captcha_load()) { |
| 187 |
|
call_user_func_array('_captcha_'. $captcha_type .'_validate', array(&$captcha_response, &$_SESSION['captcha_correct'])); |
| 188 |
|
} |
| 189 |
|
|
| 190 |
|
return $_SESSION['captcha_correct']; |
| 191 |
} |
} |
| 192 |
|
|
|
/** |
|
|
* Returns a random string for use in a captcha |
|
|
*/ |
|
|
function _captcha_istrue($variable, $default="true") { |
|
|
return (variable_get($variable, "")== true); |
|
|
} |
|
| 193 |
|
|
| 194 |
/** |
/** |
| 195 |
* Returns an array of files with TTF extensions in the specified directory. |
* Returns an array of files with TTF extensions in the specified directory. |
| 209 |
return $filelist; |
return $filelist; |
| 210 |
} |
} |
| 211 |
|
|
| 212 |
|
function _captcha_call($func) { |
| 213 |
|
_captcha_load(); |
| 214 |
|
//if (function_exists($func)) call_user_func_array($func, array()); |
| 215 |
|
} |
| 216 |
|
|
| 217 |
/** |
/** |
| 218 |
* Prints an image containing a captcha code. |
* Loads the current captcha system into memory |
| 219 |
*/ |
*/ |
| 220 |
function _captcha_image() { |
function _captcha_load() { |
| 221 |
|
|
| 222 |
// there are a few hard coded functions I'd like to eliminate here, |
$captcha_type = variable_get("captcha_type", NULL); |
| 223 |
// but for the time being we'll let them be. |
$path = drupal_get_path('module', 'captcha'); |
| 224 |
|
include_once($path.'/captcha_'.$captcha_type.'.inc'); |
|
//if we don't have GD2 functions, we can't generate the image |
|
|
if (!function_exists('imagecreatetruecolor')) return; |
|
|
|
|
|
// Set headers |
|
|
header('Expires: Mon, 01 Jan 1997 05:00:00 GMT'); |
|
|
header('Cache-Control: no-store, no-cache, must-revalidate'); |
|
|
header('Cache-Control: post-check=0, pre-check=0', false); |
|
|
header('Pragma: no-cache'); |
|
|
|
|
|
header('Content-type: image/png'); |
|
|
|
|
|
$string = _captcha_code(); |
|
|
|
|
|
// set up image, the first number is the width and the second is the height |
|
|
$im = imagecreatetruecolor(180, 80); |
|
|
|
|
|
// creates two variables to store color |
|
|
$background = imagecolorallocate($im, rand(180, 250), rand(180, 250), rand(180, 250)); |
|
|
$foreground = imagecolorallocate($im, rand(0, 80), rand(0, 80), rand(0, 80)); |
|
|
|
|
|
// fill image with bgcolor |
|
|
imagefill($im, 0, 0, $background); |
|
|
|
|
|
// Get truetype font list |
|
|
$fonts = _captcha_font_list(); |
|
| 225 |
|
|
| 226 |
// writes string |
$function_challenge = '_captcha_'. $captcha_type .'_challenge'; |
| 227 |
if (function_exists(imagettftext) && count($fonts) > 0) { |
$function_validate = '_captcha_'. $captcha_type .'_validate'; |
| 228 |
|
|
| 229 |
// write text using a truetype font |
if(function_exists($function_challenge) && function_exists($function_validate)) { |
| 230 |
$charSize = 24; // font size |
return $captcha_type; |
| 231 |
$charWidth = 0; // width of previous character |
} |
| 232 |
$x = 10; // initial x position |
else return false; |
|
$y = 30; |
|
|
|
|
|
// iterate over characters |
|
|
for ($i=0;$i<drupal_strlen($string);$i++) { |
|
|
// define angle and position of character based on previous character dimension |
|
|
$x += ($charWidth * rand(1.0, 1.6)); |
|
|
$y += rand(-5,5); |
|
|
$charAngle = rand(-5,5); |
|
|
$charSize += rand(-2,2); |
|
|
$char = drupal_substr($string,$i,1); |
|
|
|
|
|
// select random font |
|
|
$font = $fonts[rand(0,count($fonts)-1)]; |
|
|
|
|
|
// draw character |
|
|
imagettftext($im,$charSize,$charAngle,$x,$y,$foreground,$font,$char); |
|
|
|
|
|
// capture character dimensions to increment x position |
|
|
$bbox = imagettfbbox($charSize,$charAngle,$font,$char); |
|
|
$charWidth = max($bbox[0],$bbox[2],$bbox[4],$bbox[6]) - min($bbox[0],$bbox[2],$bbox[4],$bbox[6]); |
|
|
} |
|
|
} |
|
|
|
|
|
else { |
|
|
// write text using a built-in font |
|
|
$x = 10; |
|
|
$y = 0; |
|
|
|
|
|
for ($i=0;$i<drupal_strlen($string);$i++) { |
|
|
imagestring($im,5,$x,$y,drupal_substr($string,$i,1),$foreground); |
|
|
$x += rand(10,15); |
|
|
$y += rand(-4,4); |
|
|
} |
|
|
|
|
|
} |
|
| 233 |
|
|
| 234 |
// strikethrough |
} |
|
imageline($im, rand(0, 120), rand(0, 120), rand(0, 120), rand(0, 120), $foreground); |
|
| 235 |
|
|
| 236 |
// rotate only if function is defined (many PHP installations have this function missing) |
/** |
| 237 |
if (function_exists('imagerotate')) { |
* Generates list of available captcha methods |
| 238 |
$im2 = imagerotate($im,rand(-20,45),$background); |
*/ |
| 239 |
imagedestroy($im); |
function _captcha_types() { |
| 240 |
$im = $im2; |
static $types; |
|
} |
|
| 241 |
|
|
| 242 |
// add cloud only if function is defined (many PHP installations have this function missing) |
if (!isset($types)) { |
| 243 |
if (function_exists('imagecolorallocatealpha')) { |
$types = array(); |
| 244 |
$middleground = imagecolorallocatealpha($im, rand(160, 200), rand(160, 200), rand(160, 200), 80); |
$path = drupal_get_path('module', 'captcha'); |
| 245 |
|
$files = file_scan_directory($path, '^captcha_.*\.inc$'); |
| 246 |
// random shapes |
foreach ($files as $filename => $file) { |
| 247 |
for ($x=0; $x<50;$x++) { |
include_once($filename); |
| 248 |
imageline($im, rand(0, 120), rand(0, 120), rand(0, 120), rand(0, 120), $middleground); |
$function_challenge = '_'. $file->name .'_challenge'; |
| 249 |
imageellipse($im, rand(0, 120), rand(0, 120), rand(0, 120), rand(0, 120), $middleground); |
$function_validate = '_'. $file->name .'_validate'; |
| 250 |
|
if(function_exists($function_challenge) && function_exists($function_validate)) { |
| 251 |
|
$types[] = substr($file->name, 8); |
| 252 |
} |
} |
| 253 |
} |
} |
| 254 |
|
} |
| 255 |
//output to browser |
//post process types |
| 256 |
imagepng($im); |
foreach($types as $type) { |
| 257 |
imagedestroy($im); |
$r_types[$type] = $type; |
| 258 |
|
} |
| 259 |
|
return $r_types; |
| 260 |
} |
} |
| 261 |
|
|
| 262 |
?> |
?> |