Project

General

Profile

Paste
Download (22.5 KB) Statistics
| Branch: | Revision:

root / drupal7 / sites / all / modules / captcha / captcha.admin.inc @ 66b5cbf6

1
<?php
2

    
3
/**
4
 * @file
5
 * Functionality and helper functions for CAPTCHA administration.
6
 */
7

    
8
/**
9
 * Return an array with the available CAPTCHA types, for use as options array
10
 * for a select form elements.
11
 *
12
 * @param $add_special_options if true: also add a 'none' and 'default' option
13
 *
14
 * @return an associative array mapping "$module/$type" to
15
 *   "$type (from module $module)" with $module the module name implementing the CAPTCHA
16
 *   and $type the name of the CAPTCHA type.
17
 */
18
function _captcha_available_challenge_types($add_special_options=TRUE) {
19
  $captcha_types = array();
20
  if ($add_special_options) {
21
    $captcha_types['none'] = t('- No challenge -');
22
    $captcha_types['default'] = t('Default challenge type');
23
  }
24
  // We do our own version of Drupal's module_invoke_all() here because
25
  // we want to build an array with custom keys and values.
26
  foreach (module_implements('captcha') as $module) {
27
    $result = call_user_func_array($module . '_captcha', array('list'));
28
    if (is_array($result)) {
29
      foreach ($result as $type) {
30
        $captcha_types["$module/$type"] = t('@type (from module @module)', array('@type' => $type, '@module' => $module));
31
      }
32
    }
33
  }
34
  return $captcha_types;
35
}
36

    
37
/**
38
 * Form builder function for the general CAPTCHA configuration
39
 */
40
function captcha_admin_settings() {
41
  module_load_include('inc', 'captcha');
42

    
43
  // Use javascript for some added usability on admin form.
44
  drupal_add_js(drupal_get_path('module', 'captcha') . '/captcha.js');
45

    
46
  // Configuration of which forms to protect, with what challenge.
47
  $form['captcha_form_protection'] = array(
48
    '#type' => 'fieldset',
49
    '#title' => t('Form protection'),
50
    '#description' => t("Select the challenge type you want for each of the listed forms (identified by their so called <em>form_id</em>'s). You can easily add arbitrary forms with the textfield at the bottom of the table or with the help of the option <em>Add CAPTCHA administration links to forms</em> below."),
51
  );
52
  $form['captcha_form_protection']['captcha_default_challenge'] = array(
53
    '#type' => 'select',
54
    '#title' => t('Default challenge type'),
55
    '#description' => t('Select the default challenge type for CAPTCHAs. This can be overriden for each form if desired.'),
56
    '#options' => _captcha_available_challenge_types(FALSE),
57
    '#default_value' => variable_get('captcha_default_challenge', 'captcha/Math'),
58
  );
59
  // List known form_ids.
60
  $form['captcha_form_protection']['captcha_form_id_overview'] = array(
61
    '#theme' => 'captcha_admin_settings_captcha_points',
62
    '#tree' => TRUE,
63
  );
64
  $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'] = array();
65
  $captcha_type_options = _captcha_available_challenge_types();
66
  $result = db_select('captcha_points', 'cp')->fields('cp')->orderBy('form_id')->execute();
67
  foreach ($result as $captcha_point) {
68
    $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'][$captcha_point->form_id] = array();
69
    $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'][$captcha_point->form_id]['form_id'] = array(
70
      '#markup' => $captcha_point->form_id,
71
    );
72
    // Select widget for CAPTCHA type.
73
    if (isset($captcha_point->module) && $captcha_point->module) {
74
      $captcha_type = $captcha_point->module . '/' . $captcha_point->captcha_type;
75
    }
76
    elseif (isset($captcha_point->captcha_type) && ($captcha_point->captcha_type == 'default')) {
77
      $captcha_type = 'default';
78
    }
79
    else {
80
      $captcha_type = 'none';
81
    }
82
    $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'][$captcha_point->form_id]['captcha_type'] = array(
83
      '#type' => 'select',
84
      '#default_value' => $captcha_type,
85
      '#options' => $captcha_type_options,
86
    );
87
    // Additional operations.
88
    $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'][$captcha_point->form_id]['operations'] = array(
89
      '#markup' => implode(", ", array(
90
        l(t('delete'), "admin/config/people/captcha/captcha/captcha_point/{$captcha_point->form_id}/delete"),
91
      ))
92
    );
93
  }
94

    
95
  // Form items for new form_id.
96
  $form['captcha_form_protection']['captcha_form_id_overview']['captcha_new_captcha_point'] = array();
97
  // Textfield for form_id.
98
  $form['captcha_form_protection']['captcha_form_id_overview']['captcha_new_captcha_point']['form_id'] = array(
99
    '#type' => 'textfield',
100
    '#size' => 16,
101
  );
102
  // Select widget for CAPTCHA type.
103
  $form['captcha_form_protection']['captcha_form_id_overview']['captcha_new_captcha_point']['captcha_type'] = array(
104
    '#type' => 'select',
105
    '#default_value' => 'none',
106
    '#options' => $captcha_type_options,
107
  );
108

    
109
  // Checkbox to add default CAPTCHA to all non listed forms as well.
110
  $form['captcha_form_protection']['captcha_default_challenge_on_nonlisted_forms'] = array(
111
    '#type' => 'checkbox',
112
    '#title' => t('Default challenge on non-listed forms.'),
113
    '#default_value' => variable_get('captcha_default_challenge_on_nonlisted_forms', FALSE),
114
    '#description' => t('Normally, no challenge is added to forms that are not listed above. Enabling this option will add the default challenge instead.'),
115
  );
116

    
117
  // Field for the CAPTCHA administration mode.
118
  $form['captcha_form_protection']['captcha_administration_mode'] = array(
119
    '#type' => 'checkbox',
120
    '#title' => t('Add CAPTCHA administration links to forms'),
121
    '#default_value' => variable_get('captcha_administration_mode', FALSE),
122
    '#description' => t('This option makes it easy to manage CAPTCHA settings on forms. When enabled, users with the <em>administer CAPTCHA settings</em> permission will see a fieldset with CAPTCHA administration links on all forms, except on administrative pages.'),
123
  );
124
  // Field for the CAPTCHAs on admin pages.
125
  $form['captcha_form_protection']['captcha_allow_on_admin_pages'] = array(
126
    '#type' => 'checkbox',
127
    '#title' => t('Allow CAPTCHAs and CAPTCHA administration links on administrative pages'),
128
    '#default_value' => variable_get('captcha_allow_on_admin_pages', FALSE),
129
    '#description' => t("This option makes it possible to add CAPTCHAs to forms on administrative pages. CAPTCHAs are disabled by default on administrative pages (which shouldn't be accessible to untrusted users normally) to avoid the related overhead. In some situations, e.g. in the case of demo sites, it can be usefull to allow CAPTCHAs on administrative pages."),
130
  );
131

    
132
  // Button for clearing the CAPTCHA placement cache.
133
  // Based on Drupal core's "Clear all caches" (performance settings page).
134
  $form['captcha_form_protection']['captcha_placement_caching'] = array(
135
    '#type' => 'item',
136
    '#title' => t('CAPTCHA placement caching'),
137
    '#description' => t('For efficiency, the positions of the CAPTCHA elements in each of the configured forms are cached. Most of the time, the structure of a form does not change and it would be a waste to recalculate the positions every time. Occasionally however, the form structure can change (e.g. during site building) and clearing the CAPTCHA placement cache can be required to fix the CAPTCHA placement.'),
138
  );
139
  $form['captcha_form_protection']['captcha_placement_caching']['captcha_placement_cache_clear'] = array(
140
    '#type' => 'submit',
141
    '#value' => t('Clear the CAPTCHA placement cache'),
142
    '#submit' => array('captcha_clear_captcha_placement_cache_submit'),
143
  );
144

    
145
  // Configuration option for adding a CAPTCHA description.
146
  $form['captcha_add_captcha_description'] = array(
147
    '#type' => 'checkbox',
148
    '#title' => t('Add a description to the CAPTCHA'),
149
    '#description' => t('Add a configurable description to explain the purpose of the CAPTCHA to the visitor.'),
150
    '#default_value' => variable_get('captcha_add_captcha_description', TRUE),
151
  );
152
  // Textfield(s) for the CAPTCHA description.
153
  if (module_exists('locale')) {
154
    $langs = locale_language_list();
155
    $form['captcha_descriptions'] = array(
156
      '#type' => 'fieldset',
157
      '#title' => t('CAPTCHA description'),
158
      '#description' => t('Configurable description of the CAPTCHA. An empty entry will reset the description to default.'),
159
      '#attributes' => array('id' => 'edit-captcha-description-wrapper'),
160
    );
161
    foreach ($langs as $lang_code => $lang_name) {
162
      $form['captcha_descriptions']["captcha_description_$lang_code"] = array(
163
        '#type' => 'textfield',
164
        '#title' => t('For language %lang_name (code %lang_code)', array('%lang_name' => $lang_name, '%lang_code' => $lang_code)),
165
        '#default_value' => _captcha_get_description($lang_code),
166
        '#maxlength' => 256,
167
      );
168
    }
169
  }
170
  else {
171
    $form['captcha_description'] = array(
172
      '#type' => 'textfield',
173
      '#title' => t('Challenge description'),
174
      '#description' => t('Configurable description of the CAPTCHA. An empty entry will reset the description to default.'),
175
      '#default_value' => _captcha_get_description(),
176
      '#maxlength' => 256,
177
      '#attributes' => array('id' => 'edit-captcha-description-wrapper'),
178
    );
179
  }
180

    
181
  // Option for case sensitive/insensitive validation of the responses.
182
  $form['captcha_default_validation'] = array(
183
    '#type' => 'radios',
184
    '#title' => t('Default CAPTCHA validation'),
185
    '#description' => t('Define how the response should be processed by default. Note that the modules that provide the actual challenges can override or ignore this.'),
186
    '#options' => array(
187
      CAPTCHA_DEFAULT_VALIDATION_CASE_SENSITIVE => t('Case sensitive validation: the response has to exactly match the solution.'),
188
      CAPTCHA_DEFAULT_VALIDATION_CASE_INSENSITIVE => t('Case insensitive validation: lowercase/uppercase errors are ignored.'),
189
    ),
190
    '#default_value' => variable_get('captcha_default_validation', CAPTCHA_DEFAULT_VALIDATION_CASE_INSENSITIVE),
191
  );
192

    
193
  // Field for CAPTCHA persistence.
194
  // TODO for D7: Rethink/simplify the explanation and UI strings.
195
  $form['captcha_persistence'] = array(
196
    '#type' => 'radios',
197
    '#title' => t('Persistence'),
198
    '#default_value' => variable_get('captcha_persistence', CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE),
199
    '#options' => array(
200
      CAPTCHA_PERSISTENCE_SHOW_ALWAYS =>
201
        t('Always add a challenge.'),
202
      CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE =>
203
        t('Omit challenges in a multi-step/preview workflow once the user successfully responds to a challenge.'),
204
      CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_TYPE =>
205
        t('Omit challenges on a form type once the user successfully responds to a challenge on a form of that type.'),
206
      CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL =>
207
        t('Omit challenges on all forms once the user successfully responds to any challenge on the site.'),
208
    ),
209
    '#description' => t('Define if challenges should be omitted during the rest of a session once the user successfully responds to a challenge.'),
210
  );
211

    
212
  // Enable wrong response counter.
213
  $form['captcha_enable_stats'] = array(
214
    '#type' => 'checkbox',
215
    '#title' => t('Enable statistics'),
216
    '#description' => t('Keep CAPTCHA related counters in the <a href="!statusreport">status report</a>. Note that this comes with a performance penalty as updating the counters results in clearing the variable cache.', array('!statusreport' => url('admin/reports/status'))),
217
    '#default_value' => variable_get('captcha_enable_stats', FALSE),
218
  );
219

    
220
  // Option for logging wrong responses.
221
  $form['captcha_log_wrong_responses'] = array(
222
    '#type' => 'checkbox',
223
    '#title' => t('Log wrong responses'),
224
    '#description' => t('Report information about wrong responses to the <a href="!dblog">log</a>.', array('!dblog' => url('admin/reports/dblog'))),
225
    '#default_value' => variable_get('captcha_log_wrong_responses', FALSE),
226
  );
227

    
228
  // Submit button.
229
  $form['actions'] = array('#type' => 'actions');
230
  $form['actions']['submit'] = array(
231
    '#type' => 'submit',
232
    '#value' => t('Save configuration'),
233
  );
234

    
235
  return $form;
236
}
237

    
238
/**
239
 * Custom theme function for a table of (form_id -> CAPTCHA type) settings
240
 */
241
function theme_captcha_admin_settings_captcha_points($variables) {
242
  $form = $variables['form'];
243
  $header = array('form_id', t('Challenge type'), t('Operations'));
244
  $rows = array();
245
  // Existing CAPTCHA points.
246
  foreach (element_children($form['captcha_captcha_points']) as $key) {
247
    $row = array();
248
    $row[] = drupal_render($form['captcha_captcha_points'][$key]['form_id']);
249
    $row[] = drupal_render($form['captcha_captcha_points'][$key]['captcha_type']);
250
    $row[] = drupal_render($form['captcha_captcha_points'][$key]['operations']);
251
    $rows[] = $row;
252
  }
253
  // For new CAPTCHA point.
254
  $row = array();
255
  $row[] = drupal_render($form['captcha_new_captcha_point']['form_id']);
256
  $row[] = drupal_render($form['captcha_new_captcha_point']['captcha_type']);
257
  $row[] = '';
258
  $rows[] = $row;
259

    
260
  $output = theme('table', array('header' => $header, 'rows' => $rows));
261
  return $output;
262
}
263

    
264
/**
265
 * Validation handler for captcha_admin_settings form.
266
 */
267
function captcha_admin_settings_validate($form, $form_state) {
268
  $form_id = $form_state['values']['captcha_form_id_overview']['captcha_new_captcha_point']['form_id'];
269
  if (!preg_match('/^[a-z0-9_]*$/', $form_id)) {
270
    form_set_error('captcha_form_id_overview][captcha_new_captcha_point][form_id', t('Illegal form_id'));
271
  }
272
}
273

    
274
/**
275
 * Submission function for captcha_admin_settings form.
276
 */
277
function captcha_admin_settings_submit($form, &$form_state) {
278

    
279
  variable_set('captcha_administration_mode', $form_state['values']['captcha_administration_mode']);
280
  variable_set('captcha_allow_on_admin_pages', $form_state['values']['captcha_allow_on_admin_pages']);
281

    
282
  variable_set('captcha_default_challenge', $form_state['values']['captcha_default_challenge']);
283
  variable_set('captcha_default_challenge_on_nonlisted_forms', $form_state['values']['captcha_default_challenge_on_nonlisted_forms']);
284

    
285
  // Process CAPTCHA points
286
  if (isset($form_state['values']['captcha_form_id_overview']['captcha_captcha_points'])) {
287
    foreach ($form_state['values']['captcha_form_id_overview']['captcha_captcha_points'] as $captcha_point_form_id => $data) {
288
      captcha_set_form_id_setting($captcha_point_form_id, $data['captcha_type']);
289
    }
290
  }
291

    
292
  // Add new CAPTCHA point?
293
  $captcha_point_form_id = $form_state['values']['captcha_form_id_overview']['captcha_new_captcha_point']['form_id'];
294
  if (!empty($captcha_point_form_id)) {
295
    $captcha_type = $form_state['values']['captcha_form_id_overview']['captcha_new_captcha_point']['captcha_type'];
296
    captcha_set_form_id_setting($captcha_point_form_id, $captcha_type);
297
    drupal_set_message(t('Added CAPTCHA point.'), 'status');
298
  }
299

    
300
  // CAPTCHA description stuff.
301
  variable_set('captcha_add_captcha_description', $form_state['values']['captcha_add_captcha_description']);
302
  // Save (or reset) the CAPTCHA descriptions.
303
  if (module_exists('locale')) {
304
    $langs = locale_language_list();
305
    foreach ($langs as $lang_code => $lang_name) {
306
      $description = $form_state['values']["captcha_description_$lang_code"];
307
      if ($description) {
308
        variable_set("captcha_description_$lang_code", $description);
309
      }
310
      else {
311
        variable_del("captcha_description_$lang_code");
312
        drupal_set_message(t('Reset of CAPTCHA description for language %language.', array('%language' => $lang_name)), 'status');
313
      }
314
    }
315
  }
316
  else {
317
    $description = $form_state['values']['captcha_description'];
318
    if ($description) {
319
      variable_set('captcha_description', $description);
320
    }
321
    else {
322
      variable_del('captcha_description');
323
      drupal_set_message(t('Reset of CAPTCHA description.'), 'status');
324
    }
325
  }
326

    
327
  variable_set('captcha_default_validation', $form_state['values']['captcha_default_validation']);
328
  variable_set('captcha_persistence', $form_state['values']['captcha_persistence']);
329
  variable_set('captcha_enable_stats', $form_state['values']['captcha_enable_stats']);
330
  variable_set('captcha_log_wrong_responses', $form_state['values']['captcha_log_wrong_responses']);
331

    
332
  drupal_set_message(t('The CAPTCHA settings have been saved.'), 'status');
333
}
334

    
335

    
336

    
337

    
338
/**
339
 * Submit callback; clear CAPTCHA placement cache.
340
 */
341
function captcha_clear_captcha_placement_cache_submit($form, &$form_state) {
342
  variable_del('captcha_placement_map_cache');
343
  drupal_set_message(t('Cleared the CAPTCHA placement cache.'));
344
}
345

    
346

    
347
/**
348
 * Central handler for CAPTCHA point administration (adding, disabling, deleting)
349
 */
350
function captcha_point_admin($captcha_point_form_id=NULL, $op=NULL) {
351
  module_load_include('inc', 'captcha');
352

    
353
  // if $captcha_point_form_id and action $op given: do the action
354
  if ($captcha_point_form_id) {
355
    switch ($op) {
356
      case 'disable':
357
        return drupal_get_form('captcha_point_disable_confirm', $captcha_point_form_id, FALSE);
358
      case 'delete':
359
        return drupal_get_form('captcha_point_disable_confirm', $captcha_point_form_id, TRUE);
360
    }
361
    // return edit form for CAPTCHA point
362
    return drupal_get_form('captcha_point_admin_form', $captcha_point_form_id);
363
  }
364
  // return add form for CAPTCHA point
365
  return drupal_get_form('captcha_point_admin_form');
366
}
367

    
368
function captcha_point_admin_form($form, $form_state, $captcha_point_form_id=NULL) {
369
  $form = array();
370
  $default_captcha_type = 'none';
371
  if (isset($captcha_point_form_id)) {
372
    // use given CAPTCHA point form_id
373
    $form['captcha_point_form_id'] = array(
374
      '#type' => 'textfield',
375
      '#title' => t('Form ID'),
376
      '#description' => t('The Drupal form_id of the form to add the CAPTCHA to.'),
377
      '#value' => check_plain($captcha_point_form_id),
378
      '#disabled' => TRUE,
379
    );
380
    $captcha_point = captcha_get_form_id_setting($captcha_point_form_id);
381
    if ($captcha_point) {
382
      $default_captcha_type = "{$captcha_point->module}/{$captcha_point->captcha_type}";
383
    }
384
  }
385
  else {
386
    // textfield for CAPTCHA point form_id
387
    $form['captcha_point_form_id'] = array(
388
      '#type' => 'textfield',
389
      '#title' => t('Form ID'),
390
      '#description' => t('The Drupal form_id of the form to add the CAPTCHA to.'),
391
    );
392
  }
393
  // select widget for CAPTCHA type
394
  $form['captcha_type'] = array(
395
    '#type' => 'select',
396
    '#title' => t('Challenge type'),
397
    '#description' => t('The CAPTCHA type to use for this form.'),
398
    '#default_value' => $default_captcha_type,
399
    '#options' => _captcha_available_challenge_types(),
400
  );
401
  // redirect to general CAPTCHA settings page after submission
402
  $form['#redirect'] = 'admin/config/people/captcha';
403
  // submit button
404
  $form['actions'] = array('#type' => 'actions');
405
  $form['actions']['submit'] = array(
406
    '#type' => 'submit',
407
    '#value' => t('Save'),
408
  );
409
  return $form;
410
}
411

    
412

    
413
/**
414
 * validation function for captcha_point_admin_form
415
 */
416
function captcha_point_admin_form_validate($form, $form_state) {
417
  if (!preg_match('/^[a-z0-9_]+$/', $form_state['values']['captcha_point_form_id'])) {
418
    form_set_error('captcha_point_form_id', t('Illegal form_id'));
419
  }
420
}
421

    
422

    
423
/**
424
 * Submit function for captcha_point_admin_form.
425
 */
426
function captcha_point_admin_form_submit($form, $form_state) {
427
  $captcha_point_form_id = $form_state['values']['captcha_point_form_id'];
428
  $captcha_type = $form_state['values']['captcha_type'];
429
  captcha_set_form_id_setting($captcha_point_form_id, $captcha_type);
430
  drupal_set_message(t('Saved CAPTCHA point settings.'), 'status');
431
}
432

    
433
/**
434
 * Confirm dialog for disabling/deleting a CAPTCHA point
435
 */
436
function captcha_point_disable_confirm($form, &$form_state, $captcha_point_form_id, $delete) {
437
  $form = array();
438
  $form['captcha_point_form_id'] = array(
439
    '#type' => 'value',
440
    '#value' => $captcha_point_form_id,
441
  );
442
  $form['captcha_point_delete'] = array(
443
    '#type' => 'value',
444
    '#value' => $delete,
445
  );
446
  if ($delete) {
447
    $message = t('Are you sure you want to delete the CAPTCHA for form_id %form_id?', array('%form_id' => $captcha_point_form_id));
448
    $yes = t('Delete');
449
  }
450
  else {
451
    $message = t('Are you sure you want to disable the CAPTCHA for form_id %form_id?', array('%form_id' => $captcha_point_form_id));
452
    $yes = t('Disable');
453
  }
454
  return confirm_form($form, $message, 'admin/config/people/captcha/captcha', '', $yes);
455
}
456

    
457
/**
458
 * Submission handler of CAPTCHA point disabling/deleting confirm_form.
459
 */
460
function captcha_point_disable_confirm_submit($form, &$form_state) {
461
  $captcha_point_form_id = $form_state['values']['captcha_point_form_id'];
462
  $delete = $form_state['values']['captcha_point_delete'];
463
  if ($delete) {
464
    captcha_set_form_id_setting($captcha_point_form_id, NULL);
465
    drupal_set_message(t('Deleted CAPTCHA for form %form_id.', array('%form_id' => $captcha_point_form_id)));
466
  }
467
  else {
468
    captcha_set_form_id_setting($captcha_point_form_id, 'none');
469
    drupal_set_message(t('Disabled CAPTCHA for form %form_id.', array('%form_id' => $captcha_point_form_id)));
470
  }
471
  $form_state['redirect'] = 'admin/config/people/captcha/captcha';
472
}
473

    
474
/**
475
 * Helper function for generating an example challenge.
476
 */
477
function _captcha_generate_example_challenge($module, $type) {
478
  return array(
479
    '#type' => 'captcha',
480
    '#captcha_type' => $module . '/' . $type,
481
    '#captcha_admin_mode' => TRUE,
482
  );
483
}
484

    
485
/**
486
 * Funtion for generating a page with CAPTCHA examples.
487
 *
488
 * If the arguments $module and $challenge are not set, generate a list with
489
 * examples of the available CAPTCHA types.
490
 * If $module and $challenge are set, generate 10 examples of the concerning
491
 * CAPTCHA.
492
 */
493
function captcha_examples($form, $form_state, $module, $challenge) {
494
  module_load_include('inc', 'captcha');
495

    
496
  $form = array();
497
  if ($module && $challenge) {
498
    // Generate 10 example challenges.
499
    for ($i=0; $i<10; $i++) {
500
      $form["challenge_{$i}"] = _captcha_generate_example_challenge($module, $challenge);
501
    }
502
  }
503
  else {
504
    // generate a list with examples of the available CAPTCHA types
505
    $form['info'] = array(
506
      '#markup' => t('This page gives an overview of all available challenge types, generated with their current settings.'),
507
    );
508
    foreach (module_implements('captcha') as $mkey => $module) {
509
      $challenges = call_user_func_array($module . '_captcha', array('list'));
510
      if ($challenges) {
511
        foreach ($challenges as $ckey => $challenge) {
512
          $form["captcha_{$mkey}_{$ckey}"] = array(
513
            '#type' => 'fieldset',
514
            '#title' => t('Challenge %challenge by module %module', array('%challenge' => $challenge, '%module' => $module)),
515
            'challenge' => _captcha_generate_example_challenge($module, $challenge),
516
            'more_examples' => array(
517
              '#markup' => l(t('10 more examples of this challenge.'), "admin/config/people/captcha/captcha/examples/$module/$challenge"),
518
            ),
519
          );
520
        }
521
      }
522
    }
523
  }
524
  return $form;
525
}