CMSのポテンシャルを引き出す─MODxで作る商用サイト

第17回MODxのスニペットを使いこなす─FormIT[その3]

はじめに

FormITの解説は今回でいったん終わりです。退屈されている方もいらっしゃるかもしれませんが、FormITは挙動がわかりやすいスニペットで、MODx全体を理解するのにも役立ちますので、今しばらくお付き合いください。

二重投稿を防止する

前回までのようなメールフォームを作成した場合、データ送信後に誤ってブラウザのリロードボタンが押されてしまうと、同じ内容がポストされてしまい、挙動としてはあまり美しくありませんし、大量のspam投稿が発生する可能性もあります。

こちらもカスタムのフックを活用することで、二重投稿を防止させることができます。二重投稿を防止させるための方法はいくつか考えられるでしょうが、今回は投稿時の「名前」⁠メールアドレス」⁠投稿内容」を連結した文字列のMD5ハッシュを作成し、セッション中に前回保存されたハッシュ値があれば比較、値が同じであれば、エラーを出力、そうでない場合は改めてセッションの内容を更新する、という形にしてみました。

リスト1 スニペット名: DenyDuplicatedForm
<?php
// 投稿内容を取得し、連結文字列のハッシュ値を生成
$name = $hook->getValue('name');
$email = $hook->getValue('email');
$message = $hook->getValue('message');
$cur_md5 = md5($name . $email . $message);

// 作成したハッシュ値がすでにセッション中に存在する場合は二重投稿とみなす
if ($_SESSION['prev_md5'] == $cur_md5) {
  $hook->addError('customError', 'フォームはすでに投稿済みです');
  return false;
}
else {
  $_SESSION['prev_md5'] = $cur_md5;
  return true;
}

フォーム用のリソースは例のごとく、次のようになります。スニペット中で定義している

$hook->addError('customError', 'フォームはすでに投稿済みです');

というエラーは、[[!+fi.error.customError]]という形で表示させることができますので、任意の場所にこのタグを挿入しておきます。

リスト2 問い合わせフォームリソースの内容(赤字が追加部分)
[[!FormIt?
 &hooks=`DenyDuplicatedForm,SetPostdate,email,FormItAutoResponder`
 &emailTpl=`formit_mailbody`
 &emailSubject=`【お茶のなかみつ園】お問い合わせありがとうございます`
 &emailTo=`user@example.com`
 &emailToName=`お茶のなかみつ園`
 &fiarTpl=`formit_mailbody`
 &fiarSubject=`【お茶のなかみつ園】お問い合わせありがとうございます`
 &fiarFrom=`noreply@example.com`
 &validate=`name:required,
      email:email:required,
      message:required`
 &name.vTextRequired=`■ 名前の入力は必須です。<br />`
 &email.vTextRequired=`■ メールアドレスの入力は必須です。<br />`
 &message.vTextRequired=`■ 問い合わせ内容の入力は必須です。<br />`
 &successMessage=`<p>お問い合わせを受け付けました。</p>`
]]
<div class="success" style="color: #ff0000;">[[!+fi.successMessage]]</div>
<div class="error" style="color: #ff0000;">[[!+fi.error.customError ]]</div>
-- 略 --

投稿後、リロードボタンを押した場合の挙動は次のようになります。

図1 二重投稿が発生した場合のエラー
図1 二重投稿が発生した場合のエラー

メールアドレスの再確認

問い合わせフォームの中には、投稿者のメールアドレスをなるべく正確に取得するため、

  • メールアドレス
  • メールアドレス(確認用)

の2つのテキストボックスを用意しておき、両方の値がマッチした場合に投稿を受け付ける、というものがあります。

これまでの練習内容から大体想像がつくかもしれませんが、カスタムフックを使用することで、このようなフォームも簡単に実現できます。

リスト3 スニペット名: CheckMailAddr
<?php
$email = $hook->getValue('email');
$email2 = $hook->getValue('email2');
if ($email != $email2) {
  $hook->addError('email2', '入力されたメールアドレスが異なります');
  return false;
}
return true;

問い合わせフォームの内容は次のようになります。今回は解説の都合上、スタイルシートファイルを用意していませんので、HTML中にspanタグや文字色を直接ハードコードしていますが、実際には文字の装飾などはCSSファイル側で指定したほうがスマートでしょう。

リスト4 問い合わせフォームリソースの内容(赤字が追加部分)
[[!FormIt?
 &hooks=`DenyDuplicatedForm,CheckMailAddr,SetPostdate,email,FormItAutoResponder`
 &emailTpl=`formit_mailbody`
 &emailSubject=`【お茶のなかみつ園】お問い合わせありがとうございます`
 &emailTo=`user@example.com`
 &emailToName=`お茶のなかみつ園`
 &fiarTpl=`formit_mailbody`
 &fiarSubject=`【お茶のなかみつ園】お問い合わせありがとうございます`
 &fiarFrom=`noreply@example.com`
 &validate=`name:required,
      email:email:required,
      email2:email:required,
      message:required`
 &name.vTextRequired=`■ 名前の入力は必須です。<br />`
 &email.vTextRequired=`■ メールアドレスの入力は必須です。<br />`
 &email2.vTextRequired=`■ 確認用に同じメールアドレスを入力してください。<br />`
 &message.vTextRequired=`■ 問い合わせ内容の入力は必須です。<br />`
 &successMessage=`<p>お問い合わせを受け付けました。</p>`
]]
<div class="success" style="color: #ff0000;">[[!+fi.successMessage]]</div>
<div class="error" style="color: #ff0000;">[[!+fi.error.customError]]</div>
<form class="form" action="[[~[[*id]]]]" method="post">
<table id="contactform">
<tbody>
<tr><th>お名前<span style="color: #ff2222;">*</span></th>
<td><input id="name" type="text" name="name" value="[[!+fi.name]]" /><br /><span class="error" style="color: #ff0000;">[[!+fi.error.name]]</span></td>
</tr>
<tr><th>メールアドレス<span style="color: #ff2222;">*</span></th>
<td><input id="email" type="text" name="email" value="[[!+fi.email]]" /><br /><span class="error" style="color: #ff0000;">[[!+fi.error.email]]</span></td>
</tr>
<tr><th>メールアドレス(確認用)<span style="color: #ff2222;">*</span></th>
<td><input id="email2" type="text" name="email2" value="[[!+fi.email2]]" /><br /><span class="error" style="color: #ff0000;">[[!+fi.error.email2]]</span></td>
</tr>
<tr><th>問い合わせ内容<span style="color: #ff2222;">*</span></th>
<td><textarea id="message" name="message" rows="7" cols="35">[[!+fi.message]]</textarea><br /><span class="error" style="color: #ff0000;">[[!+fi.error.message]]</span></td>
</tr>
<tr><th> </th>
<td><input id="submit" type="submit" name="submit" value="送信" /></td>
</tr>
</tbody>
</table>
</form>

また、これに合わせてDenyDuplicatedFormフックの内容も少し変更しておいたほうが良いでしょう。

リスト5 DenyDuplicatedFormフックの一部
--- 略 ---
$email2 = $hook->getValue('email2');
--- 略 ---
$cur_md5 = md5($name . $email . $email2 . $message);

画面の様子は次のようになります。

図2 メールアドレスが異なる場合のエラー画面
図2 メールアドレスが異なる場合のエラー画面

最後に

以上、3回に渡ってFormITスニペットの解説を行ってきましたが、メールフォームとはいえ非常に奥が深いことがご理解いただけたのではないかと思います。一点だけ注意点があるとすれば、スニペットのバージョンアップ時の挙動や仕様が変更になる可能性があるということです。FormITに限った話ではありませんが、バージョンアップ前には必ずバックアップをとるようにしておきましょう。

おすすめ記事

記事・ニュース一覧