captcha_form_alter

Versions
5
captcha_form_alter($form_id, &$form)
6
captcha_form_alter(&$form, $form_state, $form_id)

Implementation of hook_form_alter().

This function adds a CAPTCHA to forms for untrusted users if needed and adds CAPTCHA administration links for site administrators if this option is enabled.

Code

contrib/captcha/captcha.module, line 476

<?php
function captcha_form_alter($form_id, &$form) {

  if (!user_access('skip CAPTCHA')) {
    // Visitor does not have permission to skip the CAPTCHA

    // Get CAPTCHA type and module for this form. Return if no CAPTCHA was set.
    $result = db_query("SELECT module, type FROM {captcha_points} WHERE form_id = '%s'", $form_id);
    if (!$result) {
      return;
    }
    $captcha_point = db_fetch_object($result);
    if (!$captcha_point || !$captcha_point->type) {
      return;
    }

    // Prevent caching of the page with this CAPTCHA enabled form.
    // This needs to be done even if the CAPTCHA will be skipped (because of
    // persistence): other untrusted users should not get a cached page when
    // the current untrusted user can skip the current CAPTCHA.
    global $conf;
    $conf['cache'] = FALSE;

    // Do not present CAPTCHA if not CAPTCHA-persistent and user has already solved a CAPTCHA for this form
    if (_captcha_persistence_skip($form_id)) {
      return;
    }

    // Generate a CAPTCHA and its solution
    $captcha = module_invoke($captcha_point->module, 'captcha', 'generate', $captcha_point->type);
    if (!$captcha) {
      //The selected module returned nothing, maybe it is disabled or it's wrong, we should watchdog that and then quit.
      watchdog('CAPTCHA',
        t('CAPTCHA problem: hook_captcha() of module %module returned nothing when trying to retrieve challenge type %type for form %form_id.',
          array('%type' => $captcha_point->type, '%module' => $captcha_point->module, '%form_id' => $form_id)),
        WATCHDOG_ERROR);
      return;
    }

    // Add a CAPTCHA part to the form (depends on value of captcha_description)
    $captcha_description = _captcha_get_description();
    if ($captcha_description) {
      // $captcha_description is not empty: CAPTCHA part is a fieldset with description
      $form['captcha'] = array(
        '#type' => 'fieldset',
        '#title' => t('CAPTCHA'),
        '#description' => $captcha_description,
        '#attributes' => array('class' => 'captcha'),
      );
    }
    else {
      // $captcha_description is empty: CAPTCHA part is an empty markup form element
      $form['captcha'] = array(
        '#type' => 'markup',
        '#prefix' => '<div class="captcha">',
        '#suffix' => '</div>',
      );
    }

    // Add the form elements of the generated CAPTCHA to the form
    $form['captcha'] = array_merge($form['captcha'], $captcha['form']);

    // Store the solution of the generated CAPTCHA as an internal form value.
    // This will be stored later in $_SESSION during the pre_render phase.
    // It can't be saved at this point because hook_form_alter is not only run
    // before form rendering, but also before form validation (which happens
    // in a new (POST) request. Consequently the right CAPTCHA solution would be
    // overwritten just before validation. The pre_render functions are not run
    // before validation and are the right place to store the solution in $_SESSION.
    $form['captcha']['captcha_solution'] = array(
      '#type' => 'value',
      '#value' => $captcha['solution'],
    );

    // The CAPTCHA token is used to differentiate between different instances
    // of the same form. This makes it possible to request the same form a
    // couple of times before submitting them. The solution of the CAPTCHA of
    // each of these form instances will be stored at the pre_render phase in
    // $_SESSION['captcha'][$form_id][$captcha_token]
    $form['captcha']['captcha_token'] = array(
      '#type' => 'hidden',
      '#value' => md5(mt_rand()),
    );

    // other internal values needed for the validation phase
    $form['captcha']['validationdata'] = array(
      '#type' => 'value',
      '#value' => array(
        'form_id' => $form_id,
        'preprocess' => isset($captcha['preprocess'])? $captcha['preprocess'] : FALSE,
        'module' => $captcha_point->module,
        'type' => $captcha_point->type,
      ),
    );

    // handle the pre_render functions
    $form['#pre_render'][] = 'captcha_pre_render';
    $form['#pre_render'][] = 'captcha_pre_render_place_captcha';

    // Add a validation function for the CAPTCHA part of the form
    $form['captcha']['#validate']['captcha_validate'] = array();

  }
  elseif (user_access('administer CAPTCHA settings') && variable_get('captcha_administration_mode', FALSE) && arg(0) != 'admin') {
    // For administrators: show CAPTCHA info and offer link to configure it
    $result = db_query("SELECT module, type FROM {captcha_points} WHERE form_id = '%s'", $form_id);
    if (!$result) {
      return;
    }
    $captcha_point = db_fetch_object($result);
    $form['captcha'] = array(
      '#type' => 'fieldset',
      '#title' => t('CAPTCHA'),
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
    );
    if ($captcha_point && $captcha_point->type) {
      $form['captcha']['#description'] = t('Untrusted users will see a CAPTCHA here (!settings).',
        array('!settings' => l(t('general CAPTCHA settings'), 'admin/user/captcha'))
      );
      $form['captcha']['challenge'] = array(
        '#type' => 'item',
        '#title' => t('Enabled challenge'),
        '#value' => t('"@type" by module "@module" (!change, !disable)', array(
          '@type' => $captcha_point->type,
          '@module' => $captcha_point->module,
          '!change' => l(t('change'), "admin/user/captcha/captcha/captcha_point/$form_id", array(), drupal_get_destination()),
          '!disable' => l(t('disable'), "admin/user/captcha/captcha/captcha_point/$form_id/disable", array(), drupal_get_destination()),
        )),
      );
    }
    else {
      $form['captcha']['add_captcha'] = array(
        '#value' => l(t('Place a CAPTCHA here for untrusted users.'), "admin/user/captcha/captcha/captcha_point/$form_id", array(), drupal_get_destination())
      );
    }
    // Add pre_render function for placing the CAPTCHA just above the submit button
    $form['#pre_render'] = ((array) $form['#pre_render']) + array('captcha_pre_render_place_captcha');
  }
}
?>