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&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 < 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 < 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 < 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 < 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 < 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()'><script>bad()</script></div>
Konvertierung HTML ↔ Text
Sie können die statische Methode htmlToText()
verwenden, um HTML in Text umzuwandeln:
echo Html::htmlToText('<span>Ein & 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.