View source
<?php
function math_captcha_menu($may_cache) {
$items = array();
if ($may_cache) {
$items[] = array(
'path' => 'admin/user/captcha/math_captcha',
'title' => t('Math CAPTCHA'),
'callback' => 'drupal_get_form',
'callback arguments' => array(
'math_captcha_settings_form',
),
'type' => MENU_LOCAL_TASK,
);
}
return $items;
}
function _math_captcha_enabled_challenges() {
$enabled = variable_get('math_captcha_enabled_challenges', array(
'addition' => 'addition',
'subtraction' => 'subtraction',
'multiplication' => 'multiplication',
));
return $enabled;
}
function math_captcha_settings_form() {
$form = array();
$enabled_challenges = _math_captcha_enabled_challenges();
$form['math_captcha_enabled_challenges'] = array(
'#type' => 'checkboxes',
'#title' => t('Enabled math challenges'),
'#options' => array(
'addition' => t('Addition: x + y = z'),
'subtraction' => t('Subtraction: x - y = z'),
'multiplication' => t('Multiplication: x * y = z'),
),
'#default_value' => $enabled_challenges,
'#description' => t('Select the math challenges you want to enable.'),
);
$form['math_captcha_textual_numbers'] = array(
'#type' => 'checkbox',
'#title' => 'Textual representation of numbers',
'#default_value' => variable_get('math_captcha_textual_numbers', TRUE),
'#description' => t('When enabled, the numbers in the challenge will get a textual representation if available. E.g. "four" instead of "4".'),
);
$form['math_captcha_textual_operators'] = array(
'#type' => 'checkbox',
'#title' => 'Textual representation of operators',
'#default_value' => variable_get('math_captcha_textual_operators', FALSE),
'#description' => t('When enabled, the operators in the challenge will get a textual representation if available. E.g. "plus" instead of "+".'),
);
$form['math_captcha_addition'] = array(
'#type' => 'fieldset',
'#title' => t('Addition challenge: x + y = z'),
);
$form['math_captcha_addition']['math_captcha_addition_argmax'] = array(
'#type' => 'textfield',
'#title' => t('Maximum value for x and y'),
'#default_value' => variable_get('math_captcha_addition_argmax', 10),
'#maxlength' => 3,
'#size' => 3,
);
$form['math_captcha_addition']['math_captcha_addition_allow_negative'] = array(
'#type' => 'checkbox',
'#title' => t('Allow negative values for x and y'),
'#default_value' => variable_get('math_captcha_addition_allow_negative', FALSE),
);
$form['math_captcha_subtraction'] = array(
'#type' => 'fieldset',
'#title' => t('Subtraction challenge: x - y = z'),
);
$form['math_captcha_subtraction']['math_captcha_subtraction_argmax'] = array(
'#type' => 'textfield',
'#title' => t('Maximum value for x and y'),
'#default_value' => variable_get('math_captcha_subtraction_argmax', 10),
'#maxlength' => 3,
'#size' => 3,
);
$form['math_captcha_subtraction']['math_captcha_subtraction_allow_negative'] = array(
'#type' => 'checkbox',
'#title' => t('Allow negative values for x, y and z'),
'#default_value' => variable_get('math_captcha_subtraction_allow_negative', FALSE),
);
$form['math_captcha_multiplication'] = array(
'#type' => 'fieldset',
'#title' => t('Multiplication challenge: x * y = z'),
);
$form['math_captcha_multiplication']['math_captcha_multiplication_argmax'] = array(
'#type' => 'textfield',
'#title' => t('Maximum value for x and y'),
'#default_value' => variable_get('math_captcha_multiplication_argmax', 5),
'#maxlength' => 3,
'#size' => 3,
);
$form['math_captcha_multiplication']['math_captcha_multiplication_allow_negative'] = array(
'#type' => 'checkbox',
'#title' => t('Allow negative values for x, y'),
'#default_value' => variable_get('math_captcha_multiplication_allow_negative', FALSE),
);
return system_settings_form($form);
}
function math_captcha_settings_form_validate($form_id, $form_values) {
if ($form_id == 'math_captcha_settings_form') {
if ($form_values['math_captcha_enabled_challenges'][0]) {
form_set_error('math_captcha_enabled_challenges', t('You should select at least one type of math challenges.'));
}
$argmaxs = array(
'math_captcha_addition_argmax',
'math_captcha_subtraction_argmax',
'math_captcha_multiplication_argmax',
);
foreach ($argmaxs as $argmax) {
if (!is_numeric($form_values[$argmax])) {
form_set_error($argmax, t('Maximum value should be an integer.'));
}
else {
if (intval($form_values[$argmax]) < 2) {
form_set_error($argmax, t('Maximum value should be an integer and at least 2'));
}
}
}
}
}
function _math_captcha_repr($n, $add_paratheses_when_negative = FALSE) {
$t = "{$n}";
if (variable_get('math_captcha_textual_numbers', TRUE)) {
$repr_map = array(
0 => t('zero'),
1 => t('one'),
2 => t('two'),
3 => t('three'),
4 => t('four'),
5 => t('five'),
6 => t('six'),
7 => t('seven'),
8 => t('eight'),
9 => t('nine'),
10 => t('ten'),
11 => t('eleven'),
12 => t('twelve'),
13 => t('thirteen'),
14 => t('fourteen'),
15 => t('fifteen'),
);
if (array_key_exists(abs($n), $repr_map)) {
$t = $repr_map[abs($n)];
if ($n < 0) {
$t = t('minus !number', array(
'!number' => $t,
));
}
}
}
if ($add_paratheses_when_negative && $n < 0) {
$t = "({$t})";
}
return $t;
}
function _math_captcha_repr_op($op) {
$t = "{$op}";
if (variable_get('math_captcha_textual_operators', FALSE)) {
$repr_map = array(
'+' => t('plus'),
'-' => t('minus'),
'*' => t('times'),
'=' => t('equals'),
);
if (array_key_exists($op, $repr_map)) {
$t = $repr_map[$op];
}
}
return $t;
}
function _math_captcha_build_captcha($x, $y, $operator, $result, $maxlength = 3) {
$form_item = array();
$form_item['form']['captcha_response'] = array(
'#type' => 'textfield',
'#title' => t('Math question'),
'#required' => TRUE,
'#size' => $maxlength + 2,
'#maxlength' => $maxlength,
'#description' => t('Solve this math question and enter the solution with digits. E.g. for "two plus four = ?" enter "6".'),
);
switch (mt_rand(0, 2)) {
case 0:
$form_item['solution'] = "{$result}";
$form_item['form']['captcha_response']['#field_prefix'] = _math_captcha_repr($x, TRUE) . ' ' . _math_captcha_repr_op($operator) . ' ' . _math_captcha_repr($y, TRUE) . ' ' . _math_captcha_repr_op('=');
break;
case 1:
$form_item['solution'] = "{$y}";
$form_item['form']['captcha_response']['#field_prefix'] = _math_captcha_repr($x, TRUE) . ' ' . _math_captcha_repr_op($operator) . ' ';
$form_item['form']['captcha_response']['#field_suffix'] = ' ' . _math_captcha_repr_op('=') . ' ' . _math_captcha_repr($result);
break;
case 2:
$form_item['solution'] = "{$x}";
$form_item['form']['captcha_response']['#field_suffix'] = ' ' . _math_captcha_repr_op($operator) . ' ' . _math_captcha_repr($y, TRUE) . ' ' . _math_captcha_repr_op('=') . ' ' . _math_captcha_repr($result);
break;
}
return $form_item;
}
function _math_captcha_addition_challenge() {
$argmax = intval(variable_get('math_captcha_addition_argmax', 10));
if (variable_get('math_captcha_addition_allow_negative', FALSE)) {
$x = mt_rand(-$argmax, $argmax);
$y = mt_rand(-$argmax, $argmax);
}
else {
$x = mt_rand(0, $argmax);
$y = mt_rand(0, $argmax);
}
$solution = $x + $y;
$maxlength = strlen(strval($argmax + $argmax)) + intval(variable_get('math_captcha_addition_allow_negative', FALSE));
return _math_captcha_build_captcha($x, $y, '+', $solution, $maxlength);
}
function _math_captcha_subtraction_challenge() {
$argmax = intval(variable_get('math_captcha_subtraction_argmax', 10));
if (variable_get('math_captcha_subtraction_allow_negative', FALSE)) {
$x = mt_rand(-$argmax, $argmax);
$y = mt_rand(-$argmax, $argmax);
}
else {
$y = mt_rand(0, $argmax);
$x = mt_rand($y, $argmax);
}
$solution = $x - $y;
$maxlength = strlen(strval($argmax + $argmax)) + intval(variable_get('math_captcha_subtraction_allow_negative', FALSE));
return _math_captcha_build_captcha($x, $y, '-', $solution, $maxlength);
}
function _math_captcha_multiplication_challenge() {
$argmax = intval(variable_get('math_captcha_multiplication_argmax', 5));
$x = mt_rand(1, $argmax);
$y = mt_rand(1, $argmax);
if (variable_get('math_captcha_multiplication_allow_negative', FALSE)) {
$x = $x * (mt_rand(0, 1) * 2 - 1);
$y = $y * (mt_rand(0, 1) * 2 - 1);
}
$solution = $x * $y;
$maxlength = strlen(strval($argmax * $argmax)) + intval(variable_get('math_captcha_multiplication_allow_negative', FALSE));
return _math_captcha_build_captcha($x, $y, '*', $solution, $maxlength);
}
function math_captcha_captcha($op, $captcha_type = '') {
switch ($op) {
case 'list':
return array(
'Math CAPTCHA',
);
case 'generate':
if ($captcha_type == 'Math CAPTCHA') {
$challenges = array_filter(_math_captcha_enabled_challenges());
$challenge = $challenges[array_rand($challenges)];
$form_item = call_user_func("_math_captcha_{$challenge}_challenge");
return $form_item;
}
}
}