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