1
|
<?php
|
2
|
|
3
|
/**
|
4
|
* @file
|
5
|
* All code for the Hidden CAPTCHA module, except installation-related code.
|
6
|
*/
|
7
|
|
8
|
/**
|
9
|
* Implements hook_help().
|
10
|
*/
|
11
|
function hidden_captcha_help($path, $arg) {
|
12
|
switch ($path) {
|
13
|
case 'admin/config/people/captcha/hidden_captcha':
|
14
|
return '<p>' . t('This CAPTCHA presents a text field that we expect no one to fill. The text field can be given any name and will be hidden from view using CSS.') . '</p>';
|
15
|
}
|
16
|
}
|
17
|
|
18
|
/**
|
19
|
* Implements hook_menu().
|
20
|
*/
|
21
|
function hidden_captcha_menu() {
|
22
|
$items = array();
|
23
|
$items['admin/config/people/captcha/hidden_captcha'] = array(
|
24
|
'title' => 'Hidden CAPTCHA',
|
25
|
'page callback' => 'drupal_get_form',
|
26
|
'page arguments' => array('hidden_captcha_settings_form'),
|
27
|
'access arguments' => array('administer CAPTCHA settings'),
|
28
|
'type' => MENU_LOCAL_TASK,
|
29
|
'weight' => -10,
|
30
|
);
|
31
|
return $items;
|
32
|
}
|
33
|
|
34
|
/**
|
35
|
* Function for the hidden captcha settings form.
|
36
|
*/
|
37
|
function hidden_captcha_settings_form() {
|
38
|
$form = array();
|
39
|
$form['hidden_captcha_label'] = array(
|
40
|
'#type' => 'textfield',
|
41
|
'#title' => t('Hidden text field label'),
|
42
|
'#description' => t("This is the hidden captcha form field's label, describing the expected input.<br /><strong>It is highly recommended to change it!</strong><br />The label should be as \"machine-readable\" as possible, encouraging spambots to fill in the field. An example might be a simple math challenge.<br />The label will only be visible to people who do not have CSS enabled and to robots."),
|
43
|
'#default_value' => variable_get('hidden_captcha_label', 'Website URL'),
|
44
|
);
|
45
|
return system_settings_form($form);
|
46
|
}
|
47
|
|
48
|
/**
|
49
|
* Implements hook_captcha().
|
50
|
*/
|
51
|
function hidden_captcha_captcha($op, $captcha_type = '') {
|
52
|
switch ($op) {
|
53
|
case 'list':
|
54
|
return array('Hidden CAPTCHA');
|
55
|
|
56
|
case 'generate':
|
57
|
if ($captcha_type == 'Hidden CAPTCHA') {
|
58
|
$captcha = array();
|
59
|
$captcha['solution'] = '';
|
60
|
|
61
|
// Ensure this captcha is cacheable.
|
62
|
// @see https://www.drupal.org/project/captcha/issues/2449209
|
63
|
$captcha['cacheable'] = TRUE;
|
64
|
|
65
|
// The CAPTCHA solution provided by hook_captcha() is updated in the
|
66
|
// 'captcha_session' table on pre-render phase of element process.
|
67
|
// @see captcha_pre_render_process()
|
68
|
// @see _captcha_update_captcha_session()
|
69
|
// However, if the cache is enabled, solution would be empty for the
|
70
|
// first attempt of the cached form. For the next attempt, there will
|
71
|
// not be any 'sid' in form_state
|
72
|
// (i.e. $form_state['captcha_info']['captcha_sid'] = null).
|
73
|
// So a new solution would get generated at captcha_element_process().
|
74
|
// The default 'captcha_validate' function,
|
75
|
// captcha_validate_strict_equality(), would fail in this case.
|
76
|
// @see captcha_validate()
|
77
|
// Adding custom validation function to check solution is always empty.
|
78
|
$captcha['captcha_validate'] = 'hidden_captcha_captcha_validate';
|
79
|
|
80
|
$captcha['form']['captcha_response'] = array(
|
81
|
'#type' => 'textfield',
|
82
|
'#title' => variable_get('hidden_captcha_label', 'Website URL'),
|
83
|
'#required' => FALSE,
|
84
|
'#attributes' => array('tabindex' => '-1'),
|
85
|
);
|
86
|
return $captcha;
|
87
|
}
|
88
|
break;
|
89
|
}
|
90
|
}
|
91
|
|
92
|
/**
|
93
|
* CAPTCHA validation callback; checks that the response is empty.
|
94
|
*/
|
95
|
function hidden_captcha_captcha_validate($solution, $captcha_response, $element, $form_state) {
|
96
|
return $captcha_response === '';
|
97
|
}
|
98
|
|
99
|
/**
|
100
|
* Implements hook_theme().
|
101
|
*/
|
102
|
function hidden_captcha_theme() {
|
103
|
return array(
|
104
|
'captcha' => array(
|
105
|
'arguments' => array('element' => NULL),
|
106
|
'function' => 'theme_hidden_captcha_captcha',
|
107
|
),
|
108
|
);
|
109
|
}
|
110
|
|
111
|
/**
|
112
|
* Implements theme_hook().
|
113
|
*/
|
114
|
function theme_hidden_captcha_captcha($element) {
|
115
|
$captcha = theme_captcha($element);
|
116
|
if (strncmp($element["element"]["#captcha_type"], "hidden_captcha/", 15) == 0) {
|
117
|
// Generate a random class name.
|
118
|
$chars = "abcdfghjkmnpqrstvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
119
|
$class = "";
|
120
|
for ($i = 0; $i < 64; ++$i) {
|
121
|
$class .= substr($chars, rand(0, strlen($chars) - 1), 1);
|
122
|
}
|
123
|
// Hide the random class via CSS.
|
124
|
// @todo Move the random class to an external file.
|
125
|
drupal_add_css(".$class{width:0;height:0;overflow:hidden;}", "inline");
|
126
|
// HTML for the captcha.
|
127
|
$captcha = "<div class=\"$class\">" . $captcha . "</div>";
|
128
|
}
|
129
|
return $captcha;
|
130
|
}
|