Ver. 2.6.0.1 の フォームで不具合が発見されました。

Ver. 2.6.0.1のフォームで1ページに複数のフォームがあると
送信ができない場合がある不具合が発見されました。

対象

  • a-blog cms Ver. 2.6.0.1
  • 一つのページの複数のFormモジュールがある
  • CSRF対策のオプションがON(デフォルト: ON)config.system.yaml : form_csrf_enable

対策

/php/ACMS/GET/Form.php の35行目付近の csrf_tokenメソッド を以下のように修正ください。

フォームで大量のスパムが送信される被害が報告されています


近日 a-blog cms へのフォームで、大量のスパムメールが送信されてしまう報告をいくつか受けております。 被害が発生している方は、以下対応策をいくつか用意していますので、大変お手数ですがご対応のほどお願いいたします。

reCAPTCHA以外の対策は、対応してもスパムが止まらない可能性がございますので、reCAPTCHAの導入をおすすめいたします。

reCAPTCHAの導入

お問い合わせ者が、ロボットか判断するGoogleの「reCAPTCHA」サービスと連携する方法がございます。 a-blog cms の拡張アプリとして用意されていますので、こちらご検討ください。

2021/12/07 19:50追記

reCAPTCHA拡張アプリに一部不具合がありましたので、 2021/12/07 19:50以前にダウンロードしている場合は、お手数ですが再度ダウンロードしてファイルを置き換えをお願いいたします。

ダウンロードURL: https://github.com/appleple/acms-recaptcha/raw/master/build/recaptcha.zip

reCAPTCHAの拡張アプリに関する詳細はGitHubページをご確認ください。


フォームのURL変更

攻撃はURL指定でされる可能性が高いです。根本的な解決にはなりませんが、ひとまず攻撃をさけるためにはフォームのURLを変更ください。

攻撃者のIPアドレスでブロック

.htaccessなどで、攻撃者のIPアドレスをブロックします。ただし複数のIPアドレスで攻撃される可能性が高いのでイタチごっこになってしまう可能性がございます。 order allow,deny allow from all deny from xxx.xxx.xxx.xxx deny from yyy.yyy.yyy.yyy

CMSのアップデート

2.11, 2.10, 2.9, 2.8 のそれぞれのバージョンでセキュリティフィックスをリリースいたしました。これは攻撃方法によって管理画面のフォーム設定の「入力チェック・変換」が効かない場合がある問題が修正されております。CMSアップデート後、フォーム設定の「入力チェック・変換」項目を確認・設定ください。


フォーム設定の修正

フォームのセキュリティ設定について、ドキュメントを更新させていただきました。できるだけ、こちらで紹介されている設定にしていただくようにお願いします。


今後とも a-blog cms をよろしくお願いいたします。

拡張アプリの reCAPTCHA に不具合がみつかりました。


reCAPTCHA拡張アプリに不具合が見つかりました。

2021年12月07日 19:50以前にダウンロードしてされた方は、お手数ですが再度ダウンロードしてファイルを置き換えをお願いいたします。

GitHub: https://github.com/appleple/acms-recaptcha

ダウンロードURL: https://github.com/appleple/acms-recaptcha/raw/master/build/recaptcha.zip

この度はご迷惑をおかけしてしまい申し訳ございません。 ご対応のほどよろしくお願いいたします。

フォームでエントリーなどのカスタムフィールドやグローバル変数を渡すカスタマイズ


フォームの自由度の高さは a-blog cms の特長のひとつです。このエントリーでは、そのカスタマイズの一例として、ユーザーがフォームに入力したフィールド以外の変数の渡し方を解説します。エントリーフィールド、カテゴリーフィールド、ブログフィールドなどのカスタムフィールド、クエリ変数やグローバル変数をフォームの変数として扱えるようにします。

変数を追加するテンプレートの場所

フォームを入力するテンプレートに追加します。公式テーマの site や beginner では /contact/form/input.html になります。初期の入力画面と step#reapply に共通でインクルードされ、追加した変数を途中のステップで表示することもできるようになります。

エントリーフィールドをフォームの変数として追加する

エントリーにフォームがあり、そのエントリーのカスタムフィールドを渡したい場合には、下記のようにコードを追加します。

<!-- BEGIN_MODULE Entry_Field -->

<input type="hidden" name="area" value="{area}">
<input type="hidden" name="field[]" value="area">

<input type="hidden" name="price" value="{price}">
<input type="hidden" name="field[]" value="price">

<!-- END_MODULE Entry_Field -->

area 及び price というエントリーカスタムフィールドがフォームに渡されます。

カテゴリー、ブログ、ユーザーのカスタムフィールドをフォームの変数として追加する

カテゴリー、ブログのカスタムフィールドの場合も、エントリーの場合と同様、フォームに渡すことができます。また、ログインしているユーザーに関しては、ユーザーのカスタムフィールドを渡すこともできます。その場合 ctx="uid/%{SESSION_USER_ID}" を User_Field モジュールに追加します。

<!-- BEGIN_MODULE User_Field ctx="uid/%{SESSION_USER_ID}" -->

<input type="hidden" name="gender" value="{gender}">
<input type="hidden" name="field[]" value="gender">

<!-- END_MODULE User_Field -->

gender というユーザーカスタムフィールドがフォームに渡されます。もちろん {name} や {mail} などのフィールドも渡せるので、ログインしたユーザーであればフォームの項目にいちいち入力させないといったカスタマイズも可能です。

グローバル変数をフォームの変数として追加する

グローバル変数はそのままでメールの返信テンプレートに使用できます。公式テーマでも %{BLOG_NAME} などのグローバル変数が使われています。拡張したグローバル変数の場合も同様です。しかし、グローバル変数もフォームの変数として追加する必要があるケースがあります。

フォームへのリンクにクエリストリングを持たせておけば、どの媒体、どのページからの遷移であるかを確認するなどの使い方ができます。また、Google スプレッドシートとの連携はフォームの件数や項目が多い場合の管理に便利です。

グローバル変数をフォームの変数として追加する書き方は次のとおりです。

<input type="hidden" name="global_var" value="%{GLOBAL_VAR}">
<input type="hidden" name="field[]" value="global_var">

以上、今回は type="hidden" で変数を渡すケースを解説しましたが、もちろん type="text" 等でフォームの項目の初期値として様々な変数を扱い、ユーザー側で変更可能にするカスタマイズも可能です。ぜひ、取り入れてみてください。

カテゴリーを SELECT で検索するフォームを作るには


カテゴリーリストモジュール( Category_List )を利用して、検索フォームを作る実装について書いてみます。カテゴリーリストモジュールは、子カテゴリーがあった際に入れ子で表示ができるようにするために少し複雑な動きをしています。

まずは、カテゴリーリストモジュールのスニペットを確認してみます。

カテゴリーリストモジュールのスニペット

<!-- BEGIN_MODULE Category_List -->
<div class="acms-margin-bottom-medium">
@include("/admin/module/setting.html")
  <!-- BEGIN category:loop --><!-- BEGIN ul#front -->
  <ul class="acms-list-group">
  <!-- END ul#front --><!-- BEGIN li#front -->
    <li><!-- END li#front --><!-- BEGIN category:veil -->
      <a href="{url}" class="acms-list-group-item">{name}<!-- BEGIN amount:veil -->
        <span class="acms-badge acms-float-right">{amount}</span><!-- END amount:veil -->
      </a><!-- END category:veil --><!-- BEGIN li#rear -->
    </li><!-- END li#rear --><!-- BEGIN ul#rear -->
  </ul>
  <!-- END ul#rear --><!-- END category:loop -->
</div>
<!-- END_MODULE Category_List -->

エントリーリストモジュール であれば、<ul> は entry:loop の外にあるのが一般的ですが、カテゴリーリストモジュール は、category:loop の内側に <ul> があるのでカスタマイズする際には注意が必要です。

最終的な表示されるフォームのHTML

上記のようなスニペットを利用して、以下のような HTML ができるようなことを考えてみます。

<form action="" method="POST">
  <select name="cid">
    <option>全て</option>
    <option value="2">お知らせ</option>
    <option value="3">製品情報</option>
    <option value="4">会社概要</option>
    <option value="6">お問い合わせ</option>
    <option value="7">採用情報</option>
    <option value="8">物件情報</option>
  </select>
  <input type="submit" name="ACMS_POST_2GET" value="検索">
</form>

フォームとしては実際には、以下のようになります。

スニペットを改造してみる

普通に考えると、まずは以下のように実装するのではないかと思います。

<form action="" method="POST">
  <!-- BEGIN_MODULE Category_List -->
  <select name="cid">
    <option value="">全て</option>
  <!-- BEGIN category:loop -->
    <option value="{cid}">{name}</option>
  <!-- END category:loop -->
  </select>
  <!-- END_MODULE Category_List -->
<input type="submit" name="ACMS_POST_2GET" value="検索">
</form>

しかし、これを a-blog cms のテンプレートに書くと、残念ながら以下のような結果になります。今回、どうしてそうなるのかという説明は省きますが、必要のない   <option value=""></option> を表示させないようにすることを追記することを考えます。

<select name="cid">
  <option value="">全て</option>
  <option value=""></option>
  <option value="2">お知らせ</option>
  <option value=""></option>
  <option value="3">製品情報</option>
  <option value=""></option>
  <option value="1">家庭用製品</option>
  <option value=""></option>
  <option value="5">業務用製品</option>
  <option value=""></option>
  <option value=""></option>
  <option value=""></option>
  <option value="4">会社概要</option>
  <option value=""></option>
  <option value="6">お問い合わせ</option>
  <option value=""></option>
  <option value="7">採用情報</option>
  <option value=""></option>
  <option value="8">物件情報</option>
  <option value=""></option>
  <option value=""></option>
</select>

空の optoin を非表示にする

方法としては IFブロックを利用して表示されて欲しくない部分は出ないようにします。例えば、{cid} が空ではない時という条件を設定したり

  <!-- BEGIN category:loop -->
    <!-- BEGIN_IF [{cid}/nem]-->
      <option value="{cid}">{name}</option>
    <!-- END_IF -->
  <!-- END category:loop -->

子カテゴリーがあるものがあった時に子カテゴリーを非表示にしたい場合を考え、階層の変数 {level} が 1 のものだけを表示する

  <!-- BEGIN category:loop -->
    <!-- BEGIN_IF [{level}/eq/1]-->
      <option value="{cid}">{name}</option>
    <!-- END_IF -->
  <!-- END category:loop -->

このような設定をします。

selected="selected" の処理

検索結果のページで select が選択したところが選択したままになるようにするためには、option に selected="selected" をつける必要があります。

今回は、option の中に IFブロックを書き、グローバル変数 %{CID} とカテゴリーリストモジュール内の {cid} との比較を行います。

<!-- BEGIN_IF [%{CID}/eq/{cid}] --> selected="selected"<!-- END_IF -->

最終的なカテゴリーリストモジュールの実装

  1. スニペットを改造してみる
  2. 空の optoin を非表示にする
  3. selected="selected" の処理

を実装し、人が読みやすいようにテンプレートを書くと以下のようになります。

<form action="" method="POST">
  <!-- BEGIN_MODULE Category_List -->
  <select name="cid">
    <option value="">全て</option>
  <!-- BEGIN category:loop -->
    <!-- BEGIN_IF [{level}/eq/1]-->
    <option value="{cid}"
      <!-- BEGIN_IF [%{CID}/eq/{cid}] -->
        selected="selected"
      <!-- END_IF -->
    >{name}</option>
    <!-- END_IF -->
  <!-- END category:loop -->
  </select>
  <!-- END_MODULE Category_List -->
<input type="submit" name="ACMS_POST_2GET" value="検索">
</form>

a-blog cms のテンプレートは、必要がないところは消える仕様になっていますが、消える部分の外にある改行だけ有効になってしまうことから上記を実行すると

<form action="" method="POST">
  
  <select name="cid">
    <option value="">全て</option>
  
    
  
    
    <option value="2"
      
    >お知らせ</option>
    
  
    
  
    
    <option value="3"
      
    >製品情報</option>


(以下略)

のように空白だらけのソースコードになります。HTML として表側では改行や空白は関係ないので、このままでも構いませんが綺麗にした例もご紹介しておきます。

<form action="" method="POST">
  <!-- BEGIN_MODULE Category_List -->
  <select name="cid">
    <option value="">全て</option>
  <!-- BEGIN category:loop --><!-- BEGIN_IF [{level}/eq/1]-->  <option value="{cid}"<!-- BEGIN_IF [%{CID}/eq/{cid}] --> selected="selected"<!-- END_IF -->>{name}</option>
  <!-- END_IF --><!-- END category:loop --></select>
  <!-- END_MODULE Category_List -->
<input type="submit" name="ACMS_POST_2GET" value="検索">
</form>

この HTML であれば、以下のようなソースコードになります。

<form action="" method="POST">
  
  <select name="cid">
    <option value="">全て</option>
    <option value="2">お知らせ</option>
    <option value="3">製品情報</option>
    <option value="4">会社概要</option>
    <option value="6">お問い合わせ</option>
    <option value="7" selected="selected">採用情報</option>
    <option value="8">物件情報</option>
  </select>
  
<input type="submit" name="ACMS_POST_2GET" value="検索">
</form>

今回は、特殊なカテゴリーリストのループをシンプルにする方法と、現在表示している selected の対応についての紹介でした。