You are here

function captcha_process in CAPTCHA 6.2

Process callback for CAPTCHA form element.

1 string reference to 'captcha_process'
captcha_elements in ./captcha.module
Implementation of hook_elements().

File

./captcha.module, line 173
This module enables basic CAPTCHA functionality: administrators can add a CAPTCHA to desired forms that users without the 'skip CAPTCHA' permission (typically anonymous visitors) have to solve.

Code

function captcha_process($element, $edit, &$form_state, $complete_form) {
  module_load_include('inc', 'captcha');

  // Add Javascript for general CAPTCHA functionality.
  drupal_add_js(drupal_get_path('module', 'captcha') . '/captcha.js');

  // Prevent caching of the page with CAPTCHA elements.
  // This needs to be done even if the CAPTCHA will be ommitted later:
  // other untrusted users should not get a cached page when
  // the current untrusted user can skip the current CAPTCHA.
  global $conf;
  $conf['cache'] = FALSE;

  // Get the form ID of the form we are currently processing (which is not
  // necessary the same form that is submitted (if any).
  $this_form_id = $complete_form['form_id']['#value'];

  // Get the CAPTCHA session ID.
  // If there is a submitted form: try to retrieve and reuse the
  // CAPTCHA session ID from the posted data.
  list($posted_form_id, $posted_captcha_sid) = _captcha_get_posted_captcha_info($element, $form_state, $this_form_id);
  if ($this_form_id == $posted_form_id && isset($posted_captcha_sid)) {
    $captcha_sid = $posted_captcha_sid;
  }
  else {

    // Generate a new CAPTCHA session if we could not reuse one from a posted form.
    $captcha_sid = _captcha_generate_captcha_session($this_form_id, CAPTCHA_STATUS_UNSOLVED);
  }

  // Store CAPTCHA session ID as hidden field.
  // Strictly speaking, it is not necessary to send the CAPTCHA session id
  // with the form, as the one time CAPTCHA token (see lower) is enough.
  // However, we still send it along, because it can help debugging
  // problems on live sites with only access to the markup.
  $element['captcha_sid'] = array(
    '#type' => 'hidden',
    '#value' => $captcha_sid,
  );

  // Get the token for a captcha_sid
  $captcha_token = db_result(db_query("SELECT token FROM {captcha_sessions} WHERE csid = %d", $captcha_sid));

  // Generate a new token if the token could not be retrieved (but not if the form has been submitted, because otherwise the session could be reused.)
  if (!isset($captcha_token) && !$form_state['submitted']) {

    // Additional one time CAPTCHA token: store in database and send with form.
    $captcha_token = md5(mt_rand());
    db_query("UPDATE {captcha_sessions} SET token='%s' WHERE csid=%d", $captcha_token, $captcha_sid);
  }
  $element['captcha_token'] = array(
    '#type' => 'hidden',
    '#value' => $captcha_token,
  );

  // Get implementing module and challenge for CAPTCHA.
  list($captcha_type_module, $captcha_type_challenge) = _captcha_parse_captcha_type($element['#captcha_type']);

  // Store CAPTCHA information for further processing in
  // - $form_state['captcha_info'], which survives a form rebuild (e.g. node
  //   preview), useful in _captcha_get_posted_captcha_info().
  // - $element['#captcha_info'], for post processing functions that do not
  //   receive a $form_state argument (e.g. the pre_render callback).
  $form_state['captcha_info'] = array(
    'this_form_id' => $this_form_id,
    'posted_form_id' => $posted_form_id,
    'captcha_sid' => $captcha_sid,
    'module' => $captcha_type_module,
    'captcha_type' => $captcha_type_challenge,
  );
  $element['#captcha_info'] = array(
    'form_id' => $this_form_id,
    'captcha_sid' => $captcha_sid,
  );
  if (_captcha_required_for_user($captcha_sid, $this_form_id) || $element['#captcha_admin_mode']) {

    // Generate a CAPTCHA and its solution
    // (note that the CAPTCHA session ID is given as third argument).
    $captcha = module_invoke($captcha_type_module, 'captcha', 'generate', $captcha_type_challenge, $captcha_sid);
    if (!isset($captcha['form']) || !isset($captcha['solution'])) {

      // The selected module did not return what we expected: log about it and quit.
      watchdog('CAPTCHA', 'CAPTCHA problem: unexpected result from hook_captcha() of module %module when trying to retrieve challenge type %type for form %form_id.', array(
        '%type' => $captcha_type_challenge,
        '%module' => $captcha_type_module,
        '%form_id' => $this_form_id,
      ), WATCHDOG_ERROR);
      return $element;
    }

    // Add form elements from challenge as children to CAPTCHA form element.
    $element['captcha_widgets'] = $captcha['form'];

    // Add a validation callback for the CAPTCHA form element (when not in admin mode).
    if (!$element['#captcha_admin_mode']) {
      $element['#element_validate'] = array(
        'captcha_validate',
      );
    }

    // Set a custom CAPTCHA validate function if requested.
    if (isset($captcha['captcha_validate'])) {
      $element['#captcha_validate'] = $captcha['captcha_validate'];
    }

    // Add pre_render callback for additional CAPTCHA processing.
    $element['#pre_render'] = array(
      'captcha_pre_render_process',
    );

    // Store the solution in the #captcha_info array.
    $element['#captcha_info']['solution'] = $captcha['solution'];

    // Make sure we can use a top level form value $form_state['values']['captcha_response'], even if the form has #tree=true.
    $element['#tree'] = FALSE;
  }
  return $element;
}