問い合わせフォームにreCaptchaをくっつけてスパムを防止するPHP

reCaptchaでbotからの送信を防ぐ

フォームにreCaptchaは必須だと思ってる

送信確認画面を構築するのも面倒くさい

WordPressなどのCMSを使っていると、プラグインなどでフォーム機能も簡単に実装できますが、過去記事でも書いたようなSilexなどで自作でWebサイトを構築する場合、自分でフォーム機能も実装しないといけません。

mailtoで問い合わせさせているのは論外中の論外なのですが、フォームはスパムの踏み台として使われる可能性があるため、送信確認画面を設けるなどして、botからの送信を防ぐ必要があります。

しかしそれはそれで面倒くさい。

クリックひとつでbotを防いでくれる

reCaptchaは、チェックボックスをクリックしてチェックを入れるだけでbotからのスパム送信を防いでくれます。Googleさんが提供しているサービスなので、安心して利用できると思います。

Google reCaptcha

PHPでフォームに組み込んでみる

reCaptchaの流れ

reCaptchaには、判別タイミングが3つほどあります。ここではフォーム送信時判別する方法で組み込んでいきます。大まかな流れをこうです。

  1. HTMLでreCaptchaウィジェットの読み込み・表示
    <div class="g-recaptcha" data-sitekey="SITE_KEY"></div>
  2. reCaptchaウィジェットがクリックされる
  3. 問題がなければ、reCaptchaはレスポンスコードを生成し、POST変数に値を保持する
  4. フォーム送信時にreCaptchaが保持したレスポンスコードを判別
  5. OKなら、そのままフォームを送信する

独自のRecaptchaクラスを作った

<?php
namespace MyApp\Recaptcha;

class Recaptcha
{
  private $_api = "https://www.google.com/recaptcha/api/siteverify";

  private $_response;
  private $_secret;
  private $response = array();

  // レスポンスコードを引数に受け取る
  function __construct($response)
  {
    // シークレットキーは他のファイルに保存しておき、
    // それを読み込ませても可。
    $_secret = "YOUR SECRET KEY";
    $_response = $response;

    // reCaptcha APIに問い合わせ
    $response_obj = $this->_verify($_secret, $_response);

    // レスポンスコードのプロパティからハイフンと取り除く
    // 扱いやすくするためだけの処理。なくても可。
    foreach ($response_obj as $key => $value) {
      $key = str_replace("-", "", $key);
      $this->response[$key] = $value;
    }
  }

  // アクセサメソッド
  function __get($prop)
  {
    $response = $this->response;
    if(!array_key_exists($prop, $response))
      throw new \Exception("Invalid Property: Recaptcha::{$prop}");

    return $response[$prop];
  }

  // 実際にreCaptcha APIにアクセスするメソッド
  private
  function _verify($secret, $response)
  {
    $postfields = array(
      "secret" => $secret,
      "response" => $response
    );

    $ch = curl_init();

    // reCaptcha APIのURLを指定
    curl_setopt($ch, CURLOPT_URL, $this->_api);

    // アクセス先からの返ってきた値を返す
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    // POSTメソッドを使用
    curl_setopt($ch, CURLOPT_POST, true);

    // POSTで送信する値
    curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields);

    // curlの実行
    // falseが返ってくれば例外を投げる
    if(!$res = curl_exec($ch)){
      throw new \Exception("Recaptcha: Verifing Error");
      return null;
    }

    // JSONオブジェクトを連想配列にして返す
    return json_decode($res, true);
  }

}

?>

このクラスをフォーム送信部分のPHPコードに組み込みます。

// reCaptchaからのレスポンスコードは、$_POST['g-recaptcha-response']に格納されている
$recaptcha_response = $_POST['g-recaptcha-response'];

// クラス読み込み
$recaptcha = new Recaptcha($recaptcha_response);
if($recaptcha->success !== true) {
  // reCaptcha失敗時の処理
}

// 成功時
// フォーム送信処理をおこなう

フォーム送信時に reCaptcha API との通信を行い、そこから返ってきた値を元に不適切な送信元かを判別、処理を振り分けます。

reCaptchaの判別レベル

2.0で文字の入力が不要に

reCaptcha1.0
1.0では、上記のように画像に表示された文字を入力させていました。

2.0では、文字入力が不要になり、reCaptchaの設定次第ではチェックボックスをクリックするだけで認証ができるようになりました。

デフォルトでは、下記のような指定された画像をクリックさせる仕様となってます。
reCaptcha2.0

(Visited 444 times, 1 visits today)