htmlspecialchars

Converts the five HTML-significant characters into entities so text is safe to print in a page.

Signature
htmlspecialchars(string $string, int $flags = ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, ?string $encoding = null, bool $double_encode = true): string
  • Added in PHP 4.0

Parameters

ParameterTypeDescription
$stringstringThe string being converted.
$flagsoptionalint= ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401Bitmask controlling quote handling, invalid-sequence handling and the document type used.
$encodingoptional?string= nullThe character encoding of the input. When null the default_charset ini setting is used.
$double_encodeoptionalbool= trueWhen false, existing entities in the input are not encoded again.

Return value

stringThe converted string; an empty string if the input contains an invalid code unit sequence and neither ENT_IGNORE nor ENT_SUBSTITUTE is set.

Errors

Does not throw. An unrecognised encoding is not an error: the default encoding is used instead and a warning is emitted. Input containing an invalid code unit sequence yields an empty string unless ENT_IGNORE or ENT_SUBSTITUTE is set.

Changelog

  • PHP 8.1.0The default flags changed from ENT_COMPAT to ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, so single quotes are now encoded by default and invalid sequences are substituted rather than emptying the string.

htmlspecialchars converts &, <, >, " and ' into entities. Those five characters are the ones that can break out of text and become markup, which makes this function the standard defence against cross-site scripting when echoing data into HTML.

When to reach for it

Every time a value that did not come from you is printed into a page: <?= htmlspecialchars($comment, ENT_QUOTES, 'UTF-8') ?>. Prefer it over htmlentities for UTF-8 output — it produces smaller, still-readable text and escapes exactly the characters that matter.

What trips people up

Before PHP 8.1 the default flags were ENT_COMPAT, which left single quotes alone — a value dropped into a single-quoted attribute could escape it. PHP 8.1 changed the default to ENT_QUOTES, but code that explicitly passes ENT_COMPAT or an old flag set still has the hole.

HTML escaping is context-specific. Inside a <script> block, a style attribute or a URL, entities are not interpreted the way you expect; use json_encode for JavaScript values and rawurlencode for URL components.

Finally, escape at output time, not on input. Escaping before storage leaves entity-encoded rows that break searching, string length and any non-HTML consumer.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Print a user comment, username or search term into an HTML page without letting tags execute.
  • Fill an input's value attribute with data that may contain quotes.
  • Render a log line or exception message that may contain angle brackets into a debug page.

Frequently asked questions

What is the difference between htmlspecialchars and htmlentities?

htmlspecialchars encodes only the five markup-significant characters, while htmlentities also converts every character with a named entity, such as accented letters. For UTF-8 pages htmlspecialchars is the better default.

Does htmlspecialchars escape single quotes?

Since PHP 8.1 the default flags include ENT_QUOTES, so yes. On older versions, or when you pass ENT_COMPAT explicitly, single quotes are left alone and single-quoted attributes are unsafe.

Is htmlspecialchars enough to prevent XSS?

It is enough for values placed in HTML text or a quoted attribute. It is not sufficient inside script blocks, style blocks, URLs or event handlers, which need json_encode or rawurlencode instead.

More examples

Quotes inside an attribute

The first tag is safe: both quote styles are encoded. The second uses ENT_COMPAT and single-quoted markup, so the apostrophe in o'clock closes the attribute early. The third encodes no quotes at all and breaks immediately — the flags are not cosmetic.

Example · php
<?php
$value = "5 o'clock \"sharp\"";

echo '<input value="' . htmlspecialchars($value, ENT_QUOTES, "UTF-8") . '">', "\n";
echo "<input value='" . htmlspecialchars($value, ENT_COMPAT, "UTF-8") . "'>", "\n";
echo '<input value="' . htmlspecialchars($value, ENT_NOQUOTES, "UTF-8") . '">', "\n";

Double encoding

An already-encoded string gains a second layer by default, printing &amp;amp;. Setting double_encode to false leaves existing entities alone while still encoding a bare ampersand, as the third line shows.

Example · php
<?php
$s = "Tom &amp; Jerry";

echo htmlspecialchars($s), "\n";
echo htmlspecialchars($s, ENT_QUOTES, "UTF-8", false), "\n";

$plain = "Tom & Jerry";
echo htmlspecialchars($plain, ENT_QUOTES, "UTF-8", false), "\n";

Escaping is context-specific

In HTML text the entity-encoded value is inert. Inside a script block json_encode is the right escaper — it escapes the closing tag sequence — and in a URL path rawurlencode is. Using htmlspecialchars in all three places would leave the last two exploitable.

Example · php
<?php
$name = '</script><img src=x onerror=alert(1)>';

echo "<div>", htmlspecialchars($name, ENT_QUOTES, "UTF-8"), "</div>\n";
echo "<script>var n = ", json_encode($name), ";</script>\n";
echo "<a href=\"/u/", rawurlencode($name), "\">link</a>\n";

Discussion

  • Be the first to comment on this lesson.