html_entity_decode
Converts every HTML entity in a string back to its corresponding character.
html_entity_decode(string $string, int $flags = ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, ?string $encoding = null): string- Added in PHP 4.3.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$string | string | The input string containing HTML entities. |
$flagsoptional | int= ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 | Bitmask controlling which quote styles are decoded, how invalid sequences are handled, and which document type's entity table is used. |
$encodingoptional | ?string= null | The character encoding to decode into. When null the default_charset ini setting is used. |
Return value
stringThe decoded string, with every recognised entity replaced by the character it names.
Errors
Does not throw. An unrecognised encoding is not an error: the default encoding is used instead and a warning is emitted.
Changelog
- PHP 8.1.0The default flags changed from ENT_COMPAT to ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, so single quotes are now decoded by default.
- PHP 8.0.0encoding is nullable.
html_entity_decode is the full inverse of htmlentities: it recognises the entire named-entity table for the chosen document type — ©, é, and hundreds more — plus numeric references such as A and B.
When to reach for it
Reach for it when text arrives already HTML-encoded and you need the real characters: a feed or scraped page you are turning into plain text, a database column that was double-escaped by an old CMS, or an email subject you are about to send as text/plain. If you only need the five characters htmlspecialchars handles, htmlspecialchars_decode is the narrower and safer choice.
What trips people up
Decoding is the opposite of sanitising. Running it on user input and then printing the result reintroduces working <script> tags — never decode on the way out to a browser.
Always pass the encoding explicitly. With the wrong one, é decodes to a byte your page cannot render. Note also that becomes U+00A0, a non-breaking space that trim does not remove and that == against a normal space fails on. And ' only decodes under ENT_HTML5 or ENT_XML1; the HTML 4.01 table does not define it.
Example
When to use it
- Convert a scraped or RSS-sourced HTML fragment into plain text for indexing or a text-only email.
- Repair database rows that were stored HTML-encoded by an older application.
- Decode entity-encoded values from a legacy XML or SOAP payload before comparing them.
Frequently asked questions
What is the difference between html_entity_decode and htmlspecialchars_decode?
html_entity_decode resolves the whole named entity table plus numeric references, while htmlspecialchars_decode only reverses the five characters htmlspecialchars encodes. Use the narrower one when you only ever encoded with htmlspecialchars.
Why is still not matching a normal space after decoding?
Because it decodes to U+00A0, a non-breaking space, which is a different character from the ASCII space. Replace it explicitly if you need plain spaces.
Is it safe to run html_entity_decode on user input?
Not before output. Decoding turns <script> back into a live tag, so never decode data on its way to a browser — decode only for plain-text processing.
More examples
Round trip with htmlentities
htmlentities converts both the markup characters and the accented letters into named entities. Decoding with the same flags and encoding returns a string identical to the original, which is what the final bool(true) confirms.
<?php
$original = "caf\u{00E9} & <cr\u{00E8}me> \"br\u{00FB}l\u{00E9}e\"";
$encoded = htmlentities($original, ENT_QUOTES, "UTF-8");
echo $encoded, "\n";
$decoded = html_entity_decode($encoded, ENT_QUOTES, "UTF-8");
echo $decoded, "\n";
var_dump($decoded === $original);How much each function decodes
html_entity_decode resolves every entity including © and é; htmlspecialchars_decode leaves those two untouched because they are outside its five-character set. The last line shows decoding to U+00A0, which trim leaves in place.
<?php
$s = "& < " © é |";
echo html_entity_decode($s, ENT_QUOTES, "UTF-8"), "\n";
echo htmlspecialchars_decode($s, ENT_QUOTES), "\n";
var_dump(html_entity_decode(" ", ENT_QUOTES, "UTF-8") === "\u{00A0}");
var_dump(trim(html_entity_decode(" x ", ENT_QUOTES, "UTF-8")));Document type changes the entity table
' is not part of the HTML 4.01 entity table, so with ENT_HTML401 it passes through untouched; ENT_HTML5 decodes it to an apostrophe. The numeric reference ' works under every document type, which is why encoders prefer it.
<?php
echo html_entity_decode("'", ENT_QUOTES | ENT_HTML401, "UTF-8"), "\n";
echo html_entity_decode("'", ENT_QUOTES | ENT_HTML5, "UTF-8"), "\n";
echo html_entity_decode("'", ENT_QUOTES, "UTF-8"), "\n";
echo html_entity_decode("♥", ENT_QUOTES | ENT_HTML5, "UTF-8"), "\n";
Discussion