summaryrefslogtreecommitdiffstats
path: root/math_captcha/math_captcha.challenge.inc
blob: 43bc3523eeb8818efbcca983ed8457a30c3d980d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
<?php

/**
 * function for addition challenges
 */
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 for subtraction challenges
 */
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 for multiplication challenges
 */
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);
}

/**
 * helper function to build a math CAPTCHA form item
 */
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: // question like "x + y = ?"
      $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: // question like "x + ? = z"
      $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: // question like "? + y = z"
      $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;
}

/**
 * Helper function for transforming a number to a textual representation
 */
function _math_captcha_repr($n, $add_paratheses_when_negative=FALSE) {
  // start with no textual representation
  $t = "$n";
  // if enabled and available: do textual representation
  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) {
  // start with no textual representation
  $t = "$op";
  // if enabled and available: do textual representation
  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;
}