Commit 10827c61 authored by soxofaan's avatar soxofaan

also made Image CAPTCHA free of session dependencies, yay

parent d2dfa333
......@@ -297,7 +297,19 @@ function captcha_point_disable_confirm_submit($form, &$form_state) {
}
/**
* Funtion for generating a page with CAPTCHA examples
* Helper function for generating an example challenge.
*/
function _captcha_generate_example_challenge($module, $type) {
$captcha_sid = _captcha_generate_captcha_session(CAPTCHA_STATUS_EXAMPLE);
$captcha = call_user_func_array($module .'_captcha', array('generate', $type, $captcha_sid));
_captcha_update_captcha_session($captcha_sid, $captcha['solution']);
$captcha['form']['captcha_response']['#default_value'] = $captcha['solution'];
return $captcha['form'];
}
/**
* Funtion for generating a page with CAPTCHA examples.
*
* If the arguments $module and $challenge are not set, generate a list with
* examples of the available CAPTCHA types.
* If $module and $challenge are set, generate 10 examples of the concerning
......@@ -306,12 +318,9 @@ function captcha_point_disable_confirm_submit($form, &$form_state) {
function captcha_examples($form_state, $module, $challenge) {
$form = array();
if ($module && $challenge) {
// generate 10 examples
// Generate 10 example challenges.
for ($i=0; $i<10; $i++) {
// generate CAPTCHA
$captcha = call_user_func_array($module .'_captcha', array('generate', $challenge));
// add form elements
$form["challenge_{$i}"] = $captcha['form'];
$form["challenge_{$i}"] = _captcha_generate_example_challenge($module, $challenge);
}
}
else {
......@@ -323,13 +332,10 @@ function captcha_examples($form_state, $module, $challenge) {
$challenges = call_user_func_array($module .'_captcha', 'list');
if ($challenges) {
foreach ($challenges as $ckey => $challenge) {
// generate CAPTCHA
$captcha = call_user_func_array($module .'_captcha', array('generate', $challenge));
// build form
$form["captcha_{$mkey}_{$ckey}"] = array(
'#type' => 'fieldset',
'#title' => t('Challenge "%challenge" by module "%module"', array('%challenge' => $challenge, '%module' => $module)),
'challenge' => $captcha['form'],
'challenge' => _captcha_generate_example_challenge($module, $challenge),
'more_examples' => array(
'#value' => l(t('10 more examples of this challenge.'), "admin/user/captcha/captcha/examples/$module/$challenge"),
),
......
......@@ -171,7 +171,7 @@ function captcha_form_alter(&$form, $form_state, $form_id) {
if (!user_access('skip CAPTCHA')) {
// Visitor does not have permission to skip the CAPTCHA
require_once('captcha.pages.inc');
require_once('./'. drupal_get_path('module', 'captcha') .'/captcha.pages.inc');
_captcha_form_alter_untrusted_user($form, $form_state, $form_id);
}
elseif (user_access('administer CAPTCHA settings') && variable_get('captcha_administration_mode', FALSE) && arg(0) != 'admin') {
......@@ -212,6 +212,23 @@ function captcha_form_alter(&$form, $form_state, $form_id) {
}
}
/**
* Helper function for generating a new CAPTCHA session ID
*/
function _captcha_generate_captcha_session($status=CAPTCHA_STATUS_UNSOLVED) {
global $user;
db_query("INSERT into {captcha_sessions} (uid, sid, ip_address, timestamp, form_id, solution, status, attempts) VALUES (%d, '%s', '%s', %d, '%s', '%s', %d, %d)", $user->uid, session_id(), ip_address(), time(), $form_id, '', $status, 0);
$captcha_sid = db_last_insert_id('captcha_sessions', 'csid');
return $captcha_sid;
}
/**
* Helper function for updating the solution in the CAPTCHA session table.
*/
function _captcha_update_captcha_session($captcha_sid, $solution) {
db_query("UPDATE {captcha_sessions} SET timestamp=%d, solution='%s' WHERE csid=%d", time(), $solution, $captcha_sid);
}
/**
* Default implementation of hook_captcha
*/
......
<?php
// $Id$
/**
* Form alter phase of form processing for untrusted users.
*/
......@@ -26,16 +25,15 @@ function _captcha_form_alter_untrusted_user(&$form, $form_state, $form_id) {
&& isset($form_state['post']['captcha_sid'])) {
$captcha_sid = $form_state['post']['captcha_sid'];
} else {
// New CAPTCHA session.
global $user;
db_query("INSERT into {captcha_sessions} (uid, sid, ip_address, timestamp, form_id, solution, status, attempts) VALUES (%d, '%s', '%s', %d, '%s', '%s', %d, %d)", $user->uid, session_id(), ip_address(), time(), $form_id, '', CAPTCHA_STATUS_UNSOLVED, 0);
$captcha_sid = db_last_insert_id('captcha_sessions', 'csid');
// Generate new CAPTCHA session.
$captcha_sid = _captcha_generate_captcha_session(CAPTCHA_STATUS_UNSOLVED);
}
if (_captcha_required_for_user($captcha_sid, $form_id)) {
// Generate a CAPTCHA and its solution
$captcha = module_invoke($captcha_point->module, 'captcha', 'generate', $captcha_point->type);
// Generate a CAPTCHA and its solution (note that the CAPTCHA session ID
// is given as thrid argument.
$captcha = module_invoke($captcha_point->module, 'captcha', 'generate', $captcha_point->type, $captcha_sid);
if (!$captcha) {
// The selected module returned nothing, maybe it is disabled or it's wrong, we should watchdog that and then quit.
watchdog('CAPTCHA',
......@@ -109,18 +107,19 @@ function _captcha_form_alter_untrusted_user(&$form, $form_state, $form_id) {
function _captcha_required_for_user($captcha_sid, $form_id) {
$captcha_session_status = db_result(db_query("SELECT status FROM {captcha_sessions} WHERE csid = %d", $captcha_sid));
$captcha_success_form_ids = (array)($_SESSION['captcha_success_form_ids']);
switch (variable_get('captcha_persistence', CAPTCHA_PERSISTENCE_SHOW_ALWAYS)) {
case CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL:
$captcha_persistence_status = isset($_SESSION['captcha_success_form_ids']) && (count($_SESSION['captcha_success_form_ids']) > 0);
$captcha_persistence_status = (count($captcha_success_form_ids) > 0);
break;
case CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM:
$captcha_persistence_status = isset($_SESSION['captcha_success_form_ids'][$form_id]);
$captcha_persistence_status = isset($captcha_success_form_ids[$form_id]);
break;
default:
$captcha_persistence_status = FALSE;
}
return !($captcha_session_status || $captcha_persistence_status);
return ($captcha_session_status == CAPTCHA_STATUS_UNSOLVED) && !$captcha_persistence_status;
}
/**
......@@ -141,16 +140,14 @@ function captcha_validate($form, &$form_state) {
// the csid of the posted form.
$csid = $form_state['clicked_button']['#post']['captcha_sid'];
$solution = db_result(db_query('SELECT solution FROM {captcha_sessions} WHERE csid = %d', $csid));
$solution = db_result(db_query('SELECT solution FROM {captcha_sessions} WHERE csid = %d, status = %d', $csid, CAPTCHA_STATUS_UNSOLVED));
if ($solution === FALSE) {
// unknown challenge_id
// Unknown challenge_id.
form_set_error('captcha', t('CAPTCHA test failed (unknown csid).'));
}
else {
// Unset the solution to prevent reuse of the same CAPTCHA solution
// Check answer
// Check answer.
if ($captcha_response == $solution) {
// Correct answer.
$_SESSION['captcha_success_form_ids'][$form_id] = $form_id;
......@@ -197,7 +194,7 @@ function captcha_pre_render_untrusted_user($form) {
if (_captcha_required_for_user($captcha_sid, $form_id)) {
// Update captcha_sessions table.
db_query("UPDATE {captcha_sessions} SET timestamp=%d, solution='%s' WHERE csid=%d", time(), $captcha_info['solution'], $captcha_sid);
_captcha_update_captcha_session($captcha_sid, $captcha_info['solution']);
}
else {
// Remove CAPTCHA widgets from form.
......
......@@ -46,7 +46,7 @@ function image_captcha_settings_form() {
$form['image_captcha_code_settings']['image_captcha_case_insensitive'] = array(
'#type' => 'checkbox',
'#title' => t('Case insensitive validation'),
'#description' => t('Enable this option to ignore uppercase/lowercase errors in the response. This can be usefull for adapting the challenge to your audience or for certain fonts where the differences between upper and lower case are too small.'),
'#description' => t('Enable this option to ignore uppercase/lowercase errors in the response. This can be usefull for certain target audiences or fonts.'),
'#default_value' => variable_get('image_captcha_case_insensitive', FALSE),
);
......
......@@ -5,7 +5,7 @@
* Implementation of image CAPTCHA for use with the CAPTCHA module
*/
define('IMAGE_CAPTCHA_ALLOWED_CHARACTERS', 'aAbBCdEeFfGHhijKLMmNPQRrSTtWXYZ23456789%$#!@+?*');
define('IMAGE_CAPTCHA_ALLOWED_CHARACTERS', 'aAbBCdEeFfGHhijKLMmNPQRrSTtWXYZ23456789');
/**
* Implementation of hook_help().
......@@ -15,8 +15,9 @@ function image_captcha_help($path, $arg) {
case 'admin/user/captcha/image_captcha':
$output = '<p>'. t('The image CAPTCHA is a popular challenge where a random textual code is obfuscated in an image. The image is generated on the fly for each request, which is rather CPU intensive for the server. Be careful with the size and computation related settings.') .'</p>';
if (in_array('Image', image_captcha_captcha('list'))) {
$result = image_captcha_captcha('generate', 'Image');
$img = $result['form']['captcha_image']['#value'];
require_once('./'. drupal_get_path('module', 'captcha') .'/captcha.admin.inc');
$captcha = _captcha_generate_example_challenge('image_captcha', 'Image');
$img = $captcha['captcha_image']['#value'];
$output .= t('<p>Example image, generated with the current settings:</p>!img', array('!img' => $img));
}
return $output;
......@@ -102,7 +103,7 @@ function _image_captcha_utf8_split($str) {
/**
* Implementation of hook_captcha
*/
function image_captcha_captcha($op, $captcha_type='', $response='') {
function image_captcha_captcha($op, $captcha_type='', $arg3='') {
switch ($op) {
case 'list':
// only offer image CAPTCHA if possible to generate an image CAPTCHA
......@@ -131,9 +132,7 @@ function image_captcha_captcha($op, $captcha_type='', $response='') {
$code .= $allowed_chars[array_rand($allowed_chars)];
}
// store the answer in $_SESSION for the image generator function (which happens in another http request)
$seed = mt_rand();
$_SESSION['image_captcha'][$seed] = $code;
$captcha_sid = $arg3;
// build the result to return
$result = array();
......@@ -143,16 +142,20 @@ function image_captcha_captcha($op, $captcha_type='', $response='') {
if (variable_get('image_captcha_case_insensitive', FALSE)) {
$code = strtolower($code);
$result['preprocess'] = TRUE;
$description = t('Enter the characters shown in the image without spaces.');
$description = t('Enter the characters (without spaces) shown in the image.');
}
else {
$description = t('Enter the characters shown in the image without spaces, also respect upper and lower case.');
$description = t('Enter the characters shown in the image. Ignore spaces and be careful about upper and lower case.');
}
$result['solution'] = $code;
// Generate image source URL (add timestamp to avoid problems with
// client side caching: subsequent images of the same CAPTCHA session
// have the same URL, but should display a different code).
$img_src = check_url(url("image_captcha/$captcha_sid/". time()));
$result['form']['captcha_image'] = array(
'#type' => 'markup',
'#value' => '<img src="'. check_url(url("image_captcha/$seed")) .'" alt="'. t('Image CAPTCHA') .'" title="'. t('Image CAPTCHA') .'" />',
'#value' => '<img src="'. $img_src .'" alt="'. t('Image CAPTCHA') .'" title="'. t('Image CAPTCHA') .'" />',
'#weight' => -2,
);
$result['form']['captcha_response'] = array(
......@@ -167,9 +170,9 @@ function image_captcha_captcha($op, $captcha_type='', $response='') {
}
case 'preprocess':
// Preprocessing the response for case insesitive validation
// Preprocessing the response for case insensitive validation (see above).
if ($captcha_type == 'Image') {
return strtolower($response);
return strtolower($arg3);
}
break;
}
......
......@@ -9,17 +9,18 @@
*/
/**
* menu callback function that generates the CAPTCHA image
* Menu callback function that generates the CAPTCHA image.
*/
function image_captcha_image($seed=NULL) {
if (!$seed) {
return;
function image_captcha_image($captcha_sid=NULL) {
if (!$captcha_sid) {
exit();
}
// Get solution (the code to show).
$code = db_result(db_query("SELECT solution FROM {captcha_sessions} WHERE csid = %d", (int)($captcha_sid)));
// Only generate captcha if code exists in the session.
if (isset($_SESSION['image_captcha'][$seed])) {
$code = $_SESSION['image_captcha'][$seed];
// Unset the code from $_SESSION to prevent rerendering the CAPTCHA.
unset($_SESSION['image_captcha'][$seed]);
if ($code !== FALSE) {
// generate the image
$image = @_image_captcha_generate_image($code);
// check of generation was successful
......@@ -38,8 +39,8 @@ function image_captcha_image($seed=NULL) {
imagejpeg($image);
// Clean up
imagedestroy($image);
exit();
}
exit();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment