サンプル・プログラムの実行例
reCAPTCHAは、この画面で「送信」ボタンをクリックするのがボットではなく、人間であることを判定する。
目次
サンプル・プログラムのダウンロード
SendMessage.php | サンプル・プログラム |
準備:reCAPTCHAの利用登録
reCAPTCHA にはV2とV3があるが、今回は利用者に負担をかけることが少ないV3を使用することにする。
また、Googleアカウントがない方は、事前にアカウントを入手してほしい。
Google reCAPTCHAの右上にある「Admin console」をクリックする。初回は左図のような画面が表示されるので、必要事項を選択し、reCAPTCHA を使用するドメインを入力し、「送信」を押下する。
サイトキー と シークレットキー は、これから作るプログラムで利用するので、記録しておく。
38: //チェックするURLパターン
39: define('PAT_URL', "/^https?\:\/\/[a-z\.]*pahoo\.org/ui");
40:
41: //送信先メールアドレス
42: define('MAIL_TO', '*************');
43:
44: //Google reCAPTCHA v3
45: //https://www.google.com/recaptcha/intro/v3.html から無償入手
46: //サイトキー
47: define('SITE_KEY', '*************');
48: //シークレットキー
49: define('SECRET_KEY', '*************');
50: //トークンネーム(固定)
51: define('TOKEN_NAME', '*************');
今回のプログラムでは、問い合わせ内容をサイト管理者のメールアドレスへ送信する。送信先メールアドレスは定数 MAIL_TO に、問い合わせURLが自サイトかどうかを判別するための正規表現パターンを定数 PAT_URL に、それぞれ定義しておく。
reCAPTCHAの仕組み
取得したトークンと、その他入力データをセットにしてスコア判定プログラム(サーバサイド)に送る。判定プログラムは入手したトークンと、シークレットキーを使い、Google reCAPTCHA サーバにトークン検査を要求する。すると、そのトークンに対応するスコアが返される。スコアの価は0.0以上1.0以下で、おおむね0.5未満はbotの可能性がある。
Google reCAPTCHA サーバがどのような方法でスコア計算しているかは明らかにされていないが、当サイトでは、この reCAPTCHA を導入することで、迷惑メッセージが皆無になったことから、結果として効果を発揮している。
プログラムの流れ
入力チェック画面
311: /**
312: * HTML BODYを作成する - 入力チェック用
313: * @param string $name ニックネーム
314: * @param string $url 関連URL
315: * @param string $message メッセージ
316: * @param bool $private 非公開フラグ
317: * @return string HTML BODY
318: */
319: function makeBodyCheck($name, $url, $message, $private) {
320: $myself = MYSELF;
321:
322: //入力チェック
323: $flag = TRUE;
324: if ($name == '') {
325: $flag = FALSE;
326: $name_msg = '<span class="red">※ニックネームは必須です.入力してください.</span>';
327: } else {
328: $name_msg = '';
329: }
330:
331:
332: if (($title = checkURL($url)) == FALSE) {
333: $flag = FALSE;
334: $url_msg = '<span class="red">※当サイトのURLではありません.再入力してください.</span>';
335: } else {
336: $url_msg = '';
337: }
338:
339: if ($message == '') {
340: $flag = FALSE;
341: $message_msg = '<span class="red">※メッセージは必須です.入力してください.</span>';
342: } else {
343: $message_msg = '';
344: }
345:
346: //非公開フラグの処理
347: $private_msg = $private ? 'メッセージは非公開にする.' : 'メッセージは公開する.';
348: $private = $private ? '<input type="hidden" name="private" value="TRUE" />' : '';
349:
350: //ボタン作成
351: $button = $flag ? '<input type="submit" name="send" value="送信" />' : '';
352:
353: //reCAPTCHA v3対応フォーム
354: $site_key = SITE_KEY;
355: $token_name = TOKEN_NAME;
356: $body =<<< EOD
357: <script src="https://www.google.com/recaptcha/api.js?render={$site_key}"></script>
358: <script>
359: grecaptcha.ready(function() {
360: grecaptcha.execute('{$site_key}',
361: {action:'contact'}).then(function(token) {
362: var token_name = document.getElementById('{$token_name}');
363: token_name.value = token;
364: });
365: });
366: </script>
367: <!-- タイトル -->
368: <h1 class="index1">お問い合わせ内容確認</h1>
369:
370: <!-- 本文 -->
371: <div class="main">
372: <p>
373: ご意見、ご質問、励ましのメッセージを当サイト管理者へ送信します。<br />
374: 下記の内容で問題なければ、「送信」ボタンをクリックしてください。
375: </p>
376:
377: <p>
378: ●ニックネーム {$name_msg}
379: <blockquote class="quote2">{$name}</blockquote>
380: </p>
381: <p>
382: ●関連URL {$url_msg}<span class="blue">{$title}</span>
383: <blockquote class="quote2">{$url}</blockquote>
384: </p>
385: <p>
386: ●メッセージ {$message_msg}
387: <blockquote class="quote2">{$message}</blockquote>
388: ●{$private_msg}
389: </p>
390: <form name="form_message" id="form_message" method="post" action="{$myself}">
391: <div align="center">
392: <input type="submit" name="input" id="input" value="入力画面に戻る" />
393: {$button}
394: </div>
395: <input type="hidden" name="name" id="name" value="{$name}" />
396: <input type="hidden" name="url" id="url" value="{$url}" />
397: <input type="hidden" name="message" id="message" value="{$message}" />
398: <input type="hidden" name="{$token_name}" id="{$token_name}" />
399: {$private}
400: </form>
401:
402: <p align="center">
403: <a href="/" class="footer1 style1">トップページへ戻る</a>
404: </p>
405: </div>
406: </body>
407:
408: EOD;
409: return $body;
410: }
前半で、入力データの検査を行う。
中盤(表示HTMLのbodyタグの冒頭)に、reCAPTCHA にトークン要求をするJavaScriptを記述する。
取得したトークンは定数 TOKEN_NAME で定義されたオブジェクトに格納され、次の画面に渡される。
reCAPTCHA v3 APIからデータ取得
222: /**
223: * reCAPTCHA v3 APIからデータ取得
224: * @param string $token トークン
225: * @return array 応答データ
226: */
227: function get_reCAPTCHA($token) {
228: $secret_key = SECRET_KEY;
229:
230: $ch = curl_init();
231: curl_setopt($ch, CURLOPT_URL, 'https://www.google.com/recaptcha/api/siteverify');
232: curl_setopt($ch, CURLOPT_POST, TRUE);
233:
234: //API パラメータの指定
235: curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array(
236: 'secret' => $secret_key,
237: 'response' => $token
238: )));
239: curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
240:
241: $api_response = curl_exec($ch);
242: curl_close($ch);
243:
244: return json_decode($api_response);
245: }
Google reCAPTCHA は、入力パラメータ(IN)は POST 渡しで、出力結果(OUT)は JSON で戻るというWebAPIである。
URL |
---|
https://www.google.com/recaptcha/api/siteverify |
フィールド名 | 要否 | 内 容 |
---|---|---|
secret | 必須 | シークレットキー |
response | 必須 | トークン |
送信完了
520: //処理分岐
521: if (isset($_POST['check'])) {
522: $HtmlBody = makeBodyCheck($name, $url, $message, $private);
523: } else if (isset($_POST['send'])) {
524: $res = get_reCAPTCHA($token);
525: if (isset($res->success) && $res->success && isset($res->score) && ($res->score >= 0.5)) {
526: $HtmlBody = makeBodySend($name, $url, $message, $private);
527: } else {
528: $HtmlBody = makeBodyFail($name, $url, $message, $private);
529: }
530: } else {
531: $HtmlBody = makeBodyInput($name, $url, $message, $private);
532: }
533:
534: // 表示処理
535: echo $HtmlHeader;
536: echo $HtmlBody;
537: echo $HtmlFooter;
そうでなければ、ユーザー関数 makeBodyFail を実行し、メール送信せずに、送信失敗したことをユーザーに通知する。
前半で、入力データの検査を行う。
参考サイト
- Google reCAPTCHA
- Google reCAPTCHA の使い方(v2/v3):Web Design Leaves
- GoogleのreCAPTCHAはどうやって人間とボットを見分けているのか?:GIGAZINE
みなさんも、サイトの入力画面に左図のロゴが表示されるのをご覧になったことがあるだろう。当サイトでも、「メッセージ受付」画面で reCAPTCHA を利用している。
今回は、PHPを使い、このメッセージ受付画面と同じものを作ってみることにする。