Elementi HTML
La classe Nette\Utils\Html è un aiuto per la generazione di codice HTML che previene le vulnerabilità Cross Site Scripting (XSS).
Funziona in modo tale che i suoi oggetti rappresentano elementi HTML, si impostano i loro parametri e si lascia che vengano resi:
$el = Html::el('img'); // crea l'elemento <img>.
$el->src = 'image.jpg'; // imposta l'attributo src
echo $el; // stampa '<img src="immagine.jpg">'
Installazione:
composer require nette/utils
Tutti gli esempi presuppongono che sia definito il seguente alias di classe:
use Nette\Utils\Html;
Creazione di un elemento HTML
L'elemento viene creato con il metodo Html::el()
:
$el = Html::el('img'); // crea l'elemento <img
Oltre al nome, è possibile inserire altri attributi nella sintassi HTML:
$el = Html::el('input type=text class="red important"');
Oppure passarli come array associativo al secondo parametro:
$el = Html::el('input', [
'type' => 'text',
'class' => 'important',
]);
Per modificare e restituire il nome di un elemento:
$el->setName('img');
$el->getName(); // 'img'
$el->isEmpty(); // vero, poiché <img> è un elemento nullo
Attributi HTML
È possibile impostare e ottenere i singoli attributi HTML in tre modi, a seconda di quello che si preferisce. Il primo è attraverso le proprietà:
$el->src = 'image.jpg'; // imposta l'attributo src
echo $el->src; // 'image.jpg'
unset($el->src); // rimuove l'attributo
// oppure $el->src = null;
Il secondo modo è quello di chiamare metodi che, a differenza dell'impostazione delle proprietà, possono essere concatenati tra loro:
$el = Html::el('img')->src('image.jpg')->alt('photo');
// <img src="image.jpg" alt="photo">
$el->alt(null); // rimuove l'attributo
E il terzo modo è il più loquace:
$el = Html::el('img')
->setAttribute('src', 'image.jpg')
->setAttribute('alt', 'photo');
echo $el->getAttribute('src'); // 'image.jpg'
$el->removeAttribute('alt');
In blocco, gli attributi possono essere impostati con addAttributes(array $attrs)
e cancellati con
removeAttributes(array $attrNames)
.
Il valore di un attributo non deve essere necessariamente una stringa, ma si possono usare anche valori logici per gli attributi logici:
$checkbox = Html::el('input')->type('checkbox');
$checkbox->checked = true; // <input type="checkbox" checked>
$checkbox->checked = false; // <input type="checkbox">
Un attributo può anche essere un array di token, separati da spazi, adatto per esempio alle classi CSS:
$el = Html::el('input');
$el->class[] = 'active';
$el->class[] = null; // null is ignored
$el->class[] = 'top';
echo $el; // '<input class="active top">'
Un'alternativa è un array associativo, in cui i valori dicono se la chiave deve essere elencata:
$el = Html::el('input');
$el->class['active'] = true;
$el->class['top'] = false;
echo $el; // '<input class="active">'
Gli stili CSS possono essere scritti sotto forma di array associativi:
$el = Html::el('input');
$el->style['color'] = 'green';
$el->style['display'] = 'block';
echo $el; // '<input style="color: green; display: block">'
Abbiamo utilizzato le proprietà, ma la stessa cosa può essere fatta utilizzando i metodi:
$el = Html::el('input');
$el->style('color', 'green');
$el->style('display', 'block');
echo $el; // '<input style="color: green; display: block">'
O anche nel modo più loquace:
$el = Html::el('input');
$el->appendAttribute('style', 'color', 'green');
$el->appendAttribute('style', 'display', 'block');
echo $el; // '<input style="color: green; display: block">'
Un'ultima cosa: il metodo href()
può facilitare la composizione dei parametri di query in un URL:
echo Html::el('a')->href('index.php', [
'id' => 10,
'lang' => 'en',
]);
// '<a href="index.php?id=10&lang=en"></a>'
Attributi dei dati
Gli attributi dei dati hanno un supporto speciale. Poiché i loro nomi contengono dei trattini, l'accesso tramite proprietà e
metodi non è molto elegante, quindi esiste un metodo data()
:
$el = Html::el('input');
$el->{'data-max-size'} = '500x300'; // non è così elegante
$el->data('max-size', '500x300'); // è elegante
echo $el; // '<input data-max-size="500x300">'
Se il valore dell'attributo dati è un array, viene automaticamente serializzato in JSON:
$el = Html::el('input');
$el->data('items', [1,2,3]);
echo $el; // '<input data-items="[1,2,3]">'
Contenuto dell'elemento
Il contenuto interno dell'elemento viene impostato dai metodi setHtml()
o setText()
. Usare il primo
solo se si sa che si sta passando in modo affidabile una stringa HTML sicura nel parametro.
echo Html::el('span')->setHtml('hello<br>');
// '<span>hello<br></span>'
echo Html::el('span')->setText('10 < 20');
// '<span>10 < 20</span>'
Al contrario, il contenuto interno si ottiene con i metodi getHtml()
o getText()
. Il secondo rimuove
i tag dall'output HTML e converte le entità HTML in caratteri.
echo $el->getHtml(); // '10 < 20'
echo $el->getText(); // '10 < 20'
Nodi figli
Il contenuto interno di un elemento può anche essere un array di figli. Ognuno di essi può essere una stringa o un altro
elemento Html
. Vengono inseriti usando addHtml()
o addText()
:
$el = Html::el('span')
->addHtml('hello<br>')
->addText('10 < 20')
->addHtml( Html::el('br') );
// <span>hello<br>10 < 20<br></span>
Un altro modo per creare e inserire un nuovo nodo Html
:
$ul = Html::el('ul');
$ul->create('li', ['class' => 'first'])
->setText('hello');
// <ul><li class="first">hello</li></ul>
È possibile lavorare con i nodi come se fossero elementi di un array. Si può quindi accedere ai singoli nodi usando le
parentesi quadre, contarli con count()
e iterare su di essi:
$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
Un nuovo nodo può essere inserito in una posizione specifica usando
insert(?int $index, $child, bool $replace = false)
. Se $replace = false
, inserisce l'elemento nella
posizione $index
e sposta gli altri. Se $index = null
, aggiunge un elemento alla fine.
// inserisce l'elemento nella prima posizione e fa avanzare gli altri
$el->insert(0, Html::el('span'));
Tutti i nodi vengono restituiti dal metodo getChildren()
e rimossi dal metodo removeChildren()
.
Creare un frammento di documento
Se si vuole lavorare con una matrice di nodi e non si è interessati all'elemento che li avvolge, si può creare un cosiddetto
frammento di documento passando null
al posto del nome dell'elemento:
$el = Html::el(null)
->addHtml('hello<br>')
->addText('10 < 20')
->addHtml( Html::el('br') );
// hello<br>10 < 20<br>
I metodi fromHtml()
e fromText()
offrono un modo più rapido per creare un frammento:
$el = Html::fromHtml('hello<br>');
echo $el; // 'hello<br>'
$el = Html::fromText('10 < 20');
echo $el; // '10 < 20'
Generare l'output HTML
Il modo più semplice per generare un elemento HTML è usare echo
o lanciare un oggetto in (string)
.
È anche possibile stampare separatamente i tag e gli attributi di apertura o chiusura:
$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"'
Una caratteristica importante è la protezione automatica contro il Cross Site Scripting (XSS). Tutti i valori degli
attributi o i contenuti inseriti con setText()
o addText()
vengono evasi in modo affidabile:
echo Html::el('div')
->title('" onmouseover="bad()')
->setText('<script>bad()</script>');
// <div title='" onmouseover="bad()'><script>bad()</script></div>
Conversione HTML ↔ Testo
È possibile utilizzare il metodo statico htmlToText()
per convertire l'HTML in testo:
echo Html::htmlToText('<span>One & Two</span>'); // 'One & Two'
HtmlStringable
L'oggetto Nette\Utils\Html
implementa l'interfaccia Nette\HtmlStringable
, che, ad esempio, Latte
o i form utilizzano per distinguere gli oggetti che hanno un metodo __toString()
che restituisce codice HTML.
Quindi il doppio escape non si verifica se, ad esempio, si stampa l'oggetto nel modello usando {$el}
.