- Smarty
- Twig
- etc...
- テンプレートエンジン特有の構文を覚えなければならない
- IDE がシンタックスハイライトなどに対応していないことがある
<h1>Users</h1>
<ul>
{foreach from=$users item=user}
<li>{$user.username}</li>
{/foreach}
</ul>
<h1>Users</h1>
<ul>
{% for user in users %}
<li>{{ user.username }}</li>
{% endfor %}
</ul>
- テンプレートエンジン特有の構文を覚える必要がない
- たいていの IDE がシンタックスハイライトなどに対応している
<h1>Users</h1>
<ul>
<?php foreach ($users as $user): ?>
<li><?= $user['username'] ?></li>
<?php endforeach; ?>
</ul>
とか
<h1>Users</h1>
<ul>
<?php foreach ($users as $user) { ?>
<li><?= $user['username'] ?></li>
<?php } ?>
</ul>
PHP とまったく同じ
↓
テンプレートエンジン特有の構文を覚える必要がない
- ハイライトどころかアウトライン解析までできている
- もちろん Eclipse にも対応
- とうぜん NetBeans にも対応 使ったこと無いけど
むしろ対応していないなら PHP の IDE を名乗るべきではない
IDE が対応するのではない、対応しているものが IDE なのだ
テンプレートにアサインする変数がオブジェクトなら
ちょっとしたおまじないで入力補完にまで対応
<?php /* @var $users User[] */ ?>
<h1>Users</h1>
<ul>
<?php foreach ($users as $user): ?>
<li><?= $user->getUsername() ?></li>
<?php endforeach; ?>
</ul>
このステキなテンプレートエンジンの名前は
素の PHP がテンプレートとして使われることは多い
- Zend Framework
- CakePHP
- FuelPHP
- etc...
例えばこんなの
index.php
<?php
$name = filter_input(INPUT_GET, 'name');
include __DIR__ . '/index.html.php';
index.html.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
< body>
Hello <?= $name ?>
< /body>
</html>
ここ、いわゆる XSS です
Hello <?= $name ?>
エスケープが必要
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
< body>
Hello <?= htmlspecialchars($name, ENT_QUOTES) ?>
</ body>
</html>
さすがに毎度こんなのを書いてたらめんどくさくて死ぬ
<?= htmlspecialchars($name, ENT_QUOTES) ?>
のでフレームワークによって別の書き方が提供されています
<?= $this->escapeHtml($name) ?>
- ビューヘルパーと呼ばれるもの
- あんまり楽になった気がしない
<?= h($name) ?>
h
というグローバル関数が定義されているbasics.php
を見ると他にもいろいろ定義されている
<?= $name ?>
- あらかじめエスケープされた変数がアサインされる
- ただしオブジェクトをアサインするときに困りそう
- Smarty2 の自動エスケープはクソ
- 出力時ではなく参照時にエスケープされるから
- Smarty3 なら良い感じに自動でエスケープしてくれる
- Twig も自動でエスケープしてくれる
...
素の PHP でも同じことがしたい
index.php
<?php
require __DIR__ . '/../vendor/autoload.php';
use PhpRenderer\Renderer;
$data = array(
'name' => "<script>alert('!!!')< /script>",
'html' => "<strong>oreore</strong>",
);
echo (new Renderer)->render(__DIR__ . '/index.html.php', $data);
index.html.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
< body>
Hello <?= $name ?>.
<br>
None Escape <?php echo $html ?>
< /body>
</html>
<?= $name ?>
のようなショートタグ- 自動エスケープ
<?php echo $html ?>
のような普通の PHP タグ- エスケープなし
- StreamWrapper
- Tokenizer
<?php
stream_wrapper_register('oreore', 'OreOreClass');
oreore:path/to/file
のようなストリームラッパーが使えるようになります。
OreOreClass
には "path/to/file"
が渡されるので、
そのファイルを開いて独自の処理ができます。
$tokens = token_get_all($source);
開いたファイルを PHP のソースコードとして、
トークン(字句)に分割します。
<?= → T_OPEN_TAG_WITH_ECHO
?> → T_CLOSE_TAG
この2つのトークンを見つけて、
<?= ... ?>
を、
<?=func( ... )?>
のように置換します。
include 'oreore://index.html.php'
のようにインクルードすると、
<?= ... ?>
を置換したソースコードがインクルードされます。
index.html.php
には OPCache は効かないfile:
とphar:
しか対応しないようにハードコードされてる- 置換後の opcode がキャッシュされると思ってた・・・
index.html.php
にブレークポイントを仕込んでも無駄- デバッガが止まりません