[Zend Framework] Zend_ControllerへSmarty組み込む (続きの続き)
前回デフォルトのmodifierを設定して、出力に対して自動的にエスケープ処理を行うように設定したのですが、urlエンコードをかけたいときは
{$hello|smarty:nodefaults|escape:"url"}
なんて長い記述になってしまいまして(そういうことを某氏に軽く突っ込まれまして)、何かいい方法はないかとちょっと考えてみました。
Smarty自作のmodifier
で、前回設定したmodifierは自作もできるので、オリジナルで作ってそれをデフォルト設定することにしました。通常はhtmlspecialchars()でエスケープをかけて、ある特定の条件でアサインされた値にはrawurlencode()でURLエンコード処理行うようにします。ちなみに、{$foo|escape:”html”}とした場合にはhtmlspecialchars()で、{$foo|escape|”url”}とした場合にはrawurlencode()でそれぞれエスケープ処理がなされます。
ある特定の条件でというところが迷ったのですが、足りない頭でいろいろ考えた結果、今回はアサインされた値の先頭に特定の文字列があった場合に別のエスケープ処理を施すという方法になりました。%xxx%のように%で囲まれた文字列が先頭にあった場合に、xxxに対応するエスケープ処理を施すという内容です。
自作modifierのつくり方
ファイル名はmodifierを含めたプラグインの命名規則に従って付与します。
< プラグインの型>.<modifier の名前>.php
プラグインの型はmodifierとなります。プラグインの名前は適当なものを付けます。ここでつけた名前はテンプレートでmodifierを指定するときの名前になります。
{$foo|escape:"html"}
ならば、modifierプラグインのファイル名は
modifier.escape.php
です。今回はsanitizeというmodifier名にしますので、ファイル名は
modifier.sanitize.php
とします。
このファイルをSmarty.class.phpのあるディレクトリのpluginsディレクトリ内に配置してください。もし任意の場所にファイルを配置したい場合は、Smartyのパラメタであるplugins_dirを設定する必要があります。前出のpluginsディレクトリに加えて、カレントディレクトリ内にあるtestというディレクトリを追加したい場合は以下のようになります(前回、前々回に作ったViewSmartyクラスを想定しています)。
$this->_smarty->plugins_dir=array("plugins", "test"); ※絶対パスでの指定も可能です
modifier.sanitize.phpには以下の命名規則で関数を定義します。
function smarty_modifier_<modifier 名>(処理対象の値, [パラメータ1, ...])
modifier名はsanitizeになります。処理対象の値は、通常はアサインされた値で、パラメタは{$foo|sanitize:param1:param2}のparam1、param2の部分になります。今回作成するmodifierではパラメタがないので、
function smarty_modifier_sanitize($string)
という関数を定義することになります。
以上で自作のmodifierプラグインの作り方は終わりです。
今回作るmodiferの関数の定義は以下のようになります。
<?php define("SANITIZE_TYPE", '/%(\w+)%/'); function smarty_modifier_sanitize($string) { $split = preg_split(SANITIZE_TYPE, $string, 2, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE); if(count($split) == 2) { switch ($split[0]) { case 'url': return rawurlencode($split[1]); } } return htmlspecialchars($string, ENT_QUOTES); }
これでmodifierは完成です。SANITIZE_TYPEを変更することで、値の前につける文字列のパターンを変更でき、%xxx%のxxxの部分をcaseに追加することでエスケープの種類を追加することができます。
テスト
では実際にデータが処理されるか確認してみます。以下のようなデータを用いて検証します。
$url = "http://wadslab.net/?s=zend"; $html = "<b>bold</b>";
まず、前回のまま
$this->_smarty->default_modifiers=array(‘escape:”html”‘);
の設定で表示してみます。
http://wadslab.net/?s=zend <b>bold</b>
HTMLは以下のように出力されていました。
http://wadslab.net/?s=zend <b>bold</b>
どちらの変数にもhtmlspecialchars()処理がされています。
今回期待する結果は、$htmlのほうはこれでOKですが、$urlのほうは通常の値に{$url|escape:html}を適用した結果です。画面表示、HTML出力ともに以下の出力です。
http%3A%2F%2Fwadslab.net%2F%3Fs%3Dzend
では、今回作ったmodifierをViewSmartyクラスのデフォルトmodifierとして設定してみます
//$this->_smarty->default_modifiers=array('escape:"html"'); $this->_smarty->default_modifiers=array('sanitize');
これでの処理は以下のようになりました。
http://wadslab.net/?s=zend <b>bold</b>
HTML出力は以下のとおりです。
http://wadslab.net/?s=zend <b>bold</b>
これまでと同じく両方にhtmlspecialchars()処理がされています。
では、以下のように$urlのほうに”%url%”の識別子をつけて再度表示してみましょう。
$url = "%url%http://wadslab.net/?s=zend"; $html = "<b>bold</b>";
表示は
http%3A%2F%2Fwadslab.net%2F%3Fs%3Dzend <b>bold</b>
HTMLの出力は
http%3A%2F%2Fwadslab.net%2F%3Fs%3Dzend <b>bold</b>
でした。これでうまく処理を振り分けることができたようです。
処理時間はどうなっているかですが、時間がないので明日検証したいと思います。
また、毎回%xxx%のような文字列を付加するのもあまり良い方法ではないので、assign2()のようなものを作って、この関数経由でアサインをすると自動的に%xxx%がつくような関数も考慮したいと思います。