Signature
htmlentities(
string $string,
int $flags = ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401,
?string $encoding = null,
bool $double_encode = true
): stringPurpose
htmlentities() prepares text for safe placement inside HTML output. It behaves like htmlspecialchars(), but goes further: every character that has a named HTML entity is replaced by that entity. A < becomes <, an ampersand becomes &, and letters such as é or symbols such as € become é and €.
The main reason to call it is output escaping. Text that came from a user, a database or another system should be converted before it is printed into an HTML page, so the browser shows it as text rather than interpreting it as markup.
Signature
Parameters and defaults
$string: the input text to convert.$flags: a bitmask that controls quote handling, invalid byte handling and the document type. The default isENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401. Quote flags areENT_COMPAT(double quotes only),ENT_QUOTES(both kinds) andENT_NOQUOTES(neither). Document type flags areENT_HTML401,ENT_XML1,ENT_XHTMLandENT_HTML5.$encoding: the character set of the input. When it isnull, PHP uses thedefault_charsetsetting. Passing'UTF-8'explicitly makes your code independent of configuration.$double_encode: whentrue(the default), existing entities such as&are encoded again. Whenfalse, existing valid entities are left alone.
Return value and failure cases
The function returns the encoded string. If the input contains an invalid code unit sequence for the chosen encoding and neither ENT_SUBSTITUTE nor ENT_IGNORE is set, the result is an empty string. With ENT_SUBSTITUTE, which is part of the default, bad bytes become the Unicode replacement character U+FFFD in UTF-8. ENT_IGNORE silently drops them, which the manual discourages because of possible security implications. An unrecognized encoding name causes a warning, and the default encoding is used instead.
Example 1: basic conversion
This example converts markup characters, both quote types and an accented letter.
$text = "Caf\u{E9} <b>\"Tom\" & 'Jerry'</b>";
echo htmlentities($text, ENT_QUOTES | ENT_HTML401, 'UTF-8') . "\n";Café <b>"Tom" & 'Jerry'</b>
The double quotes become ", the single quotes become ', and é becomes é.
Example 2: comparing with htmlspecialchars()
Both functions escape &, < and >, but only htmlentities() also converts the euro sign.
$s = "Price: 5 \u{20AC} & it's <ok>";
echo json_encode([
'entities' => htmlentities($s, ENT_NOQUOTES, 'UTF-8'),
'special' => htmlspecialchars($s, ENT_NOQUOTES, 'UTF-8'),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";{"entities":"Price: 5 € & it's <ok>","special":"Price: 5 € & it's <ok>"}
Because ENT_NOQUOTES is used, the apostrophe stays as it is in both results.
Example 3: double encoding and invalid bytes
This example shows $double_encode and the effect of ENT_SUBSTITUTE on an invalid UTF-8 byte.
$input = 'Fish & Chips < "A&B"';
$flags = ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401;
echo json_encode([
'twice' => htmlentities($input, $flags, 'UTF-8', true),
'once' => htmlentities($input, $flags, 'UTF-8', false),
'strict' => htmlentities("\x8F!!!", ENT_QUOTES, 'UTF-8'),
'substitute' => htmlentities("\x8F!!!", ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";{"twice":"Fish &amp; Chips &lt; "A&B"","once":"Fish & Chips < "A&B"","strict":"","substitute":"�!!!"}
With $double_encode set to false, the existing & and < survive unchanged, while the bare & in A&B is still encoded. The byte \x8F is not valid UTF-8, so without ENT_SUBSTITUTE the whole result is empty.
Edge cases
- Encoding the same string twice produces garbled output such as
&amp;, unless$double_encodeisfalse. - The flags default changed in PHP 8.1.0: older code that relied on
ENT_COMPATas the default no longer leaves single quotes alone. Since PHP 8.0.0 the$encodingargument acceptsnull. - The document type flag matters.
ENT_HTML401,ENT_XML1,ENT_XHTMLandENT_HTML5select different entity tables, so the same input can produce different output. Useget_html_translation_table()to inspect the table for a given flag set. - If the encoding does not match the real bytes of the string, characters may be mangled or the result may be empty.
Common mistakes
- Using it for the wrong context. The function is meant for HTML text and quoted attribute values. It does not make a value safe inside JavaScript, CSS or URLs. Use the appropriate escaping for each of those, for example
urlencode()for query string parts. - Escaping on input instead of output. Store raw data and convert only when you render HTML. Otherwise you will end up with entities stored in your data and double encoding later.
- Forgetting quotes in attributes.
ENT_NOQUOTESandENT_COMPATcan leave single quotes unescaped, which is unsafe inside a single-quoted attribute. KeepENT_QUOTES. - Using ENT_IGNORE casually. Discarding invalid sequences can hide problems and has security implications.
- Assuming it is required for UTF-8 pages. When the page is UTF-8,
htmlspecialchars()is usually enough, since characters likeécan be sent directly.htmlentities()is helpful when the output channel is not reliably UTF-8.
Related functions
htmlspecialchars(): converts only the special markup characters.html_entity_decode(): the reverse operation.get_html_translation_table(): returns the translation table used.nl2br(): inserts HTML line breaks before newlines.urlencode(): encodes a string for use in a URL.
Recap
htmlentities() turns every character that has a named HTML entity into that entity and returns a string. Pass 'UTF-8' explicitly, keep ENT_QUOTES, use ENT_SUBSTITUTE so invalid bytes do not produce an empty string, and set $double_encode to false only when the input already contains valid entities you want to keep.
Tested examples
$text = "Caf\u{E9} <b>\"Tom\" & 'Jerry'</b>";
echo htmlentities($text, ENT_QUOTES | ENT_HTML401, 'UTF-8') . "\n";
Café <b>"Tom" & 'Jerry'</b>
$s = "Price: 5 \u{20AC} & it's <ok>";
echo json_encode([
'entities' => htmlentities($s, ENT_NOQUOTES, 'UTF-8'),
'special' => htmlspecialchars($s, ENT_NOQUOTES, 'UTF-8'),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";
{"entities":"Price: 5 € & it's <ok>","special":"Price: 5 € & it's <ok>"}
$input = 'Fish & Chips < "A&B"';
$flags = ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401;
echo json_encode([
'twice' => htmlentities($input, $flags, 'UTF-8', true),
'once' => htmlentities($input, $flags, 'UTF-8', false),
'strict' => htmlentities("\x8F!!!", ENT_QUOTES, 'UTF-8'),
'substitute' => htmlentities("\x8F!!!", ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";
{"twice":"Fish &amp; Chips &lt; "A&B"","once":"Fish & Chips < "A&B"","strict":"","substitute":"�!!!"}