フナエさんから「最近更新してないねー。忙しい?」といわれたので更新します。
たぶん、国内でも2人くらいしか欲してなさそうなSmarty Tips。
例えば、以下のような状況があったとする。
- www.example.com/index.php
-
$smarty =& new Smarty;
$smarty->template_dir = './templates_c';
$smarty->compile_dir = '/www/tmp/smarty/templates_c'; ※1,3
(略)
$smarty->display('index.tpl'); ※2
- www.example.net/index.php
-
$smarty =& new Smarty;
$smarty->template_dir = './templates_c';
$smarty->compile_dir = '/www/tmp/smarty/templates_c'; ※1,3
(略)
$smarty->display('index.tpl'); ※2
ポイントは
- コンパイルディレクトリが同一(/www/tmp/smarty/templates_c)
- テンプレートファイル名が同一(index.tpl)
- コンパイルディレクトリはここじゃなきゃ絶対やだやだ
の3つだ。この場合、Smartyは www.example.net/index.php へのアクセス時に www.example.com/index.php 用のコンパイル済みテンプレートファイルを参照してしまうことがある(逆もまたしかり)。つまり、コンパイル済みテンプレートファイル名が衝突してしまう場合がある。
なぜ衝突が起こるのか?
Smartyは、display()もしくはfetch()を呼び出されたタイミングで
- コンパイル済みテンプレートファイルが存在するか
- コンパイル済みテンプレートファイルが存在するのであれば、前回コンパイル時からテンプレートは更新されているか
を調べ、必要があると判断した場合のみコンパイル処理を行う。
コンパイル済みテンプレートファイル名を決定しているのは_get_auto_filename()というプライベート関数で、通常この関数内では元となるテンプレートファイル名(index.tpl)のcrc32を元にコンパイル済みテンプレートファイル名(この場合は%%45^45E^45E480CD%%index.tpl.php)を一意に決定している。別の観点から見ると、元となるテンプレートファイル名のみでコンパイル済みテンプレートファイル名が決定していることになる。
つまり前述の例では、同一のテンプレートファイル名(index.tpl)で同一のコンパイルディレクトリ(/www/tmp/smarty/templates_c)内に同一のコンパイル済みテンプレートファイル(%%45^45E^45E480CD%%index.tpl.php)を作ろうとするため、結果としてファイル名の衝突が起こってしまうというわけだ。ややこしいなもう。
「なんで呼び出し時のテンプレートファイル名だけで一意に決めてるんだ?コレってバグなんじゃねーの?」と思いフォーラムをあさってみると、以下のようなスレッドが見つかった。
Duplicate template names overwrite each other
スレッド内のmessju 氏の発言より:
バグじゃねーよ(it's not a bug.)
- 異なるcompile_dirを使え
- 異なるtemplate_dirを使え
- 異なるcompile_idを使え
ああ神の声。
つまり、衝突を起こしたくなければ「サイトごとにコンパイル済みファイル名が一意に決まるよう設定しとけよベイビー」ということなのだそうな。結論として、コンパイルディレクトリを一箇所に固定したい場合の解決方法としては
$smarty->compile_id = $_SERVER['DOCUMENT_ROOT'];
とかがとっても有効で簡単な解決策であるような気がします。こうすると、前述の_get_auto_filename()にて$compile_idを付加した形でコンパイル済みファイル名を決定してくれるようになります。
イジョ(後半からいい加減)
このページ役にたちましたよ!
$smarty->compile_id = crc32(パス);
自分の場合は上のように対処しました。
おー、国内で二番目に必要としている人がいた!
コメントどうもありがとー