reCAPTCHAでメール保護

メールアドレスを保護する際に皆さんはどうしているでしょうか？

* 画像化する
* @マークを別の文字にする
* その他・・・

いろいろあると思いますが、`<a href="mailto:hoge@fuga.com">mail</a>`をHTML文中に書けないのは間違いないと思います。
ですがこれだとユーザビリティの低下を招いていると私は思います。

手間は同じかもしれないが、すぐにメールが送れる手段としては[Mailhide](https://mailhide.io/)や[captchas.net](http://captchas.net/)がありますが、クライアントとしてみればなぜ外部サイトへわざわざ飛ばされないといけないのかと疑問を持つでしょう。

なら、自分のサイト内で完結するシステムを作りましょう！！

##reChaptchaのコードを取得
[ウェブサイトにキャプチャを導入する方法【reCAPTCHAの使い方】](http://syncer.jp/how-to-introduction-recaptcha)
上記のサイトのほうが圧倒的に詳しいのでコード取得の説明はこちらにお任せいたします。

##まずは基礎となるHTML
jQueryは2.1.4を使用していますが1.11.4でもできることは確認済みです。

```html:test.html
<!DOCTYPE html>
<html>
<head>
<title>メール認証テスト</title>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />

<script src="https://www.google.com/recaptcha/api.js?hl=ja" async defer></script>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script type="text/javascript">

function scrCallback(code){
    // data-callbackを呼び出すと自動的に引数には認証コードが入る
    if(code != ''){
        // 引数の認証コードが空でなければ
        jQuery('#send').prop("disabled", false);
        // 「メールをする」の部分を送信可能状態にする
        setTimeout(function() {jQuery('#send').prop("disabled", true);}, 120000);
        // reCaptchaは２分間で認証コードがタイムアウトするので「メールする」部分も再度通信不可に
    }
}

jQuery(function ($) {
    $('#send').prop("disabled", true);
    // リロードされても送信不可にするため
    
    $('#send').click(function() {
        // 「メールする」を押します
        $.ajax({
            // POSTでajaxします
            type: 'POST',
            url: 'recaptcha.php',
            data: $('#form').serialize(),
            dataType: 'json',
            success: function(data, dataType) {
                $('#send').remove();
                // リロードしないと再取得できないように対策
                
                if (data.success == true) {
                    var mail = data.mail;
                    $('#insert').append('<a href="mailto:' + mail + '"></a>');
                    $('#insert a').text(mail);
                    setTimeout(function() {
                        $('#insert a').remove();
                        $('#insert').append('<p>メールを再度表示するにはリロードして下さい</p>');}, 60000);
                    // １分でタイムアウト
                    
                } else {
                    $('#insert').append('<p>' + data.error + '</p>');
                    // エラー表示
                }
            },
            error: function(XMLHttpRequest, textStatus, errorThrown) {
                
                //recaptcha.phpと通信できなかった時のエラーメッセージの表示
                alert('Error : ' + errorThrown);
            }
        });
        
        //サブミット後、ページをリロードしないようにする
        return false;
    });
});
</script>

</head>
<body>
<div>

<form id="form" action="" method="POST">
    <div class="g-recaptcha" data-callback="scrCallback" data-sitekey="{取得したサイト鍵}"></div>
    <input id="send" type="submit" value="メールする">
</form>

<div id="insert"><!-- ここにメッセージが入ります --></div>

</div>
</body>
</html>
```

HTMLはこんな感じ。
Ajaxすることによって完全にページ内に、安全に表示することができます。
レスポンスが100msを超えますけど（ローカル実測平均160ms程度／外部実測190ms程度【ともに10回試行の平均値】）そこまで苛つくレベルではないでしょう。

##通信するrecaptcha.php

```php:recaptcha.php
<?php
    
    require_once dirname(__FILE__).'/isAjax.php';
    
    $secret_key = '{取得した秘密鍵}';
    $mail_address = 'hogehoge@gmail.com';
    
    if (isset($_POST['g-recaptcha-response']) && !empty($_POST['g-recaptcha-response']) &&
        is_string($_POST['g-recaptcha-response'])) {
        $response_key = $_POST["g-recaptcha-response"];
    } else {
        $response_key = '';
    }
    # ここまでの操作はデフォですね
    
    $endpoint = "https://www.google.com/recaptcha/api/siteverify?secret={$secret_key}&response={$response_key}";
    $json_str = @file_get_contents($endpoint);
    # 二度目以降の取得はどうやらfalseが返ってくるようなので、エラーでも何でも取得
    
    if ($json_str !== false) {
        $tmp = json_decode($json_str, true);
        
        if ($tmp['success'] == false) {
            $json = json_encode(array('success' => false, 'error' => '不正な操作が行われた可能性があります'));
            # *1 プログラム欄外に記載
        } else {
            $json = json_encode(array('success' => true, 'mail' => $mail_address));
        }
        
    } else {
        $json = json_encode(array('success' => false, 'error' => '通信エラーです'));
    }
    
    header('X-Content-Type-Options: nosniff');
    header('Content-type: application/json; charset=utf-8');
    
    if (isAjax()) {
        echo $json;
    } else {
        echo json_encode(array('success' => false, 'error' => 'Ajax通信のみです'));
    }
    # どこに置くかはわかりませんが一応JSONハイジャック対策
    
    exit;
```

```php:isAjax.php
<?php
    function isAjax(){
        if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
           strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
            return true;
        }
    return false;
    }
```

\# *1 ：successがfalseだった場合error-codesというものが返ってくるのですが、jsでdata.error-codesとするとエラるので書き直します

##で、どうなるのさ？
管理人さんにメールしたいなぁ・・・（企業ならサポセンですかねぇ？）
ﾍ(ﾟдﾟ)ﾉ ﾅﾆｺﾚ?チェックしたらいいの？
（ココらへんもフォームの中にどうしたらいいか書いておいたほうが丁寧でしょうね。）
![125.png](https://qiita-image-store.s3.amazonaws.com/0/73791/64f5576e-ff95-9faa-563f-bbf69426696c.png)

チェックしたぜ！！
ポチッ(。^_^)σ【メールする】
![126.png](https://qiita-image-store.s3.amazonaws.com/0/73791/2678a79e-70c4-4306-4fa6-f94cb9e93556.png)

(ﾟ∀ﾟ)メルアド出た！
![127.png](https://qiita-image-store.s3.amazonaws.com/0/73791/f9df0dcc-b81c-3cd5-c3eb-c6abb8432901.png)

〜おまけ（１分後）〜
(ﾟДﾟ)消えた！！
![128.png](https://qiita-image-store.s3.amazonaws.com/0/73791/84f8f0bb-17e5-5ec3-8f4c-62dbd43f6542.png)

##結果
メールクローラーボットには多分補足されなくなります。