reCAPTCHA V2

  1. Moodle 2.x 原使用 reCAPTCHA V1,但 reCAPTCHA V1 已 shutdown,要使用 reCAPTCHA V2 必須自行修改 moodle 程式碼,且必須到 google recaptcha 網站申請一個對外的 site key 與一個驗證用的secret key
  2. 在 moodle 2.x 認證方式中填寫取得的 ReCAPTCHA 公鑰及 ReCAPTCHA 私鑰。
    頁面路徑
    
        回到首頁
        / ► 網站管理
        / ► 外掛程式
        / ► 身份認證
        / ► 管理認證方式
    	
    	ReCAPTCHA 公鑰 ==> YOUR SITE KEY
    	ReCAPTCHA 私鑰 ==> YOUR SECRET KEY
    
  3. 在 moodle lib 目錄下載 reCAPTCHA V2 的 recaptchalib.php 檔,取代原 V1 版本的 recaptchalib.php。
    [root@dywang lib]# wget --no-check-certificate -O recaptchalib.php \
    https://raw.githubusercontent.com/Mim0oo/PHPreCAPTCHA/master/recaptchalib.php
    
  4. 修改 moodle lib/recaptchalib.php,$curl->get_errno()->get_errno
    [root@dywang moodle23]# diff -uN lib/recaptchalib_v2.php lib/recaptchalib.php 
    --- lib/recaptchalib_v2.php	2019-02-27 18:41:19.469687248 +0800
    +++ lib/recaptchalib.php	2019-03-05 11:47:15.224470978 +0800
    @@ -174,7 +174,7 @@
         $curl = new curl();
         $curlresponse = $curl->post($verifyurl, $params);
     
    -    if ($curl->get_errno() === 0) {
    +    if ($curl->get_errno === 0) {
             $curldata = json_decode($curlresponse);
     
             if (isset($curldata->success) && $curldata->success === true) {
    
  5. 修改 moodle lib/form/recaptcha.php 的顯示及驗證函式,依目前頁面語系顯示 reCAPTCH 頁面。
    [root@dywang moodle23]# diff -uNwB ../moodle23.bak/lib/form/recaptcha.php lib/form/recaptcha.php
    --- ../moodle23.bak/lib/form/recaptcha.php	2012-06-26 01:14:43.000000000 +0800
    +++ lib/form/recaptcha.php	2019-03-05 12:01:10.195188235 +0800
    @@ -83,31 +82,14 @@
             }
             $error = $attributes['error_message'];
             unset($attributes['error_message']);
    -
    -        $strincorrectpleasetryagain = get_string('incorrectpleasetryagain', 'auth');
    -        $strenterthewordsabove = get_string('enterthewordsabove', 'auth');
    -        $strenterthenumbersyouhear = get_string('enterthenumbersyouhear', 'auth');
    -        $strgetanothercaptcha = get_string('getanothercaptcha', 'auth');
    -        $strgetanaudiocaptcha = get_string('getanaudiocaptcha', 'auth');
    -        $strgetanimagecaptcha = get_string('getanimagecaptcha', 'auth');
    +		$lang = recaptcha_lang(current_language());
     
             $html .= '
    -<div id="recaptcha_widget" style="display:none">
    -
    -<div id="recaptcha_image"></div>
    -<div class="recaptcha_only_if_incorrect_sol" style="color:red">' . $strincorrectpleasetryagain . '</div>
    -
    -<span class="recaptcha_only_if_image"><label for="recaptcha_response_field">' . $strenterthewordsabove . '</label></span>
    -<span class="recaptcha_only_if_audio"><label for="recaptcha_response_field">' . $strenterthenumbersyouhear . '</label></span>
    +      <script src="https://www.google.com/recaptcha/api.js?onload=recaptchacallback&hl='. $lang .'" async defer></script>
    +      <div class="g-recaptcha" data-sitekey="'.$CFG->recaptchapublickey .'"></div>
    +      <input type="submit" value="Submit">';
     
    -<input type="text" id="recaptcha_response_field" name="recaptcha_response_field" />
    -<input type="hidden" name="recaptcha_element" value="dummyvalue" /> <!-- Dummy value to fool formslib -->
    -<div><a href="javascript:Recaptcha.reload()">' . $strgetanothercaptcha . '</a></div>
    -<div class="recaptcha_only_if_image"><a href="javascript:Recaptcha.switch_type(\'audio\')">' . $strgetanaudiocaptcha . '</a></div>
    -<div class="recaptcha_only_if_audio"><a href="javascript:Recaptcha.switch_type(\'image\')">' . $strgetanimagecaptcha . '</a></div>
    -</div>';
    -
    -        return $html . recaptcha_get_html($CFG->recaptchapublickey, $error, $this->_https);
    +        return $html; // . recaptcha_get_html($CFG->recaptchapublickey, $error, $this->_https);
         }
    
  6. 修改 moodle lib/form/recaptcha.php 的驗證函式。
    @@ -133,25 +115,22 @@
         }
     
         /**
    -     * Checks input and challenged field
    +     * Checks recaptcha response with Google.
          *
    -     * @param string $challenge_field recaptcha shown  to user
    -     * @param string $response_field input value by user
    +     * @param string $responsestr
          * @return bool
          */
    -    function verify($challenge_field, $response_field) {
    +    public function verify($responsestr) {
             global $CFG;
    -        require_once $CFG->libdir . '/recaptchalib.php';
    -        $response = recaptcha_check_answer($CFG->recaptchaprivatekey,
    -                                           getremoteaddr(),
    -                                           $challenge_field,
    -                                           $response_field,
    -                                           $this->_https);
    -        if (!$response->is_valid) {
    +        require_once($CFG->libdir . '/recaptchalib.php');
    +
    +        $response = recaptcha_check_response(RECAPTCHA_VERIFY_URL, $CFG->recaptchaprivatekey,
    +                                           getremoteaddr(), $responsestr);
    +        if (!$response['isvalid']) {
                 $attributes = $this->getAttributes();
    -            $attributes['error_message'] = $response->error;
    +            $attributes['error_message'] = $response['error'];
                 $this->setAttributes($attributes);
    -            return $response->error;
    +            return $response['error'];
             }
             return true;
         }
    
  7. reCAPTCHA V2 驗證函式不同,必須修改 login/signup_form.php 中啟動 reCAPTCH 時的驗證程式。
    [root@dywang moodle23]# diff -uN ../moodle23.bak/login/signup_form.php login/signup_form.php 
    --- ../moodle23.bak/login/signup_form.php	2012-08-19 15:20:40.000000000 +0800
    +++ login/signup_form.php	2019-03-05 11:34:25.069754509 +0800
    @@ -172,15 +172,14 @@
             }
     
             if ($this->signup_captcha_enabled()) {
    -            $recaptcha_element = $this->_form->getElement('recaptcha_element');
    -            if (!empty($this->_form->_submitValues['recaptcha_challenge_field'])) {
    -                $challenge_field = $this->_form->_submitValues['recaptcha_challenge_field'];
    -                $response_field = $this->_form->_submitValues['recaptcha_response_field'];
    -                if (true !== ($result = $recaptcha_element->verify($challenge_field, $response_field))) {
    -                    $errors['recaptcha'] = $result;
    +            $recaptchaelement = $this->_form->getElement('recaptcha_element');
    +            if (!empty($this->_form->_submitValues['g-recaptcha-response'])) {
    +                $response = $this->_form->_submitValues['g-recaptcha-response'];
    +                if (!$recaptchaelement->verify($response)) {
    +                    $errors['recaptcha_element'] = get_string('incorrectpleasetryagain', 'auth');
                     }
                 } else {
    -                $errors['recaptcha'] = get_string('missingrecaptchachallengefield');
    +                $errors['recaptcha_element'] = get_string('missingrecaptchachallengefield');
                 }
             }
             // Validate customisable profile fields. (profile_validation expects an object as the parameter with userid set)
    
    Image recaptchav2