Projet

Général

Profil

Paste
Télécharger (10,6 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / recaptcha / recaptcha.module @ f76f30e1

1
<?php
2

    
3
/**
4
 * @file
5
 * Uses the reCAPTCHA web service to improve the CAPTCHA system.
6
 */
7

    
8
/**
9
 * Implements hook_help().
10
 */
11
function recaptcha_help($path, $arg) {
12
  $output = '';
13
  switch ($path) {
14
    case 'admin/modules#name':
15
      $output .= t('reCAPTCHA');
16
      break;
17
    case 'admin/modules#description':
18
    case 'admin/user/captcha/recaptcha':
19
      $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')));
20
      break;
21
    case 'admin/help#recaptcha':
22
      $output .= '<p>' .
23
        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'))) .
24
        '</p><h3>' .
25
        t('Configuration') .
26
        '</h3><p>' .
27
        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'))) .
28
        '</p>';
29
      break;
30
  }
31
  return $output;
32
}
33

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

    
51
/**
52
 * Implements hook_permission().
53
 */
54
function recaptcha_permission() {
55
  return array(
56
    'administer recaptcha' => array(
57
      'title' => t('reCaptcha Administration'),
58
      'description' => t('Administer reCaptcha settings'),
59
    ),
60
  );
61
}
62

    
63
/**
64
 * Implements hook_captcha().
65
 */
66
function recaptcha_captcha($op, $captcha_type = '') {
67
  switch ($op) {
68
    case 'list':
69
      return array('reCAPTCHA');
70

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

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

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

    
94
        $recaptcha_options = array(
95
          'theme' => $recaptcha_theme,
96
        );
97

    
98
        // Localization support.
99
        global $language;
100
        if (isset($language->language)) {
101
          // reCAPTCHA uses two-character language codes, so 'pt-br' must be
102
          // passed as 'pt'; cf. https://developers.google.com/recaptcha/docs/customization#i18n
103
          $recaptcha_options['lang'] = drupal_substr($language->language, 0, 2);
104
        }
105

    
106
        // Construct the Javascript, but only display it once.
107
        static $_recaptcha_jsadded = FALSE;
108
        if ($_recaptcha_jsadded == FALSE && $recaptcha_ajax_api == FALSE) {
109
          $_recaptcha_jsadded = TRUE;
110

    
111
          // Add support to display the custom theme.
112
          if ($recaptcha_theme == 'custom') {
113
            $recaptcha_options['custom_theme_widget'] = 'recaptcha_custom_theme_widget';
114
          }
115

    
116
          // Set the default tab index.
117
          if (!empty($recaptcha_tabindex)) {
118
            $recaptcha_options['tabindex'] = $recaptcha_tabindex;
119
          }
120
          drupal_add_js('var RecaptchaOptions = ' . drupal_json_encode($recaptcha_options) . ';', array('type' => 'inline'));
121
        }
122

    
123
        // Create the form. Captcha requires TRUE to be returned in solution.
124
        $captcha['solution'] = TRUE;
125
        $captcha['captcha_validate'] = 'recaptcha_captcha_validation';
126

    
127
        // If 'Disable Client-Side Cookies' is set, then add query string to
128
        // end of the public key string before passing to recaptchalib.
129
        if (variable_get('recaptcha_nocookies', FALSE)) {
130
          $recaptcha_public_key .= '&nocookie=1';
131
        }
132

    
133
        $captcha['form']['captcha_response'] = array(
134
          '#type' => 'hidden',
135
          '#value' => 'reCAPTCHA',
136
        );
137

    
138
        // Expose the form, either straight HTML, or using the AJAX API.
139
        // Build the custom theme HTML if necessary.
140
        $recaptcha_custom_html = ($recaptcha_theme == 'custom') ? theme('recaptcha_custom_widget') : '';
141
        if ($recaptcha_ajax_api == FALSE) {
142
          // Only generate recaptcha_get_html() if we're not using the AJAX API.
143
          $html = recaptcha_get_html($recaptcha_public_key, NULL, TRUE);
144
          $captcha['form']['captcha_form'] = array(
145
            '#type' => 'item',
146
            '#markup' => (!empty($recaptcha_custom_html) ? '<div id="recaptcha_custom_theme_widget">' . $recaptcha_custom_html . '</div>' : '') . $html,
147
          );
148
        }
149
        else {
150
          $captcha['form']['captcha_form'] = array(
151
            '#type' => 'item',
152
            // Create the destination container, inserting any custom theme HTML
153
            // necessary ($recaptcha_custom_html will be empty if we are not
154
            // using custom theme).
155
            '#markup' => '<div id="recaptcha_ajax_api_container">' . $recaptcha_custom_html . '</div>',
156
          );
157
          drupal_add_js('https://www.google.com/recaptcha/api/js/recaptcha_ajax.js', array('type' => 'external'));
158
          $recaptcha_options['public_key'] = $recaptcha_public_key;
159
          $recaptcha_options['container'] = 'recaptcha_ajax_api_container';
160
          drupal_add_js(array('recaptcha' => $recaptcha_options), 'setting');
161
          drupal_add_js(drupal_get_path('module', 'recaptcha') . '/recaptcha.js');
162
        }
163
      }
164
      return $captcha;
165
  }
166
}
167

    
168
/**
169
 * @return bool
170
 *   TRUE if the reCAPTCHA server is up, FALSE otherwise.
171
 */
172
function _recaptcha_test_recaptcha_server() {
173
  $response = drupal_http_request('https://' . RECAPTCHA_VERIFY_SERVER);
174
  if (empty($response->error)) {
175
    return TRUE;
176
  }
177
  else {
178
    watchdog('reCAPTCHA', 'Unable to connect with the reCAPTCHA server (@server): @errno: @errstr', array(
179
      '@server' => RECAPTCHA_VERIFY_SERVER,
180
      '@errno' => $response->code,
181
      '@errstr' => $response->error,
182
    ), WATCHDOG_ERROR);
183
    return FALSE;
184
  }
185
}
186

    
187
/**
188
 * Return the cached output of _recaptcha_test_recaptcha_server().
189
 *
190
 * @return bool
191
 *   TRUE if the reCAPTCHA server was up last time it was checked, FALSE
192
 *   otherwise.
193
 */
194
function _recaptcha_server_is_up() {
195
  static $server_status;
196
  // Use static cache value, if available.
197
  if (isset($server_status)) {
198
    return $server_status;
199
  }
200
  // Check if the status is cached already.
201
  $status_cache = cache_get('recaptcha_server_status');
202
  if ($status_cache !== FALSE) {
203
    $server_status = (bool) $status_cache;
204
    return $server_status;
205
  }
206
  // Status is not cached. Check if server is up.
207
  $server_status = _recaptcha_test_recaptcha_server();
208

    
209
  // Set to 5 minutes, if interval is not set.
210
  $cache_period = variable_get('recaptcha_server_status_check_interval', 5);
211
  // Save it as integer as cache_get returns FALSE, if not found.
212
  cache_set('recaptcha_server_status', (int) $server_status, 'cache', time() + ($cache_period * 60));
213
  return $server_status;
214
}
215

    
216
/**
217
 * CAPTCHA Callback; Validates the reCAPTCHA code.
218
 */
219
function recaptcha_captcha_validation($solution = NULL, $response = NULL) {
220
  global $user;
221
  $recaptcha_private_key = variable_get('recaptcha_private_key', FALSE);
222
  $ip_address = ip_address();
223
  if ($recaptcha_private_key && $ip_address && $response === 'reCAPTCHA' && !empty($_POST['recaptcha_challenge_field']) && !empty($_POST['recaptcha_response_field']) && _recaptcha_server_is_up()) {
224
    $resp = recaptcha_check_answer(
225
      $recaptcha_private_key,
226
      $ip_address,
227
      check_plain($_POST['recaptcha_challenge_field']),
228
      check_plain($_POST['recaptcha_response_field'])
229
    );
230
    return $resp->is_valid;
231
  }
232
  return FALSE;
233
}
234

    
235
/**
236
 * Implements hook_theme().
237
 */
238
function recaptcha_theme() {
239
  return array(
240
    'recaptcha_custom_widget' => array(
241
      'arguments' => array(),
242
    ),
243
  );
244
}
245

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

    
272
/**
273
 * Load the recaptcha library.
274
 */
275
function _recaptcha_load_library() {
276
  return module_load_include('php', 'recaptcha', 'recaptcha-php-1.11/recaptchalib');
277
}