1 |
85ad3d82
|
Assos Assos
|
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.
|