Projet

Général

Profil

Révision be58a50c

Ajouté par Assos Assos il y a environ 7 ans

Weekly update of contrib modules

Voir les différences:

drupal7/sites/all/modules/recaptcha/recaptcha.module
2 2

  
3 3
/**
4 4
 * @file
5
 * Uses the reCAPTCHA web service to improve the CAPTCHA system.
5
 * Verifies if user is a human without necessity to solve a CAPTCHA.
6 6
 */
7 7

  
8
require_once dirname(__FILE__) . '/recaptcha-php/src/ReCaptcha/ReCaptcha.php';
9
require_once dirname(__FILE__) . '/recaptcha-php/src/ReCaptcha/RequestMethod.php';
10
require_once dirname(__FILE__) . '/recaptcha-php/src/ReCaptcha/RequestParameters.php';
11
require_once dirname(__FILE__) . '/recaptcha-php/src/ReCaptcha/Response.php';
12
require_once dirname(__FILE__) . '/src/ReCaptcha/RequestMethod/Drupal7Post.php';
13

  
8 14
/**
9 15
 * Implements hook_help().
10 16
 */
11 17
function recaptcha_help($path, $arg) {
12
  $output = '';
13

  
14 18
  switch ($path) {
15
    case 'admin/modules#name':
16
      $output .= t('reCAPTCHA');
17
      break;
18

  
19
    case 'admin/modules#description':
20
    case 'admin/user/captcha/recaptcha':
21
      $output .= t('Uses the <a href="@url" target="_blank">reCAPTCHA</a> web service to improve the CAPTCHA system and protect email addresses.', array('@url' => url('https://www.google.com/recaptcha')));
22
      break;
23

  
24
    case 'admin/help#recaptcha':
25
      $output .= '<p>' .
26
        t('Uses the reCAPTCHA web service to improve the CAPTCHA module and protect email addresses. For more information on what reCAPTCHA is, visit <a href="@url" target="_blank">the official website</a>.', array('@url' => url('https://www.google.com/recaptcha'))) .
27
        '</p><h3>' .
28
        t('Configuration') .
29
        '</h3><p>' .
30
        t('The settings associated with reCAPTCHA can be found in the <a href="@recaptchatab">reCAPTCHA tab</a>, in the <a href="@captchasettings">CAPTCHA settings</a>. You must set your public and private reCAPTCHA keys in order to use the module. Once the public and private keys are set, visit the <a href="@captchasettings">CAPTCHA settings</a>, where you can choose where reCAPTCHA should be displayed.', array('@recaptchatab' => url('admin/user/captcha/recaptcha'), '@captchasettings' => url('admin/user/captcha'))) .
31
        '</p>';
32
      break;
19
    case 'admin/config/people/captcha/recaptcha':
20
      return t('Google <a href="@url">reCAPTCHA</a> is a free service to protect your website from spam and abuse. reCAPTCHA uses an advanced risk analysis engine and adaptive CAPTCHAs to keep automated software from engaging in abusive activities on your site. It does this while letting your valid users pass through with ease.', array('@url' => 'https://www.google.com/recaptcha'));
33 21
  }
22
}
34 23

  
35
  return $output;
24
/**
25
 * Implements hook_theme().
26
 */
27
function recaptcha_theme() {
28
  return array(
29
    'recaptcha_widget_noscript' => array(
30
      'variables' => array(
31
        'widget' => NULL,
32
      ),
33
      'template' => 'recaptcha-widget-noscript',
34
    ),
35
  );
36 36
}
37 37

  
38 38
/**
39 39
 * Implements hook_menu().
40 40
 */
41 41
function recaptcha_menu() {
42
  $items = array();
43 42
  $items['admin/config/people/captcha/recaptcha'] = array(
44 43
    'title' => 'reCAPTCHA',
45
    'description' => 'Administer the reCAPTCHA web service.',
44
    'description' => 'Administer the Google No CAPTCHA reCAPTCHA web service.',
46 45
    'page callback' => 'drupal_get_form',
47 46
    'page arguments' => array('recaptcha_admin_settings'),
48 47
    'access arguments' => array('administer recaptcha'),
49 48
    'type' => MENU_LOCAL_TASK,
50 49
    'file' => 'recaptcha.admin.inc',
50
    'weight' => 1,
51 51
  );
52

  
52 53
  return $items;
53 54
}
54 55

  
......
58 59
function recaptcha_permission() {
59 60
  return array(
60 61
    'administer recaptcha' => array(
61
      'title' => t('reCaptcha Administration'),
62
      'description' => t('Administer reCaptcha settings'),
62
      'title' => t('Administer reCAPTCHA'),
63
      'description' => t('Administer reCAPTCHA settings'),
63 64
    ),
64 65
  );
65 66
}
......
68 69
 * Implements hook_captcha().
69 70
 */
70 71
function recaptcha_captcha($op, $captcha_type = '') {
72
  global $language;
73

  
71 74
  switch ($op) {
72 75
    case 'list':
73 76
      return array('reCAPTCHA');
......
75 78
    case 'generate':
76 79
      $captcha = array();
77 80
      if ($captcha_type == 'reCAPTCHA') {
78
        // Retrieve configuration variables.
79
        $recaptcha_theme = variable_get('recaptcha_theme', 'red');
80
        $recaptcha_tabindex = variable_get('recaptcha_tabindex', NULL);
81
        $recaptcha_public_key = variable_get('recaptcha_public_key', FALSE);
82
        $recaptcha_ajax_api = variable_get('recaptcha_ajax_api', FALSE);
83

  
84
        // Test if reCAPTCHA can be used, falling back to Math if it is not
85
        // configured, the library won't load, or the server is down.
86
        if (!$recaptcha_public_key || !_recaptcha_load_library() || !_recaptcha_server_is_up()) {
87
          return captcha_captcha('generate', 'Math');
88
        }
89

  
90
        if ($recaptcha_ajax_api) {
91
          // By default CAPTCHA turns off page caching on any page where a
92
          // CAPTCHA challenge appears. If recaptcha is using AJAX API, set
93
          // caching back to its old state as stored in DB.
94
          global $conf;
95
          $conf['cache'] = unserialize(db_query("SELECT value FROM {variable} WHERE name = 'cache'")->fetchField());
96
        }
97

  
98
        $recaptcha_options = array(
99
          'theme' => $recaptcha_theme,
100
        );
101

  
102
        // Localization support.
103
        global $language;
104
        if (isset($language->language)) {
105
          // reCAPTCHA uses two-character language codes, so 'pt-br' must be
106
          // passed as 'pt'.
107
          $recaptcha_options['lang'] = drupal_substr($language->language, 0, 2);
108
        }
109

  
110
        // Construct the Javascript, but only display it once.
111
        static $_recaptcha_jsadded = FALSE;
112
        if ($_recaptcha_jsadded == FALSE && $recaptcha_ajax_api == FALSE) {
113
          $_recaptcha_jsadded = TRUE;
114

  
115
          // Add support to display the custom theme.
116
          if ($recaptcha_theme == 'custom') {
117
            $recaptcha_options['custom_theme_widget'] = 'recaptcha_custom_theme_widget';
118
          }
81
        $recaptcha_site_key = variable_get('recaptcha_site_key', '');
82
        $recaptcha_secret_key = variable_get('recaptcha_secret_key', '');
83

  
84
        if (!empty($recaptcha_site_key) && !empty($recaptcha_secret_key)) {
85
          // Build the reCAPTCHA captcha form if site_key and secret_key are
86
          // configured. Captcha requires TRUE to be returned in solution.
87
          $captcha['solution'] = TRUE;
88
          $captcha['captcha_validate'] = 'recaptcha_captcha_validation';
89
          $captcha['form']['captcha_response'] = array(
90
            '#type' => 'hidden',
91
            '#value' => 'Google no captcha',
92
          );
119 93

  
120
          // Set the default tab index.
121
          if (!empty($recaptcha_tabindex)) {
122
            $recaptcha_options['tabindex'] = $recaptcha_tabindex;
94
          $noscript = '';
95
          if (variable_get('recaptcha_noscript', 0)) {
96
            $variables = array(
97
              'sitekey' => $recaptcha_site_key,
98
              'language' => $language->language,
99
            );
100
            $noscript = theme('recaptcha_widget_noscript', array('widget' => $variables));
123 101
          }
124
          drupal_add_js('var RecaptchaOptions = ' . drupal_json_encode($recaptcha_options) . ';', array('type' => 'inline'));
125
        }
126 102

  
127
        // Create the form. Captcha requires TRUE to be returned in solution.
128
        $captcha['solution'] = TRUE;
129
        $captcha['captcha_validate'] = 'recaptcha_captcha_validation';
130

  
131
        // If 'Disable Client-Side Cookies' is set, then add query string to
132
        // end of the public key string before passing to recaptchalib.
133
        if (variable_get('recaptcha_nocookies', FALSE)) {
134
          $recaptcha_public_key .= '&nocookie=1';
135
        }
103
          $attributes = array(
104
            'class' => 'g-recaptcha',
105
            'data-sitekey' => $recaptcha_site_key,
106
            'data-theme' => variable_get('recaptcha_theme', 'light'),
107
            'data-type' => variable_get('recaptcha_type', 'image'),
108
            'data-size' => variable_get('recaptcha_size', ''),
109
            'data-tabindex' => variable_get('recaptcha_tabindex', 0),
110
          );
111
          // Filter out empty tabindex/size.
112
          $attributes = array_filter($attributes);
136 113

  
137
        $captcha['form']['captcha_response'] = array(
138
          '#type' => 'hidden',
139
          '#value' => 'reCAPTCHA',
140
        );
114
          $captcha['form']['recaptcha_widget'] = array(
115
            '#markup' => '<div' . drupal_attributes($attributes) . '></div>',
116
            '#suffix' => $noscript,
117
          );
141 118

  
142
        // Expose the form, either straight HTML, or using the AJAX API.
143
        // Build the custom theme HTML if necessary.
144
        $recaptcha_custom_html = ($recaptcha_theme == 'custom') ? theme('recaptcha_custom_widget') : '';
145
        if ($recaptcha_ajax_api == FALSE) {
146
          // Only generate recaptcha_get_html() if we're not using the AJAX API.
147
          $html = recaptcha_get_html($recaptcha_public_key, NULL, TRUE);
148
          $captcha['form']['captcha_form'] = array(
149
            '#type' => 'item',
150
            '#markup' => (!empty($recaptcha_custom_html) ? '<div id="recaptcha_custom_theme_widget">' . $recaptcha_custom_html . '</div>' : '') . $html,
119
          // @todo: #1664602: D7 does not yet support "async" in drupal_add_js().
120
          // drupal_add_js(url('https://www.google.com/recaptcha/api.js', array('query' => array('hl' => $language->language), 'absolute' => TRUE)), array('defer' => TRUE, 'async' => TRUE, 'type' => 'external'));
121
          $data = array(
122
            '#tag' => 'script',
123
            '#value' => '',
124
            '#attributes' => array(
125
              'src' => url('https://www.google.com/recaptcha/api.js', array('query' => array('hl' => $language->language), 'absolute' => TRUE)),
126
              'async' => 'async',
127
              'defer' => 'defer',
128
            ),
151 129
          );
130
          drupal_add_html_head($data, 'recaptcha_api');
152 131
        }
153 132
        else {
154
          $captcha['form']['captcha_form'] = array(
155
            '#type' => 'item',
156
            // Create the destination container, inserting any custom theme HTML
157
            // necessary ($recaptcha_custom_html will be empty if we are not
158
            // using custom theme).
159
            '#markup' => '<div id="recaptcha_ajax_api_container">' . $recaptcha_custom_html . '</div>',
160
          );
161
          drupal_add_js('https://www.google.com/recaptcha/api/js/recaptcha_ajax.js', array('type' => 'external'));
162
          $recaptcha_options['public_key'] = $recaptcha_public_key;
163
          $recaptcha_options['container'] = 'recaptcha_ajax_api_container';
164
          drupal_add_js(array('recaptcha' => $recaptcha_options), 'setting');
165
          drupal_add_js(drupal_get_path('module', 'recaptcha') . '/recaptcha.js');
133
          // Fallback to Math captcha as reCAPTCHA is not configured.
134
          $captcha = captcha_captcha('generate', 'Math');
166 135
        }
167 136
      }
168 137
      return $captcha;
......
170 139
}
171 140

  
172 141
/**
173
 * Test whether the reCAPTCHA server is up.
174
 *
175
 * @return bool
176
 *   TRUE if the reCAPTCHA server is up, FALSE otherwise.
142
 * CAPTCHA Callback; Validates the reCAPTCHA code.
177 143
 */
178
function _recaptcha_test_recaptcha_server() {
179
  $response = drupal_http_request('https://' . RECAPTCHA_VERIFY_SERVER);
180
  if (empty($response->error)) {
181
    return TRUE;
182
  }
183
  else {
184
    watchdog('reCAPTCHA', 'Unable to connect with the reCAPTCHA server (@server): @errno: @errstr', array(
185
      '@server' => RECAPTCHA_VERIFY_SERVER,
186
      '@errno' => $response->code,
187
      '@errstr' => $response->error,
188
    ), WATCHDOG_ERROR);
144
function recaptcha_captcha_validation($solution, $response, $element, $form_state) {
145
  $recaptcha_secret_key = variable_get('recaptcha_secret_key', '');
146
  if (empty($_POST['g-recaptcha-response']) || empty($recaptcha_secret_key)) {
189 147
    return FALSE;
190 148
  }
191
}
192 149

  
193
/**
194
 * Return the cached output of _recaptcha_test_recaptcha_server().
195
 *
196
 * @return bool
197
 *   TRUE if the reCAPTCHA server was up last time it was checked, FALSE
198
 *   otherwise.
199
 */
200
function _recaptcha_server_is_up() {
201
  static $server_status;
202
  // Use static cache value, if available.
203
  if (isset($server_status)) {
204
    return $server_status;
205
  }
206
  // Check if the status is cached already.
207
  $status_cache = cache_get('recaptcha_server_status');
208
  if ($status_cache !== FALSE) {
209
    $server_status = (bool) $status_cache;
210
    return $server_status;
211
  }
212
  // Status is not cached. Check if server is up.
213
  $server_status = _recaptcha_test_recaptcha_server();
150
  // Use drupal_http_request() to circumvent all issues with the Google library.
151
  $recaptcha = new \ReCaptcha\ReCaptcha($recaptcha_secret_key, new \ReCaptcha\RequestMethod\Drupal7Post());
214 152

  
215
  // Set to 5 minutes, if interval is not set.
216
  $cache_period = variable_get('recaptcha_server_status_check_interval', 5);
217
  // Save it as integer as cache_get returns FALSE, if not found.
218
  cache_set('recaptcha_server_status', (int) $server_status, 'cache', time() + ($cache_period * 60));
219
  return $server_status;
220
}
153
  $resp = $recaptcha->verify(
154
    $_POST['g-recaptcha-response'],
155
    ip_address()
156
  );
221 157

  
222
/**
223
 * CAPTCHA Callback; Validates the reCAPTCHA code.
224
 */
225
function recaptcha_captcha_validation($solution = NULL, $response = NULL) {
226
  global $user;
227
  $recaptcha_private_key = variable_get('recaptcha_private_key', FALSE);
228
  $ip_address = ip_address();
229
  if ($recaptcha_private_key && $ip_address && $response === 'reCAPTCHA' && !empty($_POST['recaptcha_challenge_field']) && !empty($_POST['recaptcha_response_field']) && _recaptcha_server_is_up()) {
230
    $resp = recaptcha_check_answer(
231
      $recaptcha_private_key,
232
      $ip_address,
233
      check_plain($_POST['recaptcha_challenge_field']),
234
      check_plain($_POST['recaptcha_response_field'])
158
  if ($resp->isSuccess()) {
159
    // Verified!
160
    return TRUE;
161
  }
162
  else {
163
    // Error code reference, https://developers.google.com/recaptcha/docs/verify
164
    $error_codes = array(
165
      'missing-input-secret' => t('The secret parameter is missing.'),
166
      'invalid-input-secret' => t('The secret parameter is invalid or malformed.'),
167
      'missing-input-response' => t('The response parameter is missing.'),
168
      'invalid-input-response' => t('The response parameter is invalid or malformed.'),
169
      'invalid-json' => t('The json response is invalid or malformed.'),
170
      'unknown' => t('Unknown error.'),
235 171
    );
236
    return $resp->is_valid;
172
    foreach ($resp->getErrorCodes() as $code) {
173
      if (!isset($error_codes[$code])) {
174
        $code = 'unknown';
175
      }
176
      watchdog('reCAPTCHA web service', '@error', array('@error' => $error_codes[$code]), WATCHDOG_ERROR);
177
    }
237 178
  }
238 179
  return FALSE;
239 180
}
240 181

  
241 182
/**
242
 * Implements hook_theme().
243
 */
244
function recaptcha_theme() {
245
  return array(
246
    'recaptcha_custom_widget' => array(
247
      'arguments' => array(),
248
    ),
249
  );
250
}
251

  
252
/**
253
 * Theme function: creates the custom themed recaptcha widget.
183
 * Process variables for recaptcha-widget-noscript.tpl.php.
254 184
 *
255
 * @ingroup themeable
256
 */
257
function theme_recaptcha_custom_widget() {
258
  $recaptcha_only_if_incorrect_sol = t('Incorrect please try again');
259
  $recaptcha_only_if_image_enter = t('Enter the words above:');
260
  $recaptcha_only_if_audio_enter = t('Enter the words you hear:');
261
  $recaptcha_get_another_captcha = t('Get another CAPTCHA');
262
  $recaptcha_only_if_image = t('Get an audio CAPTCHA');
263
  $recaptcha_only_if_audio = t('Get an image CAPTCHA');
264
  $help = t('Help');
265
  return <<<EOT
266
    <div id="recaptcha_image"></div>
267
    <div class="recaptcha_only_if_incorrect_sol" style="color:red">$recaptcha_only_if_incorrect_sol</div>
268
    <span class="recaptcha_only_if_image">$recaptcha_only_if_image_enter</span>
269
    <span class="recaptcha_only_if_audio">$recaptcha_only_if_audio_enter</span>
270
    <input type="text" id="recaptcha_response_field" name="recaptcha_response_field" />
271
    <div class="recaptcha_get_another_captcha"><a href="javascript:Recaptcha.reload()">$recaptcha_get_another_captcha</a></div>
272
    <div class="recaptcha_only_if_image"><a href="javascript:Recaptcha.switch_type('audio')">$recaptcha_only_if_image</a></div>
273
    <div class="recaptcha_only_if_audio"><a href="javascript:Recaptcha.switch_type('image')">$recaptcha_only_if_audio</a></div>
274
    <div class="recaptcha_help"><a href="javascript:Recaptcha.showhelp()">$help</a></div>
275
EOT;
276
}
277

  
278
/**
279
 * Load the recaptcha library.
185
 * @see recaptcha-widget-noscript.tpl.php
280 186
 */
281
function _recaptcha_load_library() {
282
  return module_load_include('php', 'recaptcha', 'recaptcha-php-1.11/recaptchalib');
187
function template_preprocess_recaptcha_widget_noscript(&$variables) {
188
  $variables['sitekey']  = check_plain($variables['widget']['sitekey']);
189
  $variables['language'] = check_plain($variables['widget']['language']);
190
  $variables['url']      = check_url(url('https://www.google.com/recaptcha/api/fallback', array('query' => array('k' => $variables['widget']['sitekey'], 'hl' => $variables['widget']['language']), 'absolute' => TRUE)));
283 191
}

Formats disponibles : Unified diff