[メモ] symfony/sfPayloadFilterChainPluginによる文字列のフィルタ保存

sfPayloadFilterChainPlugin

掲示板とかで、表示時にフィルタをかけるんじゃなくて、保存時にまずい文字列とかを見つけて伏字にしたりするためのsymfony プラグイン。

インストール方法

> symfony plugin-install http://plugins.symfony-project.com/sfPayloadFilterChainPlugin

設定ファイル

$ cd frontend/config/pfc
$ edit frontend/config/pfc/profiles.yml
post_comment: [censor_bad_words, hide_phone_number]

$ edit frontend/config/pfc/filters.yml

  censor_bad_words:
    enabled: on
    class:   myCensorshipFilter
    params:
      bad_words:        [死ね, 死ねばいいのに, 氏ね]
      replacement_word: "王大人に死亡確認されればいいのに"
  hide_phone_number:
    enabled: on
    class:   akkyHidePhoneNumberFilter
    params:
      replacement_word: "***-****-****"

payloadでフィルタするテキストを受け渡す作りで、説明にあるように単純なpayloadクラスを作っておく

lib/payload/myTextPayload.class.php

class myTextPayload
{
  public function getText()
  {
    return $this->text;
  }
  public function setText($text)
  {
    $this->text = $text;
  }
}

あとはフィルタクラスを実装して配置。autoloadさせるので置いたら”symfony cc”を呼ぶこと

lib/filter/akkyHidePhoneNumberFilter.class.php

/**
 * hide Japan's phone number from text
 *
 */
class akkyHidePhoneNumberFilter extends sfFilter
{
  // not a perfect solution
  //  see http://blog.livedoor.jp/nipotan/archives/17526053.html
  const PATTERN = '/(?:0\d{1,4}[-.]?)?\d{1,4}[-.]?\d{4}/';
  /**
   * Make phone number unreadable.
   * 
   * @param     string     $text
   * @return    string
   */
  public function execute($chain, $payload)
  {
    $replacementWord
      = $this->getParameter('replacement_word', 'xxx-xxxx-xxxx');

    // Retrieve text from payload
    $text = $payload->getText();

    $censoredText = preg_replace(self::PATTERN, $replacementWord, $text);

    // Replace payload text
    $payload->setText($censoredText);
    
    // Execute next filter in chain
    $chain->execute($payload);
  }
}

あとは、実際に書き込みの発生するところで、手動(アクション側)または自動(モデル側)でこのfilterを呼び出すことで、まずい単語にマスクをかけるフィルタなどを、フィールド毎に適用させることができます。

class messageActions extends sfActions
{
  public function executePost()
  {
    $payloadComment = new myTextPayload();
    $payloadComment->setText($this->getRequestParameter('comment'));
    // Filter payload
    $chain = new pfcPayloadFilterChain();
    $chain->loadProfile('post_comment');
    $chain->setPayload($payloadComment);
    $chain->execute();
    $this->comment = $payloadComment->getText();

    (このあとpropelオブジェクトにセットして保存とか)

で、入力フィールドのこういうのが

秋元(030-5555-5555)死ね

こうなる

秋元(***-****-****)王大人に死亡確認されればいいのに

アクションごとに適用できるフィルタをきめ細かく変更できるところと、適用するfilterをyamlで調整したり、可変のパラメータを設定できたりするところが利点なんでしょうか。もうちょっと使ってみようかと思っています。