You are here

function captcha_validate in CAPTCHA 7

Same name and namespace in other branches
  1. 8 captcha.module \captcha_validate()
  2. 5.3 captcha.module \captcha_validate()
  3. 6.2 captcha.module \captcha_validate()
  4. 6 captcha.module \captcha_validate()

CAPTCHA validation handler.

This function is placed in the main captcha.module file to make sure that it is available (even for cached forms, which don't fire captcha_form_alter(), and subsequently don't include additional include files).

1 string reference to 'captcha_validate'
captcha_element_process in ./captcha.module
Process callback for CAPTCHA form element.

File

./captcha.module, line 698
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_validate($element, &$form_state) {

  // If disable captcha mode is enabled, bypass captcha validation.
  if (variable_get('disable_captcha', FALSE)) {
    return;
  }
  $captcha_info = $form_state['captcha_info'];
  $form_id = $captcha_info['this_form_id'];

  // Get CAPTCHA response.
  $captcha_response = $form_state['values']['captcha_response'];

  // Get CAPTCHA session from CAPTCHA info
  // TODO: is this correct in all cases: see comment and code in previous revisions?
  $csid = $captcha_info['captcha_sid'];
  $solution = db_query('SELECT solution FROM {captcha_sessions} WHERE csid = :csid', array(
    ':csid' => $csid,
  ))
    ->fetchField();

  // @todo: what is the result when there is no entry for the captcha_session? in D6 it was FALSE, what in D7?
  if ($solution === FALSE) {

    // Unknown challenge_id.
    // TODO: this probably never happens anymore now that there is detection
    // for CAPTCHA session reuse attacks in _captcha_get_posted_captcha_info().
    form_set_error('captcha', t('CAPTCHA validation error: unknown CAPTCHA session ID. Contact the site administrator if this problem persists.'));
    watchdog('CAPTCHA', 'CAPTCHA validation error: unknown CAPTCHA session ID (%csid).', array(
      '%csid' => var_export($csid, TRUE),
    ), WATCHDOG_ERROR);
  }
  else {

    // Get CAPTCHA validate function or fall back on strict equality.
    $captcha_validate = $element['#captcha_validate'];
    if (!function_exists($captcha_validate)) {
      $captcha_validate = 'captcha_validate_strict_equality';
    }

    // Check the response with the CAPTCHA validation function.
    // Apart from the traditional expected $solution and received $response,
    // we also provide the CAPTCHA $element and $form_state arrays for more advanced use cases.
    if ($captcha_validate($solution, $captcha_response, $element, $form_state)) {

      // Correct answer.
      // Store form_id in session (but only if it is useful to do so, avoid setting stuff in session unnecessarily).
      $captcha_persistence = variable_get('captcha_persistence', CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE);
      if ($captcha_persistence == CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL || $captcha_persistence == CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_TYPE) {
        $_SESSION['captcha_success_form_ids'][$form_id] = $form_id;
      }

      // Record success.
      db_update('captcha_sessions')
        ->condition('csid', $csid)
        ->fields(array(
        'status' => CAPTCHA_STATUS_SOLVED,
      ))
        ->expression('attempts', 'attempts + 1')
        ->execute();
    }
    else {

      // Wrong answer.
      db_update('captcha_sessions')
        ->condition('csid', $csid)
        ->expression('attempts', 'attempts + 1')
        ->execute();

      // Set form error.
      form_set_error('captcha_response', _captcha_get_error_message());

      // Update wrong response counter.
      if (variable_get('captcha_enable_stats', FALSE)) {
        variable_set('captcha_wrong_response_counter', variable_get('captcha_wrong_response_counter', 0) + 1);
      }

      // Log to watchdog if needed.
      if (variable_get('captcha_log_wrong_responses', FALSE)) {
        watchdog('CAPTCHA', '%form_id post blocked by CAPTCHA module: challenge %challenge (by module %module), user answered "@response", but the solution was "@solution".', array(
          '%form_id' => $form_id,
          '@response' => $captcha_response,
          '@solution' => $solution,
          '%challenge' => $captcha_info['captcha_type'],
          '%module' => $captcha_info['module'],
        ), WATCHDOG_NOTICE);
      }
    }
  }
}