HTML要素

クラスNette\Utils\Htmlは、クロスサイトスクリプティング(XSS)脆弱性の発生を防ぐHTMLコードを生成するためのヘルパーです。

そのオブジェクトがHTML要素を表し、パラメータを設定してレンダリングさせることで機能します。

$el = Html::el('img');  // <img> 要素を作成します
$el->src = 'image.jpg'; // src 属性を設定します
echo $el;               // '<img src="image.jpg">' を出力します

インストール:

composer require nette/utils

すべての例では、エイリアスが作成されていることを前提としています。

use Nette\Utils\Html;

HTML要素の作成

要素はHtml::el()メソッドで作成します。

$el = Html::el('img'); // <img> 要素を作成します

名前以外にも、HTML構文で他の属性を指定できます。

$el = Html::el('input type=text class="red important"');

または、2番目のパラメータとして連想配列で渡します。

$el = Html::el('input', [
	'type' => 'text',
	'class' => 'important',
]);

要素名の変更と返却:

$el->setName('img');
$el->getName(); // 'img'
$el->isEmpty(); // true、<img> は空要素であるため

HTML属性

個々のHTML属性は3つの方法で変更および読み取りできます。どちらが好きかはあなた次第です。最初の方法はプロパティを介して行われます。

$el->src = 'image.jpg'; // src 属性を設定します

echo $el->src; // 'image.jpg'

unset($el->src);  // 属性を削除します
// または $el->src = null;

2番目の方法はメソッド呼び出しであり、プロパティ設定とは異なり、連鎖させることができます。

$el = Html::el('img')->src('image.jpg')->alt('photo');
// <img src="image.jpg" alt="photo">

$el->alt(null); // 属性の削除

そして3番目の方法は最も冗長です。

$el = Html::el('img')
	->setAttribute('src', 'image.jpg')
	->setAttribute('alt', 'photo');

echo $el->getAttribute('src'); // 'image.jpg'

$el->removeAttribute('alt');

属性はaddAttributes(array $attrs)を使用して一括で設定でき、removeAttributes(array $attrNames)を使用して削除できます。

属性の値は文字列である必要はなく、論理属性には論理値を使用できます。

$checkbox = Html::el('input')->type('checkbox');
$checkbox->checked = true;  // <input type="checkbox" checked>
$checkbox->checked = false; // <input type="checkbox">

属性は値の配列にすることもでき、スペースで区切られて出力されます。これは、たとえばCSSクラスに便利です。

$el = Html::el('input');
$el->class[] = 'active';
$el->class[] = null; // null は無視されます
$el->class[] = 'top';
echo $el; // '<input class="active top">'

代替案は連想配列であり、値はキーを出力するかどうかを示します。

$el = Html::el('input');
$el->class['active'] = true;
$el->class['top'] = false;
echo $el; // '<input class="active">'

CSSスタイルは連想配列の形式で記述できます。

$el = Html::el('input');
$el->style['color'] = 'green';
$el->style['display'] = 'block';
echo $el; // '<input style="color: green; display: block">'

これまでプロパティを使用してきましたが、同じことをメソッドを使用して記述できます。

$el = Html::el('input');
$el->style('color', 'green');
$el->style('display', 'block');
echo $el; // '<input style="color: green; display: block">'

または、最も冗長な方法でも可能です。

$el = Html::el('input');
$el->appendAttribute('style', 'color', 'green');
$el->appendAttribute('style', 'display', 'block');
echo $el; // '<input style="color: green; display: block">'

最後にちょっとしたこと:href()メソッドはURLのクエリパラメータの組み立てを容易にすることができます。

echo Html::el('a')->href('index.php', [
	'id' => 10,
	'lang' => 'en',
]);
// '<a href="index.php?id=10&amp;lang=en"></a>'

データ属性

データ属性には特別なサポートがあります。名前にはハイフンが含まれているため、プロパティやメソッドによるアクセスはそれほどエレガントではありません。そのため、data()メソッドがあります。

$el = Html::el('input');
$el->{'data-max-size'} = '500x300'; // それほどエレガントではありません
$el->data('max-size', '500x300'); // エレガントです
echo $el; // '<input data-max-size="500x300">'

データ属性の値が配列の場合、自動的にJSONにシリアライズされます。

$el = Html::el('input');
$el->data('items', [1,2,3]);
echo $el; // '<input data-items="[1,2,3]">'

要素の内容

要素の内部コンテンツはsetHtml()またはsetText()メソッドで設定します。最初のメソッドは、パラメータで確実に安全なHTML文字列を渡していることがわかっている場合にのみ使用してください。

echo Html::el('span')->setHtml('hello<br>');
// '<span>hello<br></span>'

echo Html::el('span')->setText('10 < 20');
// '<span>10 &lt; 20</span>'

逆に、内部コンテンツはgetHtml()またはgetText()メソッドで取得します。2番目のメソッドは、出力からHTMLタグを削除し、HTMLエンティティを文字に変換します。

echo $el->getHtml(); // '10 &lt; 20'
echo $el->getText(); // '10 < 20'

子ノード

要素の内部は、子(children)ノードの配列にすることもできます。それぞれは、文字列または別のHtml要素のいずれかになります。addHtml()またはaddText()を使用して挿入します。

$el = Html::el('span')
	->addHtml('hello<br>')
	->addText('10 < 20')
	->addHtml( Html::el('br') );
// <span>hello<br>10 &lt; 20<br></span>

新しいHtmlノードを作成して挿入する別の方法:

$ul = Html::el('ul');
$ul->create('li', ['class' => 'first'])
	->setText('první');
// <ul><li class="first">první</li></ul>

ノードは、配列であるかのように操作できます。つまり、角括弧を使用して個々のノードにアクセスし、count()を使用してカウントし、それらを反復処理します。

$el = Html::el('div');
$el[] = '<b>hello</b>';
$el[] = Html::el('span');
echo $el[1]; // '<span></span>'

foreach ($el as $child) { /* ... */ }

echo count($el); // 2

新しいノードは、insert(?int $index, $child, bool $replace = false)を使用して特定の場所に挿入できます。$replace = falseの場合、要素を$indexの位置に挿入し、他の要素をシフトします。$index = nullの場合、要素を末尾に追加します。

// 要素を最初の位置に挿入し、他の要素をシフトします
$el->insert(0, Html::el('span'));

すべてのノードはgetChildren()メソッドで取得し、removeChildren()メソッドで削除します。

ドキュメントフラグメントの作成

ノードの配列を操作し、ラッパー要素に関心がない場合は、要素名の代わりにnullを渡すことで、いわゆるドキュメントフラグメントを作成できます。

$el = Html::el(null)
	->addHtml('hello<br>')
	->addText('10 < 20')
	->addHtml( Html::el('br') );
// hello<br>10 &lt; 20<br>

フラグメントを作成するより高速な方法は、fromHtml()およびfromText()メソッドを提供します。

$el = Html::fromHtml('hello<br>');
echo $el; // 'hello<br>'

$el = Html::fromText('10 < 20');
echo $el; // '10 &lt; 20'

HTML出力の生成

HTML要素を出力する最も簡単な方法は、echoを使用するか、オブジェクトを(string)にキャストすることです。開始タグまたは終了タグと属性を個別に出力することもできます。

$el = Html::el('div class=header')->setText('hello');

echo $el;               // '<div class="header">hello</div>'
$s = (string) $el;      // '<div class="header">hello</div>'
$s = $el->toHtml();     // '<div class="header">hello</div>'
$s = $el->toText();     // 'hello'
echo $el->startTag();   // '<div class="header">'
echo $el->endTag();     // '</div>'
echo $el->attributes(); // 'class="header"'

重要な特徴は、クロスサイトスクリプティング (XSS)に対する自動保護です。setText()またはaddText()を介して挿入されたすべての属性値またはコンテンツは、確実にエスケープされます。

echo Html::el('div')
	->title('" onmouseover="bad()')
	->setText('<script>bad()</script>');

// <div title='" onmouseover="bad()'>&lt;script&gt;bad()&lt;/script&gt;</div>

HTML ↔ テキスト変換

HTMLをテキストに変換するには、静的メソッドhtmlToText()を使用できます。

echo Html::htmlToText('<span>One &amp; Two</span>'); // 'One & Two'

HtmlStringable

オブジェクトNette\Utils\Htmlは、Nette\HtmlStringableインターフェースを実装しています。これにより、たとえばLatteやフォームは、HTMLコードを返す__toString()メソッドを持つオブジェクトを区別します。したがって、たとえばテンプレートで{$el}を使用してオブジェクトを出力しても、二重エスケープは発生しません。

バージョン: 4.0