2 // This file is part of Moodle - http://moodle.org/
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16 // This file is part of Moodle - http://moodle.org/
18 // Moodle is free software: you can redistribute it and/or modify
19 // it under the terms of the GNU General Public License as published by
20 // the Free Software Foundation, either version 3 of the License, or
21 // (at your option) any later version.
23 // Moodle is distributed in the hope that it will be useful,
24 // but WITHOUT ANY WARRANTY; without even the implied warranty of
25 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 // GNU General Public License for more details.
28 // You should have received a copy of the GNU General Public License
29 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
32 * This is a PHP library that handles calling reCAPTCHA v2.
35 * {@link https://developers.google.com/recaptcha/docs/display}
36 * - Get a reCAPTCHA API Key
37 * {@link https://www.google.com/recaptcha/admin}
39 * {@link http://groups.google.com/group/recaptcha}
42 * @copyright 2018 Jeff Webster
43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
46 defined('MOODLE_INTERNAL') ||
die();
51 define('RECAPTCHA_API_URL', 'https://www.google.com/recaptcha/api.js');
52 define('RECAPTCHA_VERIFY_URL', 'https://www.google.com/recaptcha/api/siteverify');
55 * Returns the language code the reCAPTCHA element should use.
56 * Google reCAPTCHA uses different language codes than Moodle so we must convert.
57 * https://developers.google.com/recaptcha/docs/language
59 * @param string $lang Language to use. If not provided, get current language.
60 * @return string A language code
62 function recaptcha_lang($lang = null) {
65 $lang = current_language();
92 // For any language code that didn't change reduce down to the base language.
93 if (($lang === $glang) and (strpos($lang, '_') !== false)) {
94 list($glang, $trash) = explode('_', $lang, 2);
100 * Gets the challenge HTML
101 * This is called from the browser, and the resulting reCAPTCHA HTML widget
102 * is embedded within the HTML form it was called from.
104 * @param string $apiurl URL for reCAPTCHA API
105 * @param string $pubkey The public key for reCAPTCHA
106 * @param string $lang Language to use. If not provided, get current language.
107 * @return string - The HTML to be embedded in the user's form.
109 function recaptcha_get_challenge_html($apiurl, $pubkey, $lang = null) {
112 // To use reCAPTCHA you must have an API key.
113 if ($pubkey === null ||
$pubkey === '') {
114 return get_string('getrecaptchaapi', 'auth');
118 var recaptchacallback = function() {
119 grecaptcha.render('recaptcha_element', {
120 'sitekey' : '$pubkey'
124 $lang = recaptcha_lang($lang);
125 $apicode = "\n<script type=\"text/javascript\" ";
126 $apicode .= "src=\"$apiurl?onload=recaptchacallback&render=explicit&hl=$lang\" async defer>";
127 $apicode .= "</script>\n";
129 $return = html_writer
::script($jscode, '');
130 $return .= html_writer
::div('', 'recaptcha_element', array('id' => 'recaptcha_element'));
137 * Calls an HTTP POST function to verify if the user's response was correct
139 * @param string $verifyurl URL for reCAPTCHA verification
140 * @param string $privkey The private key for reCAPTCHA
141 * @param string $remoteip The user's IP
142 * @param string $response The response from reCAPTCHA
143 * @return ReCaptchaResponse
145 function recaptcha_check_response($verifyurl, $privkey, $remoteip, $response) {
147 require_once($CFG->libdir
.'/filelib.php');
149 // Check response - isvalid boolean, error string.
150 $checkresponse = array('isvalid' => false, 'error' => 'check-not-started');
152 // To use reCAPTCHA you must have an API key.
153 if ($privkey === null ||
$privkey === '') {
154 $checkresponse['isvalid'] = false;
155 $checkresponse['error'] = 'no-apikey';
156 return $checkresponse;
159 // For security reasons, you must pass the remote ip to reCAPTCHA.
160 if ($remoteip === null ||
$remoteip === '') {
161 $checkresponse['isvalid'] = false;
162 $checkresponse['error'] = 'no-remoteip';
163 return $checkresponse;
166 // Discard spam submissions.
167 if ($response === null ||
strlen($response) === 0) {
168 $checkresponse['isvalid'] = false;
169 $checkresponse['error'] = 'incorrect-captcha-sol';
170 return $checkresponse;
173 $params = array('secret' => $privkey, 'remoteip' => $remoteip, 'response' => $response);
175 $curlresponse = $curl->post($verifyurl, $params);
177 if ($curl->get_errno() === 0) {
178 $curldata = json_decode($curlresponse);
180 if (isset($curldata->success
) && $curldata->success
=== true) {
181 $checkresponse['isvalid'] = true;
182 $checkresponse['error'] = '';
184 $checkresponse['isvalid'] = false;
185 $checkresponse['error'] = $curldata->{error
-codes
};
188 $checkresponse['isvalid'] = false;
189 $checkresponse['error'] = 'check-failed';
191 return $checkresponse;