HTML-Elemente

Die Klasse Nette\Utils\Html ist ein Hilfsmittel zur Generierung von HTML-Code, der Cross Site Scripting (XSS)-Schwachstellen verhindert.

Sie funktioniert so, dass ihre Objekte HTML-Elemente darstellen, wir setzen ihre Parameter und lassen sie rendern:

$el = Html::el('img');  // erzeugt <img>-Element
$el->src = 'image.jpg'; // setzt src-Attribut
echo $el;               // gibt '<img src="bild.jpg">' aus

Die Installation:

composer require nette/utils

Alle Beispiele gehen davon aus, dass der folgende Klassenalias definiert ist:

use Nette\Utils\Html;

Ein HTML-Element erstellen

Das Element wird mit der Methode Html::el() erstellt:

$el = Html::el('img'); // erzeugt <img>-Element

Neben dem Namen können Sie weitere Attribute in der HTML-Syntax angeben:

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

Oder Sie übergeben sie als assoziatives Array an den zweiten Parameter:

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

Um einen Elementnamen zu ändern und zurückzugeben:

$el->setName('img');
$el->getName(); // 'img'
$el->isEmpty(); // wahr, da <img> ein leeres Element ist

HTML-Attribute

Sie können einzelne HTML-Attribute auf drei Arten setzen und abrufen, es bleibt Ihnen überlassen, welche Ihnen besser gefällt. Die erste ist über die Eigenschaften:

$el->src = 'image.jpg'; // setzt src-Attribut

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

unset($el->src); // entfernt das Attribut
// oder $el->src = null;

Der zweite Weg ist der Aufruf von Methoden, die wir im Gegensatz zum Setzen von Eigenschaften aneinanderreihen können:

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

$el->alt(null); // entfernt das Attribut

Und der dritte Weg ist der gesprächigste:

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

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

$el->removeAttribute('alt');

In der Masse können Attribute mit addAttributes(array $attrs) gesetzt und mit removeAttributes(array $attrNames) gelöscht werden.

Der Wert eines Attributs muss nicht nur ein String sein, es können auch logische Werte für logische Attribute verwendet werden:

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

Ein Attribut kann auch ein Array von Token sein, die durch Leerzeichen getrennt aufgelistet werden, was sich z.B. für CSS-Klassen eignet:

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

Eine Alternative ist ein assoziatives Array, bei dem die Werte angeben, ob der Schlüssel aufgeführt werden soll:

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

CSS-Stile können in Form von assoziativen Arrays geschrieben werden:

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

Wir haben jetzt Eigenschaften verwendet, aber das Gleiche lässt sich auch mit den Methoden machen:

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

Oder sogar auf die gesprächigste Art und Weise:

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

Eine letzte Sache: Die Methode href() kann die Zusammenstellung von Abfrageparametern in einer URL erleichtern:

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

Daten-Attribute

Datenattribute haben eine besondere Unterstützung. Da ihre Namen Bindestriche enthalten, ist der Zugriff über Eigenschaften und Methoden nicht so elegant, daher gibt es eine Methode data():

$el = Html::el('input');
$el->{'data-max-size'} = '500x300'; // nicht so elegant
$el->data('max-size', '500x300'); // ist elegant
echo $el; // '<input data-max-size="500x300">'

Wenn der Wert des Datenattributs ein Array ist, wird es automatisch in JSON serialisiert:

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

Element Inhalt

Der innere Inhalt des Elements wird mit den Methoden setHtml() oder setText() festgelegt. Verwenden Sie die erste Methode nur, wenn Sie wissen, dass Sie zuverlässig einen sicheren HTML-String im Parameter übergeben.

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

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

Umgekehrt wird der innere Inhalt mit den Methoden getHtml() oder getText() ermittelt. Die zweite Methode entfernt Tags aus der HTML-Ausgabe und wandelt die HTML-Entities in Zeichen um.

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

Kind-Knoten

Der innere Inhalt eines Elements kann auch ein Array von Kindern sein. Jedes dieser Elemente kann entweder eine Zeichenkette oder ein anderes Html Element sein. Sie werden mit addHtml() oder addText() eingefügt:

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

Eine andere Möglichkeit, einen neuen Html Knoten zu erstellen und einzufügen:

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

Sie können mit Knoten arbeiten, als wären sie Array-Elemente. Greifen Sie also mit eckigen Klammern auf die einzelnen Knoten zu, zählen Sie sie mit count() und iterieren Sie über sie:

$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

Mit insert(?int $index, $child, bool $replace = false) kann ein neuer Knoten an einer bestimmten Position eingefügt werden. Wenn $replace = false, wird das Element an der Position $index eingefügt und die anderen verschoben. Wenn $index = null, wird ein Element am Ende angehängt.

// fügt das Element an der ersten Position ein und schiebt die anderen vor
$el->insert(0, Html::el('span'));

Alle Knoten werden von der Methode getChildren() zurückgegeben und von der Methode removeChildren() entfernt.

Erstellen eines Dokumentfragments

Wenn Sie mit einem Array von Knoten arbeiten wollen und nicht an dem umhüllenden Element interessiert sind, können Sie ein sogenanntes Dokumentenfragment erstellen, indem Sie null anstelle des Elementnamens übergeben:

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

Die Methoden fromHtml() und fromText() bieten eine schnellere Möglichkeit, ein Fragment zu erstellen:

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

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

HTML-Ausgabe generieren

Der einfachste Weg, ein HTML-Element zu erzeugen, ist die Verwendung von echo oder die Umwandlung eines Objekts in (string). Sie können auch öffnende oder schließende Tags und Attribute separat drucken:

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

echo $el;               // '<div class="header"></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"'

Eine wichtige Funktion ist der automatische Schutz gegen Cross Site Scripting (XSS). Alle Attributwerte oder Inhalte, die mit setText() oder addText() eingefügt werden, werden zuverlässig escaped:

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

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

Konvertierung HTML ↔ Text

Sie können die statische Methode htmlToText() verwenden, um HTML in Text umzuwandeln:

echo Html::htmlToText('<span>Ein &amp; Zwei</span>'); // 'Eins & Zwei'

HtmlStringable

Das Objekt Nette\Utils\Html implementiert die Schnittstelle Nette\HtmlStringable, die z.B. von Latte oder Formularen verwendet wird, um Objekte zu unterscheiden, die eine Methode __toString() haben, die HTML-Code zurückgibt. Das doppelte Escaping tritt also nicht auf, wenn wir z.B. das Objekt in der Vorlage mit {$el} ausgeben.

Version: 4.0