1
|
|
2
|
This documentation is for developers that want to implement their own
|
3
|
challenge type and integrate it with the base CAPTCHA module.
|
4
|
|
5
|
|
6
|
=== Required: hook_captcha($op, $captcha_type='') ===
|
7
|
|
8
|
The hook_captcha() hook is the only required function if you want to integrate
|
9
|
with the base CAPTCHA module.
|
10
|
Functionality depends on the first argument $op:
|
11
|
* 'list': you should return an array of possible challenge types
|
12
|
that your module implements.
|
13
|
* 'generate': generate a challenge.
|
14
|
You should return an array that offers form elements and the solution
|
15
|
of your challenge, defined by the second argument $captcha_type.
|
16
|
The returned array $captcha should have the following items:
|
17
|
$captcha['solution']: this is the solution of your challenge
|
18
|
$captcha['form']: an array of the form elements you want to add to the form.
|
19
|
There should be a key 'captcha_response' in this array, which points to
|
20
|
the form element where the user enters his answer.
|
21
|
An optional additional argument $captcha_sid with the captcha session ID is
|
22
|
available for more advanced challenges (e.g. the image CAPTCHA uses this
|
23
|
argument, see image_captcha_captcha()).
|
24
|
|
25
|
Let's give a simple example to make this more clear.
|
26
|
We create the challenge 'Foo CAPTCHA', which requires the user to
|
27
|
enter "foo" in a textfield.
|
28
|
|
29
|
"""
|
30
|
/**
|
31
|
* Implementation of hook_captcha().
|
32
|
*/
|
33
|
function foo_captcha_captcha($op, $captcha_type='') {
|
34
|
switch ($op) {
|
35
|
case 'list':
|
36
|
return array('Foo CAPTCHA');
|
37
|
case 'generate':
|
38
|
if ($captcha_type == 'Foo CAPTCHA') {
|
39
|
$captcha = array();
|
40
|
$captcha['solution'] = 'foo';
|
41
|
$captcha['form']['captcha_response'] = array(
|
42
|
'#type' => 'textfield',
|
43
|
'#title' => t('Enter "foo"'),
|
44
|
'#required' => TRUE,
|
45
|
);
|
46
|
return $captcha;
|
47
|
}
|
48
|
break;
|
49
|
}
|
50
|
}
|
51
|
"""
|
52
|
|
53
|
Validation of the answer against the solution and other stuff is done by the
|
54
|
base CAPTCHA module.
|
55
|
|
56
|
|
57
|
|
58
|
|
59
|
=== Required: the .info file ===
|
60
|
|
61
|
You should specify that your module depends on the base CAPTCHA module.
|
62
|
Optionally you could put your module in the "Spam control" package.
|
63
|
|
64
|
For our simple foo CAPTCHA module this would mean the following lines in the
|
65
|
file foo_captcha.info:
|
66
|
|
67
|
"""
|
68
|
name = "Foo CAPTCHA"
|
69
|
description = "The foo CAPTCHA requires the user to enter the word 'foo'."
|
70
|
package = "Spam control"
|
71
|
dependencies[] = captcha
|
72
|
core = 6.x
|
73
|
"""
|
74
|
|
75
|
|
76
|
|
77
|
|
78
|
=== Recommended: hook_menu($may_cache) ===
|
79
|
|
80
|
More advanced CAPTCHA modules probably want some configuration page.
|
81
|
To integrate nicely with the base CAPTCHA module you should offer your
|
82
|
configuration page as a MENU_LOCAL_TASK menu entry under 'admin/config/people/captcha/'.
|
83
|
|
84
|
For our simple foo CAPTCHA module this would mean:
|
85
|
|
86
|
"""
|
87
|
/**
|
88
|
* Implementation of hook_menu().
|
89
|
*/
|
90
|
function foo_captcha_menu($may_cache) {
|
91
|
$items = array();
|
92
|
if ($may_cache) {
|
93
|
$items['admin/config/people/captcha/foo_captcha'] = array(
|
94
|
'title' => t('Foo CAPTCHA'),
|
95
|
'page callback' => 'drupal_get_form',
|
96
|
'page arguments' => array('foo_captcha_settings_form'),
|
97
|
'type' => MENU_LOCAL_TASK,
|
98
|
);
|
99
|
}
|
100
|
return $items;
|
101
|
}
|
102
|
"""
|
103
|
|
104
|
You should of course implement a function foo_captcha_settings_form() which
|
105
|
returns the form of your configuration page.
|
106
|
|
107
|
|
108
|
|
109
|
|
110
|
=== Optional: hook_help($section) ===
|
111
|
To offer a description/explanation of your challenge, you can use the
|
112
|
normal hook_help() system.
|
113
|
|
114
|
For our simple foo CAPTCHA module this would mean:
|
115
|
|
116
|
"""
|
117
|
/**
|
118
|
* Implementation of hook_help().
|
119
|
*/
|
120
|
function foo_captcha_help($path, $arg) {
|
121
|
switch ($path) {
|
122
|
case 'admin/config/people/captcha/foo_captcha':
|
123
|
return '<p>'. t('This is a very simple challenge, which requires users to enter "foo" in a textfield.') .'</p>';
|
124
|
}
|
125
|
}
|
126
|
"""
|
127
|
|
128
|
|
129
|
|
130
|
=== Optional: custom response validation ===
|
131
|
The CAPTCHA module provides an option for case sensitive and case insensitve
|
132
|
validation of the responses. If this is not sufficient, you can provide
|
133
|
your own validation function with the 'captcha_validate' field, illustrated
|
134
|
by the following example:
|
135
|
|
136
|
"""
|
137
|
/**
|
138
|
* Implementation of hook_captcha().
|
139
|
*/
|
140
|
function foo_captcha_captcha($op, $captcha_type='') {
|
141
|
switch ($op) {
|
142
|
...
|
143
|
case 'generate':
|
144
|
if ($captcha_type == 'Foo CAPTCHA') {
|
145
|
$captcha = array();
|
146
|
$captcha['solution'] = ...
|
147
|
$captcha['form'] = ...
|
148
|
$captcha['captcha_validate'] = 'foo_captcha_custom_validation';
|
149
|
return $captcha;
|
150
|
}
|
151
|
break;
|
152
|
}
|
153
|
}
|
154
|
|
155
|
/**
|
156
|
* Custom CAPTCHA validation function.
|
157
|
*
|
158
|
* @param solution the solution for the challenge as reported by hook_captcha('generate', ...).
|
159
|
* @param response the answer given by the user.
|
160
|
* @return TRUE on succes and FALSE on failure.
|
161
|
*/
|
162
|
function foo_captcha_custom_validation($solution, $response) {
|
163
|
return $response == "foo" || $response == "bar";
|
164
|
}
|
165
|
"""
|
166
|
|
167
|
Previous example shows the basic usage for custom validation with only a $solution
|
168
|
and $response argument, which should be sufficient for most CAPTCHA modules.
|
169
|
More advanced CAPTCHA modules can also use extra provided arguments $element
|
170
|
and $form_state:
|
171
|
"""
|
172
|
function foo_captcha_custom_validation($solution, $response, $element, $form_state) {
|
173
|
return $form_state['foo']['#bar'] = 'baz';
|
174
|
}
|
175
|
"""
|
176
|
These extra arguments are the $element and $form_state arguments of the validation function
|
177
|
of the #captcha element. See captcha_validate() in captcha.module for more info about this.
|
178
|
|
179
|
|
180
|
|
181
|
=== Hook into CAPTCHA placement ===
|
182
|
The CAPTCHA module attempts to place the CAPTCHA element in an appropriate spot
|
183
|
at the bottom of the targeted form, but this automatic detection may be insufficient
|
184
|
for complex forms.
|
185
|
The hook_captcha_placement_map hook allows to define the placement of the CAPTCHA element
|
186
|
as desired. The hook should return an array, mapping form IDs to placement arrays, which are
|
187
|
associative arrays with the following fields:
|
188
|
- 'path': path (array of path items) of the form's container element in which the
|
189
|
CAPTCHA element should be inserted.
|
190
|
- 'key': the key of the element before which the CAPTCHA element
|
191
|
should be inserted. If the field 'key' is undefined or NULL, the CAPTCHA will
|
192
|
just be appended in the container.
|
193
|
- 'weight': if 'key' is not NULL: should be the weight of the element defined by 'key'.
|
194
|
If 'key' is NULL and weight is not NULL/unset: set the weight property of the CAPTCHA element
|
195
|
to this value.
|
196
|
|
197
|
For example:
|
198
|
"""
|
199
|
/**
|
200
|
* Implementation of hook_captcha_placement_map
|
201
|
*/
|
202
|
function hook_captcha_placement_map() {
|
203
|
return array(
|
204
|
'my_fancy_form' => array(
|
205
|
'path' => array('items', 'buttons'),
|
206
|
'key' => 'savebutton',
|
207
|
),
|
208
|
'another_form' => array(
|
209
|
'path' => array(),
|
210
|
'weight' => 34,
|
211
|
),
|
212
|
);
|
213
|
}
|
214
|
"""
|
215
|
This will place the CAPTCHA element
|
216
|
- in the 'my_fancy_form' form inside the container $form['items']['buttons'],
|
217
|
just before the element $form['items']['buttons']['sacebutton'].
|
218
|
- in the 'another_form' form at the toplevel of the form, with a weight 34.
|
219
|
|