WordPress|Contact Form 7 で日本語文字数の割合を指定しスパムを最大限に防ぐ

WordPress で問合せフォームを設置する時に使用する定番プラグインと言えば、「Contact Form 7」。簡単な設定だけですぐにフォームが設置できるものの、何も対策をせずに放置していてスパムが来るようになり頭を抱えている人もいるのではないかと思います。もし今大丈夫でも、ある日突然スパムが来るようになる可能性が高いので今のうちから対策しておきましょう。

ここで紹介する対策は、メールの本文に日本語が含まれていない場合はエラーを返しメール送信できないようにするというものです。WordPress 5.4 で動作確認済み。もし英語のメールを受け取ることを想定しているような場合は、最後に紹介する「Contact Form 7」の「クイズ」機能を使った方法を試してください。

日本語/全角の割合をチェック(厳しめ)

日本語が含まれていない場合にエラーを返す方法については、いくつかのサイトで紹介されていますが、それらは日本語が1文字以上入ってさえいれば送信できてしまうものが多いため、ここでは日本語/全角文字が全体の文字数に対して特定の割合以上含まれているかどうかチェックするという少し厳しめのバリデーションを紹介します。

各コードの$field_name = ‘your-message’;の部分は、利用しているフォームのチェックしたいフィールド名に変更してください。

日本語が指定の割合以上含まれているかチェック

下記の例では、正規表現で指定したぁ-んァ-ヶー一-龠0-9、。のとおり、「ひらがな」「カタカナ」「漢字」「全角数字」「、」「。」にマッチする文字が全体の50%未満の場合はエラーを返すようにしています。

50% ルールは、ルー大柴(古っ)みたいに、チョイチョイ英単語を混ぜるような人でない限りまずはエラーにはなりませんが、心配であれば$min_rate = 30;(30%)などに下げておいても良いでしょう。

function wpcf7_validate_mb_char( $result, $tag ) {
	$field_name	= 'your-message'; //チェックしたいフォームフィールド名
	$value		= str_replace(array("\r", "\n", ' ', ' '), '', $_POST[$field_name]); //改行とスペースを取り除く
	$min_rate	= 50; //(%)最小日本語文字数の割合(これ以上でなければエラー)
	$str_l		= mb_strlen($value , "UTF-8"); // 文字数取得(ダブルクオーテーション必須)
	$str_ja		= preg_match_all("/[ぁ-んァ-ヶー一-龠0-9、。]/u", $value, $matches); //日本語の文字数を取得
	$str_mb_rate	= ($str_ja / $str_l) * 100; // 日本語文字数の割合を計算

	if (!empty($value)) {
		if ($str_mb_rate < $min_rate) {
			$result['valid'] = false;
			$result['reason'] = array($field_name => '日本語以外の言語が多く含まれています');
		}
	}
	return $result;
}
add_filter( 'wpcf7_validate', 'wpcf7_validate_mb_char', 10, 2 );

全角文字が特定の割合以上含まれているかチェック

これは日本語かどうかではなく、全角かどうかのチェックです。

mb_strwidth 関数は、半角を1、全角を2とした文字列の幅を返し、mb_strlen 関数は、半角全角に関係なく文字数を返すため、mb_strwidth – mb_strlenで全角の文字数を取得することができます。

ただし、mb_strwidth 関数は韓国語や中国語も全角として扱うということ、また一部の日本語記号を半角として扱う特徴があります。より厳密に日本語だけに限定したい場合は上のコードを使いましょう。

function wpcf7_validate_mb_char( $result, $tag ) {
	$field_name	= 'your-message'; //チェックしたいフォームフィールド名
	$value		= str_replace(array("\r", "\n", ' ', ' '), '', $_POST[$field_name]); //改行とスペースを取り除く
	$min_rate	= 50; //(%)最小日本語文字数の割合(これ以上でなければエラー)
	$str_l		= mb_strlen($value , "UTF-8"); // 文字数取得(ダブルクオーテーション必須)
	$str_w		= mb_strwidth($value, "UTF-8"); // 文字幅(半角1、全角2でカウント)
	$str_mb		= $str_w - $str_l; // 日本語(マルチバイト)の文字数取得
	$str_mb_rate	= ($str_mb / $str_l) * 100; // 日本語文字数の割合を計算

	if (!empty($value)) {
		if ($str_mb_rate < $min_rate) {
			$result['valid'] = false;
			$result['reason'] = array($field_name => '日本語の割合が少ない' . $str_mb_rate . '/' . $min_rate);
		}
	}
	return $result;
}
add_filter( 'wpcf7_validate', 'wpcf7_validate_mb_char', 10, 2 );

日本語/全角が含まれるかチェック(緩め)

一応参考までに、他サイトで紹介されているような方法も紹介しておきます。これは文字数の割合はチェックしていないため、たとえ1文字だけでもバリデーションを通過する文字列が含まれれば送信できてしまいます。しかし通常はこれで十分だと思います。

ひらがなが含まれているかチェック

正規表現で、ひらがなが1文字以上含まれているかどうかチェックし、なければエラーを返します。

function wpcf7_validate_mb_char( $result, $tag ) {
	$field_name	= 'your-message'; //チェックしたいフォームフィールド名
	$value		= str_replace(array("\r", "\n", ' ', ' '), '', $_POST[$field_name]); //改行とスペースを取り除く

	if (!empty($value)) {
		if (!preg_match('/[ぁ-ん]/u', $value)) {
			$result['valid'] = false;
			$result['reason'] = array($field_name => '日本語でお願いします');
		}
	}
	return $result;
}
add_filter( 'wpcf7_validate', 'wpcf7_validate_mb_char', 10, 2 );

半角英数字のみかどうかチェック

半角英数字のみだった場合はエラーを返します。半角英数字以外の文字列が1文字でも含まれていれば許可されるため、この中では一番緩いバリデーションとなります。

function wpcf7_validate_mb_char( $result, $tag ) {
	$field_name	= 'your-message'; //チェックしたいフォームフィールド名
	$value		= str_replace(array("\r", "\n", ' ', ' '), '', $_POST[$field_name]); //改行とスペースを取り除く

	if (!empty($value)) {
		if (preg_match('/^[!-~]+$/', $value)) {
			$result['valid'] = false;
			$result['reason'] = array($field_name => '日本語でお願いします');
		}
	}
	return $result;
}
add_filter( 'wpcf7_validate', 'wpcf7_validate_mb_char', 10, 2 );

Contact Form 7 のクイズ機能を使う

「Contact Form 7」の「クイズ」機能を使用することで、スパム対策を実現できます。

特別なコードを追加する必要ないため、比較的簡単に導入できるものの、実は今回紹介した対策法の中では一番強力なスパム対策になり得ます。

フォーム追加の画面で「クイズ」をクリックすると、クイズ設定画面が表示されますので、質問答え半角パイプ(|)で分けて登録します(例:質問|答え)。改行して複数登録しておくと、その内の1つが毎回ランダムで表示されます。

英語のメールを受け取る可能性がある場合など、送信者の使用言語に関係なくスパム対策したい場合は、下記などのクイズを設定すると良いでしょう。

10+5=|15
3×3=|9
100-50=|50

今回紹介した方法以外にもっと画期的な方法などあれば是非コメント欄で教えてください。

この記事を書いた人

日本では主にUNIXサーバーの構築、運用などに携わり、2006年に仕事を辞めてカナダに来てそのまま永住。

カナダでは、日本からカナダに留学や永住、ビジネスで渡航する人たちのサポートを行う傍ら、専門分野+趣味でもあるWeb制作、運用を継続しながら、最近では写真/動画撮影、動画制作、モーショングラフィックなど、新しい分野のスキルアップに励んでいます。

Peas Code は、僕が過去の経験の中で学んだことを、特定の分野に限定せず公開していくことを目的としています。中にはコードに見えてしまうような意味不明な僕独自の理論も含まれますが、知っていると平和になれると言う意味で、Peas(peace → peas) Code と名付けました。これが意味不明か・・・。

僕について、もうちょっと詳細を知りたいという変わった人は[About me]を見てください。

All Comments

  • はじめまして!
    スパム対策として非常に有益な情報を知ることができ
    大変感謝しております。
    ところで素人質問で大変恐縮なのですが

    $field_name = ‘your-message’; //チェックしたいフォームフィールド名

    ここのフィールド名を複数対応にしたい場合
    (your-messageとyour-addressなど)のコード表記は
    どのようにすればよいのでしょうか?

    何卒ご教授いただけますでしょうか。
    よろしくお願いいたします。

    たかぷりん 2021年9月14日 11:38 PM 返信
    • コメントありがとうございます。
      複数の各フィールドをどのような条件でチェックしたいのかによっても処理は変わってくると思いますが、もし全く同じ条件でただ複数フィールドに対応するということであれば、下記のようにループ処理を追加するのがシンプルで分かりやすいのではないかと思います。決してベストな方法とは言えないかもしれませんが・・・一応動作確認はしてあります。

      //例)ひらがなが含まれているかチェック
      function wpcf7_validate_mb_char( $result, $tag ) {

      foreach( $tag as $tag_arr ){
      $field_name = $tag_arr[‘name’];
      if($field_name == “your-message” || $field_name == “your-subject”){ //チェックしたいフィールド名
      $value = str_replace(array(“\r”, “\n”, ‘ ‘, ‘ ’), ”, $_POST[$field_name]); //改行とスペースを取り除く

      if (!empty($value)) {
      if (!preg_match(‘/[ぁ-ん]/u’, $value)) {
      $result[‘valid’] = false;
      $result[‘reason’] = array($field_name => ‘日本語でお願いします’);
      }
      }
      }
      }
      return $result;
      }

      hidepooh 2021年9月15日 12:58 PM 返信

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です