HTML-Elemente

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

Sie funktioniert, indem ihre Objekte HTML-Elemente repräsentieren, deren Attribute gesetzt und die dann gerendert werden können:

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

Installation:

composer require nette/utils

Alle Beispiele setzen voraus, dass der folgende Alias definiert wurde:

use Nette\Utils\Html;

Erstellung von HTML-Elementen

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

$el = Html::el('img'); // erstellt das Element <img>

Neben dem Elementnamen können Sie weitere Attribute direkt in HTML-Syntax angeben:

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

Oder übergeben Sie sie als assoziatives Array im zweiten Parameter:

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

Ändern und Abrufen des Elementnamens:

$el->setName('img');
$el->getName(); // 'img'
$el->isEmpty(); // true, da <img> ein leeres Element ist (z.B. <br>, <hr>)

HTML-Attribute

Einzelne HTML-Attribute können auf drei Arten geändert und gelesen werden, es hängt von Ihnen ab, welche Ihnen am besten gefällt. Die erste ist über Properties:

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

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

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

Die zweite Möglichkeit ist der Aufruf von Methoden, die – im Gegensatz zum Setzen von Eigenschaften – verkettet werden können:

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

$el->alt(null); // Attribut entfernen

Und die dritte Möglichkeit ist die ausführlichste:

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

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

$el->removeAttribute('alt');

Attribute können gesammelt mit addAttributes(array $attrs) gesetzt und mit removeAttributes(array $attrNames) entfernt werden.

Der Wert eines Attributs muss kein String sein; für boolesche Attribute können auch boolesche Werte 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 Werten sein, die durch Leerzeichen getrennt ausgegeben werden. Dies ist beispielsweise für CSS-Klassen nützlich:

$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 booleschen Werte angeben, ob der jeweilige Schlüssel als Wert ausgegeben werden soll:

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

CSS-Stile können als assoziatives Array geschrieben werden:

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

Wir haben eben Eigenschaften verwendet, aber dasselbe kann auch mit Methoden erreicht werden:

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

Oder auf die ausführlichste Weise:

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

Noch eine Anmerkung: Die Methode href() kann das Zusammenstellen von Query-Parametern in URLs vereinfachen:

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

Datenattribute

Datenattribute (data-*) werden besonders unterstützt. Da ihre Namen Bindestriche enthalten, ist der Zugriff über Eigenschaften und Methoden weniger elegant. Daher gibt es die Methode data():

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

Wenn der Wert eines Datenattributs ein Array ist, wird er automatisch nach JSON serialisiert:

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

Inhalt des Elements

Der innere Inhalt eines Elements wird mit den Methoden setHtml() oder setText() festgelegt. Verwenden Sie setHtml() nur, wenn Sie sicher sind, dass der übergebene String vertrauenswürdiges HTML enthält.

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() abgerufen. Letztere entfernt HTML-Tags aus dem Inhalt und konvertiert HTML-Entitäten in die entsprechenden Zeichen.

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

Kindknoten

Der Inhalt eines Elements kann auch ein Array von Kindknoten (Children) sein. Jeder Kindknoten kann entweder ein String oder ein weiteres Html-Element sein. Sie werden mit addHtml() oder addText() hinzugefügt:

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

Eine weitere Möglichkeit, einen neuen Html-Knoten zu erstellen und hinzuzufügen:

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

Mit den Kindknoten kann wie mit einem Array gearbeitet werden. Das heißt, man kann auf einzelne Knoten über eckige Klammern zugreifen, ihre Anzahl mit count() ermitteln und über sie iterieren:

$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

Ein neuer Knoten kann an einer bestimmten Position mit insert(?int $index, $child, bool $replace = false) eingefügt werden. Wenn $replace = false ist, wird das Element an der Position $index eingefügt und die nachfolgenden Elemente werden verschoben. Wenn $index = null ist, wird das Element am Ende angefügt.

// Fügt das Element an die erste Position ein und verschiebt die anderen
$el->insert(0, Html::el('span'));

Alle Kindknoten können mit der Methode getChildren() abgerufen und mit removeChildren() entfernt werden.

Erstellung eines Dokumentfragments

Wenn man mit einem Array von Knoten arbeiten möchte, ohne ein umschließendes Element zu benötigen, kann man ein sogenanntes Dokumentfragment erstellen, indem man null anstelle eines Elementnamens übergibt:

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

Einen schnelleren Weg zur Erstellung eines Fragments bieten die Methoden fromHtml() und fromText():

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

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

Generierung der HTML-Ausgabe

Der einfachste Weg, ein HTML-Element auszugeben, ist die Verwendung von echo oder die Typumwandlung des Objekts zu (string). Es ist auch möglich, das öffnende Tag, das schließende Tag und die Attribute separat auszugeben:

$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"'

Ein wichtiges Merkmal ist der automatische Schutz vor Cross-Site-Scripting (XSS). Alle Attributwerte oder Inhalte, die mit setText() oder addText() eingefügt werden, werden zuverlässig maskiert (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

Zur Konvertierung von HTML in reinen Text können Sie die statische Methode htmlToText() verwenden:

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

HtmlStringable

Das Objekt Nette\Utils\Html implementiert das Nette\HtmlStringable-Interface. Dieses Interface wird beispielsweise von Latte oder Formularen verwendet, um Objekte zu erkennen, deren __toString()-Methode HTML-Code zurückgibt. Dadurch wird verhindert, dass der Inhalt doppelt maskiert wird, wenn ein solches Objekt beispielsweise in einer Vorlage mit {$el} ausgegeben wird.

Version: 4.0