#navi_header|PHP| 高機能なPHPテンプレートHTMLエンジン、Smartyについての2005年6月当時のメモです。当時はバージョンが2.6.6とかその辺を使ってました。2008年12月現在、大分マイナーバージョンが上がっていますが、基本的な使い方やセキュリティ面でのTipsは今でも役に立つと思います。 公式サイト: http://www.smarty.net/ 公式日本語マニュアル: http://www.smarty.net/manual/ja/ #outline --------- * インストールやマニュアル、使い方 公式日本語マニュアル参照: http://www.smarty.net/manual/ja/ 実際の使い方のノウハウは、Smartyを使っているCMSアプリのコードを調べてみることをお奨めします。自分もXOOPSのコードで色々勉強しました。((XOOPSの場合はDBからテンプレートリソースを読み出す機能があり、resourceプラグインの作り方はこれを見て勉強しました。)) また Smarty-2.6.x/demo/ 以下にサンプルが入っていますので、そちらも忘れずに目を通してみましょう。 LinuxやUNIXユーザの場合、templates_cディレクトリをWebサーバ実行ユーザーから書き込み可能にしておくのを忘れずに。 $ chmod 777 templates_c/ とでも実行しておいてください。 * Tips, ノウハウ, ハウツー ** Smartyのタグをデフォルトの"{"から変更するには Smartyのコマンドタグは、"{"で始まり"}"で終わるのがデフォルトです。しかし、これだとJavaScriptの関数と同じなので、不便です。 そこで、XOOPSやYakiBikiでは次のようにして、"<{"と"}>"に変更しています。 $smarty = new Smarty; $smarty->left_delimiter = "<{"; $smarty->right_delimiter = "}>"; ** テンプレートHTMLをデータベースから読み出すには XOOPSのコードを見てみましょう。 xoops-2.X.X/html/class/smarty/plugins/resource.db.php 上記ファイルが参考になるはずです。 (2005年当時のファイルになります。2008年現在、XoopsCubeになってどうなっているのかは分かりません、御免なさい。) ** セキュリティ上の問題 データベースを利用して、テンプレートをユーザーが自由に変更できるようなCMSを作成する場合、絶対に注意しなければならない事項があります。 '' Smartyのデフォルトでは {php} - {/php} 組み込み関数により、自由にPHPコードを記述できます。 '' これはすなわちユーザーに、PHPでできるありとあらゆる操作を行える力を与えることに他なりません。 JavaScriptを埋め込まれる以上に危険なこの機能を無効化するには、 '' $securityプロパティをtrueにします。 '' $smarty->security = true; '' この一行を絶対に忘れないでください。 '' この場合でもし{php}タグが使われていた場合、Smartyはエラーを出力すると同時に処理も続行します。 ** オブジェクトを割り当てる場合のプライベート("_"で始まる)要素への制限 '' ここも2005年当時の話です。アップデートできず御免なさい。2008年現在は、公式日本語マニュアルの「第15章 拡張機能」→「オブジェクト」の項を参照して下さい。 '' オブジェクトを割り当てる場合、 register_object assign(_by_ref) の二種類が存在します。 register_objectを使うと、第三パラメータに使用可能なメソッド・メンバ名を配列で指示できます。 assign(_by_ref)では、以下の二つの条件すべてが成立している場合に、"_"で始まるメンバ・メソッドへの(テンプレートHTML内での)アクセスを禁止できます。(Smarty errorが発生します。) - assign(_by_ref)で割り当てている。 - $smarty->security = true にしている。 '' register_object()に関しては、この"_"で始まる要素へのアクセス制限機能は適用されないことに注意してください。 '' このオブジェクト割り当てを調べたときの過程をメモっておきます。 *** Smarty.class.php まず、register_object でSmartyのソースツリー(正確にはlibs/以下)をgrepしました。そしたら、Smarty.class.phpの function register_object($object, &$object_impl, $allowed = array(), $smarty_args = true, $block_methods = array()) { settype($allowed, 'array'); settype($smarty_args, 'boolean'); $this->_reg_objects[$object] = array(&$object_impl, $allowed, $smarty_args, $block_methods); } にヒットしました。んで、これ見ると_reg_objects[]という配列にいろいろセットされてます。実際にregister_objectで割り当てたオブジェクトを使用しているテンプレートHTMLのコンパイル後の該当部分を見てみると、 <{obj1->meth1 ... }> が、 _reg_objects['obj1'][0]->meth1(array(), $this);?> になってました。 *** Smarty_Compiler.class.php 先の調査結果をふまえて、_reg_objectsでgrepしたら、Smarty_Compiler.class.php中で function _compile_registered_object_tag($tag_command, $attrs, $tag_modifier) が見つかりました。んで、調べていくと・・・ } elseif( !empty($this->_reg_objects[$object][1]) && !in_array($obj_comp, $this->_reg_objects[$object][1])) { $this->_trigger_fatal_error( "'$obj_comp' is not a registered component of object '$object'", $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); というのが見つかりました。$obj_compというのはこの関数の前の方で list($object, $obj_comp) = explode('->', $tag_command); として取得されています。つまりメンバ・メソッド名の部分ですな。 '' というわけで、register_object()の場合は $smarty->securityとは何の関係もないどころか、"_"ではじまるプライベート要素にはアクセスし放題というわけです。 '' だから代わりに、register_object()の第三パラメータの配列でアクセス制限をかけている訳ですね。(代わりというわけではないと思いますが。) *** 結局"_"で始まるアクセス制限はどうしてるのか? '_'でSmarty_Compiler.class.phpを検索したら見つかりました。_parse_varとかいう関数の中で、 } else if (substr($_index,0,2) == '->') { if(substr($_index,2,2) == '__') { $this->_syntax_error( 'call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__); } elseif($this->security && substr($_index, 2, 1) == '_') { $this->_syntax_error( '(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); みたくなってました。 #navi_footer|PHP|