Merge branch 'MDL-74866-311-behat' of https://github.com/HuongNV13/moodle into MOODLE...
[moodle.git] / lib / recaptchalib_v2.php
blob8267fa7cf0fd1c31768b01d3824f6055c7340784
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
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.
8 //
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/>.
31 /**
32 * This is a PHP library that handles calling reCAPTCHA v2.
34 * - Documentation
35 * {@link https://developers.google.com/recaptcha/docs/display}
36 * - Get a reCAPTCHA API Key
37 * {@link https://www.google.com/recaptcha/admin}
38 * - Discussion group
39 * {@link http://groups.google.com/group/recaptcha}
41 * @package core
42 * @copyright 2018 Jeff Webster
43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
46 defined('MOODLE_INTERNAL') || die();
48 /**
49 * The reCAPTCHA URL's
51 define('RECAPTCHA_API_URL', 'https://www.recaptcha.net/recaptcha/api.js');
52 define('RECAPTCHA_VERIFY_URL', 'https://www.recaptcha.net/recaptcha/api/siteverify');
54 /**
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) {
64 if (empty($lang)) {
65 $lang = current_language();
68 $glang = $lang;
69 switch ($glang) {
70 case 'en':
71 $glang = 'en-GB';
72 break;
73 case 'en_us':
74 $glang = 'en';
75 break;
76 case 'zh_cn':
77 $glang = 'zh-CN';
78 break;
79 case 'zh_tw':
80 $glang = 'zh-TW';
81 break;
82 case 'fr_ca':
83 $glang = 'fr-CA';
84 break;
85 case 'pt_br':
86 $glang = 'pt-BR';
87 break;
88 case 'he':
89 $glang = 'iw';
90 break;
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);
96 return $glang;
99 /**
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) {
110 global $CFG, $PAGE;
112 // To use reCAPTCHA you must have an API key.
113 if ($pubkey === null || $pubkey === '') {
114 return get_string('getrecaptchaapi', 'auth');
117 $jscode = "
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'));
131 $return .= $apicode;
133 return $return;
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) {
146 global $CFG;
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);
174 $curl = new curl();
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'] = '';
183 } else {
184 $checkresponse['isvalid'] = false;
185 $checkresponse['error'] = $curldata->{error-codes};
187 } else {
188 $checkresponse['isvalid'] = false;
189 $checkresponse['error'] = 'check-failed';
191 return $checkresponse;