HTML in Strings codieren (Thema: PHP Beispiele)

Anwendung der Funktion htmlentities() zur Codierung von HTML-Zeichen

1. Einleitung

Um HTML-Code in einem String so zu codieren, dass er vom Browser als normaler Text interpretiert wird, kann htmlentities($string, $flags, $encoding, $double_encode) verwendet werden. Die Funktion erwartet einen String als Übergabeparameter. Zudem können optional einige Flags ($flags) übergeben werden, sowie das Encoding ($encoding) des Strings (sollte in der Regel UTF-8 sein) und eine Angabe, ob bereits codierte HTML-Zeichen noch einmal codiert werden sollen ($double_encode).

Insbesondere Benutzereingaben sollten vor der Ausgabe immer mit htmlentities() codiert werden, andernfalls ergeben sich erhebliche Sicherheitslücken, da zum Beispiel Javascript-Code von außen eingeschleust werden kann.

2. Ein einfaches Beispiel

In diesem Beispiel soll eine einfache mathematische Aussage dargestellt werden. Diese enthält ein größer-als-Zeichen („>”), welches Teil der HTML-Syntax ist und daher codiert werden muss.

PHP-Code
<?php
	$str = 'Daher gilt: 100 > 5. qed.';
	var_dump(htmlentities($str));
?>

HTML-Code: Ausgabe
string(28) "Daher gilt: 100 &gt; 5. qed."


3. Auch einfache Anführungszeichen codieren

Standardmäßig codiert htmlentities() zwar doppelte Anführungszeichen ("), aber keine einfachen Anführungszeichen ('). In einigen Fällen kann dies ein Sicherheitsproblem sein. Um auch einfache Anführungszeichen zu codieren, muss ENT_QUOTES als zweiter Parameter hinzugefügt werden. Da man in der Regel dadurch keine Nachteile hat, ist das fast immer zu empfehlen.

Im nachfolgenden Beispiel soll eine URL eines Benutzers ausgegeben werden. Das Skript verwendet dabei falschen HTML-Code und setzt die Werte von Attributen in einfache statt doppelte Anführungszeichen. Das kann ein Angreifer ausnutzen, indem er in der auszugebenden URL ein einfaches Anführungszeichen platziert und danach eigenen HTML-Code einschleust (hier beispielsweise JavaScript).

PHP-Code
<?php
	$start = "<a href='";
	$end = "'>Die URL eines Benutzers</a>";
	$url = "http://www.google.de/' onmouseover='alert(12345);' title='";

	$code1 = $start . htmlentities($url) . $end;
	var_dump($code1);

	$code2 = $start . htmlentities($url, ENT_QUOTES) . $end;
	var_dump($code2);
?>

HTML-Code: Ausgabe
string(96) "<a href='http://www.google.de/' onmouseover='alert(12345);' title=''>Die URL eines Benutzers</a>"
string(116) "<a href='http://www.google.de/&#039; onmouseover=&#039;alert(12345);&#039; title=&#039;'>Die URL eines Benutzers</a>"


4. Zeichensatz festlegen

Die von htmlentities() durchgeführte Codierung ist auch vom verwendeten Zeichensatz abhängig. Um Probleme zu vermeiden, sollte daher der erwartete Zeichensatz immer angegeben werden. Dieser wird in Form eines Strings (Name des Zeichensatzes) als dritter Parameter übergeben. In der Regel sollte es sich dabei um „UTF-8” handeln.

Im nächsten Beispiel wird der Zeichensatz (UTF-8) einmal weggelassen und einmal übergeben. In ersterem Fall ist das Ergebnis von htmlentities() falsch, da es die UTF-8-Zeichen nicht richtig interpretiert. Nur bei Angabe des Zeichensatzes entspricht die Rückgabe den Erwartungen.

PHP-Code
<?php
	$str = 'Das ist ein ٽ<em>Beispiel</em>ٽ';

	var_dump(htmlentities($str, ENT_QUOTES));
	var_dump(htmlentities($str, ENT_QUOTES, 'UTF-8'));
?>

HTML-Code: Ausgabe
string(73) "Das ist ein &Ugrave;&frac12;&lt;em&gt;Beispiel&lt;/em&gt;&Ugrave;&frac12;"
string(45) "Das ist ein ٽ&lt;em&gt;Beispiel&lt;/em&gt;ٽ"


5. Keine doppelten Codierungen

Kann der zu codierende String bereits codierte HTML-Zeichen enthalten, welche nicht noch einmal codiert werden sollen, dann kann (bool)false als vierter Parameter übergeben werden. Andernfalls werden diese automatisch mehrfach codiert, was zu unschönen (und falschen) Ergebnissen führen kann.

Im nachfolgenden Beispiel wird ein String übergeben, welcher einen Umlaut enthält, der bereits zuvor codiert wurde (aus „ö” wurde „&ouml;”). Bei „normaler” Anwendung von htmlentities würde das „&” wiederum codiert werden, wodurch aus „&ouml;” nun „&amp;ouml;” werden würde. Das ist offensichtlich nicht gewünscht, daher wird bei der zweiten Ausgabe ein (bool)false als vierter Parameter übergeben.

PHP-Code
<?php
	$str = 'Ein fr&ouml;hliches Beispiel!';

	var_dump(htmlentities($str, ENT_QUOTES, 'UTF-8', true));
	var_dump(htmlentities($str, ENT_QUOTES, 'UTF-8', false));
?>

HTML-Code: Ausgabe
string(33) "Ein fr&amp;ouml;hliches Beispiel!"
string(29) "Ein fr&ouml;hliches Beispiel!"


6. Eine einheitliche htmlentities-Funktion pro Projekt

Es kann hilfreich sein, für ein Projekt oder eine Komponente eine zentrale htmlentities-Funktion zu definieren. So ist es beispielsweise möglich, den verwendeten Zeichensatz an einer zentralen Stelle festzulegen. Im Beispiel wird eine solche Funktion definiert, welche htmlentities() immer mit ENT_QUOTES als Flag und UTF-8 als Zeichensatz aufruft. Sie bietet zudem auch gleich die Möglichkeit, zu lange Strings ab einer gewissen Länge abzuschneiden (mit „...” am Ende), was im Entwicklungsalltag durchaus nützlich sein kann.

PHP-Code
<?php
	function myhtmlentities($str, $maxlength=-1, $tooLongStr='...', $doubleEncode=true) {
		if ($maxlength>=0 && isset($str[$maxlength])) {
			$str = mb_substr($str, 0, $maxlength) . $tooLongStr;
		}
		return htmlentities($str, ENT_QUOTES, 'UTF-8', $doubleEncode);
	}

	$str = 'Das ist ein <em>"Beispiel"</em>';
	var_dump(myhtmlentities($str));
	var_dump(myhtmlentities($str, 10));
?>

HTML-Code: Ausgabe
string(53) "Das ist ein &lt;em&gt;&quot;Beispiel&quot;&lt;/em&gt;"
string(13) "Das ist ei..."


7. Codierung wieder umkehren

Soll die Codierung wieder umgekehrt werden, dann kann html_entity_decode() verwendet werden

PHP-Code
<?php
	$str = 'Das ist <em>HTML</em>';
	$strEntities = htmlentities($str);
	var_dump($strEntities);
	var_dump(html_entity_decode($strEntities));
?>

HTML-Code: Ausgabe
string(33) "Das ist &lt;em&gt;HTML&lt;/em&gt;"
string(21) "Das ist <em>HTML</em>"


Kommentare (1)

Von neu nach alt
Sehr nützlich
ArnoNuehm (Gast) #