CakePHP サニタイズでエスケープされた改行コードを元に戻す簡単なコンポーネントを作ってみる

『Sanitize::clean』でサニタイズを行うと、改行コードもエスケープされます。

このままでは、『textarea』要素に入力された改行がない状態になり、想像していた表示にならないことがあります。
下記の赤文字の部分がサニタイズ時にエスケープされた改行コードです。

▼サニタイズされた『textarea』要素のテキスト

登録時に『Sanitize::clean』を使用しサニタイズを行いました。\n\nこのテキストは確認用です。

このままでは『nl2br』関数も使用できないので、コンポーネント作成の練習も兼ねて、『\\\n』を『\n』に戻す簡単なコンポーネントを作りたいと思います。

(表示では『\n』ですが、実際はエスケープシーケンスがあるので『\\\n』の状態になっています。)


コンポーネントは、『Object』クラスを継承し作成します。

▼『Object』クラスを継承

class HtmlDecodeComponent extends Object {
    public $name = 'HtmlDecode';
}

これをCakePHPの規約どおりに、『html_decode.php』として『/app/controllers/components』ディレクトリに配置します。
これでコンポーネントの準備ができました。

次は、メソッドを追加していきます。
改行コードを元に戻すメソッドだけでは寂しいので、HTMLエンティティを特殊文字に置き換えるメソッドも書いてみました。

▼作成したコンポーネントにメソッドを追加

class HtmlDecodeCompnent extends Object {
    public $name = 'HtmlDecode';

    // 置き換え対象のHTMLエンティティ
    protected $_patterns = array(
        'before' => array(
            "/¥&/",    // 『&』
            "/¥</",     // 『<』
            "/¥>/",     // 『>』
            "/¥"/",   // 『"』
            "/¥'/",    // 『'』
        ),

        'after' => array(
            "&",    // 『&amp』
            "<",    // 『&lt;』
            ">",    // 『&gt;』
            "'",    // 『&quot;』
            '"',    // 『&#39;』
        )
    );

    /**
     *	HTMLエンティティを特殊文字に置き換える
     *
     *	@param    string or array     $data      HTMLエンティティを特殊文字に置き換えたい配列、または文字列
     *	@param    pool                $script    置き換え後の特殊文字がScriptタグになった場合、削除するなら『true』を指定
     *	@param    pool                $space     置き換え後の文字列からスペースを削除するなら『true』を指定
     *
     *	@return   string or array     $data      処理後、引数に指定された形式で返す。
     */
    public function htmlCheck($data, $script = true, $image = true, $space = true) {
        if(is_array($data)) {
            $cnvData = array();

            // 配列の処理
            foreach($data as $key => $item) {
                if(isset($item)) {
                    // 特殊文字へ置き換え
                    $cnvData[$key] = $this->_htmlDecode($item);

                    // スクリプトタグの削除
                    if($script) $cnvData[$key] = Sanitize::stripScripts($cnvData[$key]);

                    // 画像の削除
                    if($image) $cnvData[$key] = Sanitize::stripImages($cnvData[$key]);

                    // スペースの削除
                    if($space) $cnvData[$key] = Sanitize::stripWhitespace($cnvData[$key]);
                }
            }
        } else {
            if(isset($data)) {
                // 特殊文字へ置き換え
                $cnvData = $this->_htmlDecode($data);

                // スクリプトタグの削除
                if($script) $cnvData = Sanitize::stripScripts($cnvData);

                // 画像の削除
                if($image) $cnvData = Sanitize::stripImages($cnvData);

                // スペースの削除
                if($space) $cnvData = Sanitize::stripWhitespace($cnvData);
            }
        }

        return $cnvData;
    }

    /**
     *	配列、または文字列に含まれる『///n』を『/n』に置き換える
     *
     *	@param    string or array    $data         『///n』を『/n』に置き換えたい配列、または文字列
     *	@param    pool               $conversion    置き換え後の『/n』を『
』タグに変更する場合、trueを指定 * * @return string or array $data 処理後、引数に指定された形式で返す。 * */
public function nlCheck($data, $conversion = false) { if(is_array($data)) { $cnvData = array(); foreach($data as $key => $item) { if(isset($item)) { // 『/n』へ置き換え $cnvData[$key] = $this->_nlDecode($item); // 『
』へ置き換え
if($conversion) $cnvData[$key] = nl2br($cnvData[$key]); } } } else { if(isset($data)) { // 『/n』へ置き換え $cnvData = $this->_nlDecode($data); // 『
』へ置き換え
if($conversion) $cnvData = nl2br($cnvData); } } return $cnvData; } /** * HTMLエンティティを特殊文字に置き換える * * @param string $data 置き換えたい文字列 * * @return string 置き換え後の文字列 */ protected function _htmlDecode($data) { return preg_replace($this->_patterns['before'], $this->_patterns['after'], $data); } /** * 『///n』を『/n』に置き換える * * @param string $data 置き換えたい文字列 * * @return string 置き換え後の文字列 */ protected function _nlDecode($data) { return preg_replace('/\\\n/', "\n", $data); } }

『preg_replace』関数を使用し、正規表現で文字を置き換えていくだけのメソッドたちです。

あとは、コントローラーからコンポーネントを呼び出せば、他のコンポーネント同様に使用することができます。

▼コントローラー

class PostsController extends AppController {
    public $name  = 'Posts';
    public $users = array('Post');
    public $components = array('HtmlDecode');

    public function index() {
        /*
        処理は省略します・・・
        */

        $text = $this->HtmlDecode->nlCheck('登録時に『Sanitize::clean』を使用しサニタイズを行いました。\n\nこのテキストは確認用です。', true);
        $this->set('text', $text);
    }
}

▼ビュー

<?php
echo $text;
?>

▼結果

登録時に『Sanitize::clean』を使用しサニタイズを行いました。
<br />
<br />
<br />
このテキストは確認用です。

コンポーネントを作成するのもとっても簡単ですね。
さすがCakePHPって感じです。

ちなみに、今回はコンポーネントとして作成しましたが、モデルの段階で処理したほうがいいのか(ビヘイビア)迷いました。

ビューで処理するのは、『コントローラーから渡されたデータをビュー側でループや条件分岐以外の処理をして表示する』のは間違っていると思うので止めましたが・・・

もっとMVCの理解を深めないといけないですね^^;


※記事を投稿後、『CakePHPを使ったMVC設計のベストプラクティス』を見て、モデルの段階で処理したほうがいい気がしてきました。
今回作成したコンポーネントと同じ処理を行うビヘイビアを作成しようと思います。