Displaying a string in PHP looks harmless until the string contains HTML. A user enters <strong>Hello</strong>, and the browser helpfully turns it into bold text. Browsers are obedient like that, even when we would prefer them to be suspicious.
The PHP htmlentities() function converts applicable characters into HTML entities. This lets the browser display HTML-like content as text instead of interpreting it as markup.
It is useful when you specifically need broad entity conversion. For ordinary HTML output escaping, however, htmlspecialchars() is usually the more practical choice. This article explains the difference and shows how to use htmlentities() correctly in PHP 8.2 and later.
Quick Answer
Use htmlentities() when you want PHP to convert every character that has a corresponding HTML entity.
<?php
$input = '<strong>Café & tea</strong>';
$encoded = htmlentities(
$input,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
);
echo $encoded;
The generated HTML source contains encoded entities:
<strong>Café & tea</strong>
The browser displays the original value as plain text:
<strong>Café & tea</strong>
For most values printed into an HTML text node or attribute, prefer htmlspecialchars(). It escapes the characters that can affect HTML parsing without converting ordinary accented characters such as é into named entities.
PHP htmlentities() Syntax
The current function signature is:
htmlentities(
string $string,
int $flags = ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401,
?string $encoding = null,
bool $double_encode = true
): string
The four parameters control what is encoded and how PHP handles the input:
$stringis the text to encode.$flagscontrol quote handling, invalid byte sequences, and the document type.$encodingspecifies the character encoding. UseUTF-8in modern applications.$double_encodedecides whether existing entities such as&should be encoded again.
The official PHP htmlentities() documentation lists every supported flag and character encoding.
Basic htmlentities() Example
Consider a string containing an HTML element:
<?php
$message = '<em>Save your changes</em>';
echo htmlentities(
$message,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
);
The browser does not render an italic message. It displays the tags themselves because the angle brackets have been encoded.
<em>Save your changes</em>
htmlentities() returns the converted string. It does not modify the original variable.
One important boundary is easy to miss: HTML entity encoding protects an HTML output context. It does not make a value safe for an SQL query, URL, JavaScript block, or CSS rule. For database queries, use MySQLi prepared statements to prevent SQL injection.
Choose the Correct htmlentities() Flags
The $flags argument is a bitmask. Multiple constants can be combined with the bitwise OR operator.
<?php
$encoded = htmlentities(
$input,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
);
This combination is a sensible choice for a modern HTML5 page:
ENT_QUOTESconverts both single and double quotes.ENT_SUBSTITUTEreplaces invalid character sequences instead of silently losing the entire result.ENT_HTML5applies the HTML5 entity rules.
ENT_QUOTES, ENT_COMPAT, and ENT_NOQUOTES
These constants decide how quotes are handled.
<?php
$text = 'She said, "It\'s ready."';
echo htmlentities($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
With ENT_QUOTES, PHP encodes both types of quotation marks:
She said, "It's ready."
ENT_COMPAT encodes double quotes but leaves single quotes unchanged. ENT_NOQUOTES leaves both types unchanged.
For dynamic values placed inside HTML attributes, ENT_QUOTES is the safest default because an application may use either single or double quotes around an attribute value.
<input
type="text"
name="display-name"
value="<?= htmlentities(
$displayName,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
) ?>"
>
Use ENT_SUBSTITUTE for Invalid Input
A string may contain bytes that are not valid for its declared encoding. Without suitable handling, conversion can fail or produce an empty result.
ENT_SUBSTITUTE replaces an invalid sequence with the Unicode replacement character. This is normally preferable to ENT_IGNORE, which silently removes invalid sequences and is discouraged because discarded bytes can change the meaning of the text.
<?php
$encoded = htmlentities(
$possiblyInvalidInput,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
);
Using ENT_SUBSTITUTE does not repair a broken data pipeline. It only gives the output layer a predictable way to handle invalid input. The application should still use UTF-8 consistently when receiving, storing, and returning text.
Specify UTF-8 Explicitly
The encoding argument tells PHP how to interpret the input bytes.
<?php
$name = 'Renée';
echo htmlentities(
$name,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
);
PHP can use the default_charset configuration value when the encoding argument is omitted. Passing 'UTF-8' explicitly still makes the function call easier to understand and prevents an unexpected server configuration from changing its behaviour.
The declared encoding must match the actual string encoding. Labelling ISO-8859-1 data as UTF-8 does not convert it. It only gives PHP incorrect instructions with impressive confidence.
When conversion between encodings is genuinely required, perform that conversion separately. Do not use htmlentities() as a character-set conversion tool.
Avoid Double Encoding Existing Entities
The fourth argument, $double_encode, controls what happens to entities already present in the string.
<?php
$text = 'Tea & coffee';
echo htmlentities(
$text,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
);
Because double encoding is enabled by default, the existing ampersand is encoded again:
Tea &amp; coffee
Set the fourth argument to false when the input may already contain valid entities that must remain unchanged.
<?php
$text = 'Tea & coffee';
$encoded = htmlentities(
$text,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8',
false
);
echo $encoded;
The result remains:
Tea & coffee
Do not automatically set $double_encode to false everywhere. Raw text normally should not contain pre-encoded entities. A mixture of raw and encoded data often means values are being escaped too early or more than once.
A reliable rule is to store the original text and encode it at the output boundary. This keeps database values reusable for HTML, JSON, email, exports, and other destinations that require different handling.
htmlentities() vs htmlspecialchars()
htmlentities() and htmlspecialchars() are often treated as interchangeable, but they encode different sets of characters.
htmlspecialchars() converts the characters that have a special meaning in HTML:
&<>- single quotes, depending on the flags
- double quotes, depending on the flags
htmlentities() converts those characters and also converts other characters that have matching HTML entities.
<?php
$text = 'Café <strong>menu</strong>';
echo htmlspecialchars(
$text,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
);
echo PHP_EOL;
echo htmlentities(
$text,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
);
The results differ:
Café <strong>menu</strong>
Café <strong>menu</strong>
Both functions prevent the <strong> element from being interpreted as markup. The difference is that htmlentities() also converts é.
For most modern UTF-8 pages, converting accented letters into named entities provides little practical benefit. Browsers can display UTF-8 characters directly, and the original text is usually easier to inspect in the generated source.
Use htmlspecialchars() for normal HTML output escaping. Use htmlentities() when the broader conversion is an actual requirement, such as when generating entity-based output for a specific legacy or interoperability need.
The PHP htmlspecialchars() documentation explains its supported flags and encoding behaviour.
Escape Data for Its Output Context
Calling htmlentities() is not a universal sanitisation step. It is an encoding operation for HTML output.
The correct treatment depends on where the value is inserted.
HTML Text Content
Escape dynamic text before placing it between HTML tags.
<p>
<?= htmlspecialchars(
$comment,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
) ?>
</p>
Although htmlentities() also works here, htmlspecialchars() is normally sufficient.
HTML Attribute Values
Encode dynamic attribute values and keep the value enclosed in quotes.
<input
type="text"
name="title"
value="<?= htmlspecialchars(
$title,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
) ?>"
>
ENT_QUOTES matters here because it encodes both single and double quotes.
URLs Inside HTML
A URL may need two separate operations. Encode its query parameter as a URL component first, and then escape the complete URL for HTML output.
<?php
$searchUrl = '/search.php?q=' . rawurlencode($searchTerm);
?>
<a href="<?= htmlspecialchars(
$searchUrl,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
) ?>">
View search results
</a>
rawurlencode() and HTML escaping solve different problems. One prepares a value for a URL component. The other prevents the URL from interfering with the surrounding HTML.
JavaScript and JSON
Do not place an HTML-encoded value directly into JavaScript and assume it is safe. Use JSON encoding when passing PHP data into a script.
<script>
const profileName = <?= json_encode(
$profileName,
JSON_HEX_TAG
| JSON_HEX_AMP
| JSON_HEX_APOS
| JSON_HEX_QUOT
| JSON_THROW_ON_ERROR
) ?>;
</script>
This keeps the encoding appropriate for JavaScript syntax. HTML entities are not a substitute for JSON string encoding.
Encode on Output, Not Before Storage
A common mistake is to run htmlentities() before saving user input to the database.
<?php
// Avoid storing HTML-encoded text.
$storedComment = htmlentities(
$_POST['comment'],
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
);
This stores presentation-specific data instead of the original value. It can lead to double encoding, awkward searches, confusing exports, and incorrect output in non-HTML formats.
Store the original validated text. Use a prepared statement for the database operation. Escape the value later when it is inserted into HTML.
<?php
$comment = trim($_POST['comment'] ?? '');
$stmt = $mysqli->prepare(
'INSERT INTO comments (comment_text) VALUES (?)'
);
$stmt->bind_param('s', $comment);
$stmt->execute();
When displaying the saved value:
<p>
<?= htmlspecialchars(
$comment,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
) ?>
</p>
This separation keeps the data clean. Database safety is handled by prepared statements, while HTML safety is handled at the output boundary.
Decode HTML Entities with html_entity_decode()
html_entity_decode() performs the reverse operation. It converts HTML entities back to their corresponding characters.
<?php
$encoded = 'Tom & Jerry <strong>show</strong>';
$decoded = html_entity_decode(
$encoded,
ENT_QUOTES | ENT_HTML5,
'UTF-8'
);
echo $decoded;
The output is:
Tom & Jerry <strong>show</strong>
Decoding does not make content safe to display. In fact, it can restore HTML tags that were previously encoded. Escape the result again before inserting it into an HTML page when it must be shown as text.
<?php
$decoded = html_entity_decode(
$storedValue,
ENT_QUOTES | ENT_HTML5,
'UTF-8'
);
?>
<p>
<?= htmlspecialchars(
$decoded,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
) ?>
</p>
The related get_html_translation_table() function can return the translation table used by PHP for HTML entity conversion. It is occasionally useful for debugging or inspecting the characters affected by a specific document type.
<?php
$table = get_html_translation_table(
HTML_ENTITIES,
ENT_QUOTES | ENT_HTML5,
'UTF-8'
);
echo $table['é'];
The official html_entity_decode() reference documents the supported flags and decoding behaviour.
Common htmlentities() Mistakes and Fixes
Encoding the Same Value More Than Once
Double encoding commonly appears when a value is escaped before storage and then escaped again during display.
<?php
$text = 'Fish & chips';
$once = htmlentities(
$text,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
);
$twice = htmlentities(
$once,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
);
echo $twice;
The ampersand becomes increasingly encoded:
Fish &amp; chips
Fix this by storing raw text and escaping it only when producing HTML output. Do not use repeated decoding as a cleanup strategy because it can unexpectedly restore executable markup.
Using the Wrong Character Encoding
If the input is UTF-8 but the function is told to use another encoding, accented or multilingual text may be corrupted.
<?php
echo htmlentities(
$text,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
);
Keep the application consistent. Use UTF-8 in PHP, the database connection, table columns, HTML documents, and HTTP responses.
Using htmlentities() as an Input Filter
htmlentities() does not validate input and should not be used to decide whether a value is acceptable.
Validation and output encoding are separate steps. For example, validate an email address when receiving it, but still escape it before displaying it in HTML.
<?php
$email = trim($_POST['email'] ?? '');
if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
$error = 'Enter a valid email address.';
}
<p>
<?= htmlspecialchars(
$email,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
) ?>
</p>
The PHP filter_var() function is suitable for validating and sanitising supported data types. It does not replace context-aware output escaping.
Escaping an Entire HTML Fragment
Passing trusted application markup through htmlentities() turns the complete fragment into visible text.
<?php
$html = '<p>Welcome, <strong>Sam</strong>.</p>';
echo htmlentities(
$html,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
);
This is correct only when the intention is to show the HTML source. When an application intentionally accepts a limited set of HTML elements, it needs a proper HTML sanitiser with an allowlist. Decoding or selectively replacing entity strings is not a reliable sanitisation method.
Using HTML Encoding for SQL or JavaScript
HTML entities do not prevent SQL injection and do not correctly encode JavaScript strings.
- Use prepared statements for SQL queries.
- Use
json_encode()when transferring PHP data to JavaScript. - Use URL encoding for URL components.
- Use HTML escaping only when inserting text into HTML.
The destination determines the encoding. There is no single escape function that safely handles every context.
Practical htmlentities() Helper
If a project genuinely needs broad HTML entity conversion in several places, a small helper keeps the flags and encoding consistent.
<?php
function encodeHtmlEntities(string $value): string
{
return htmlentities(
$value,
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,
'UTF-8'
);
}
Use it only in HTML output contexts where htmlentities() is the intended choice.
<p>
<?= encodeHtmlEntities($description) ?>
</p>
A helper improves consistency, but it does not remove the need to think about context. A value inserted into JavaScript, JSON, SQL, CSS, or a URL still needs the correct encoding method for that destination.
Developer FAQ
Does htmlentities() prevent XSS?
It can prevent HTML injection when untrusted text is encoded correctly before being inserted into an HTML text or quoted attribute context.
It is not a complete XSS solution for every context. Values placed inside JavaScript, CSS, URLs, event-handler attributes, or raw HTML require different handling. A strong PHP security approach combines context-aware output encoding with input validation, prepared statements, safe template patterns, and browser-side protections where appropriate.
Should I use htmlentities() or htmlspecialchars()?
Use htmlspecialchars() for most HTML output escaping. It encodes the characters that can affect HTML parsing while keeping normal UTF-8 characters readable.
Use htmlentities() when you specifically need every character with a matching HTML entity to be converted.
Should htmlentities() be used before inserting data into MySQL?
No. Store the original validated value and use a prepared statement for the database query. Apply HTML encoding only when the value is displayed in HTML.
Why does htmlentities() return unexpected or empty output?
The input may contain invalid byte sequences or the declared character encoding may not match the actual data. Use the correct encoding and include ENT_SUBSTITUTE so invalid sequences are replaced predictably.
What does the double_encode parameter do?
When it is true, which is the default, PHP encodes ampersands in existing entities again. When it is false, recognised entities can remain unchanged.
Using false can help with deliberately pre-encoded content, but it should not be used to hide an inconsistent data flow.
Can htmlentities() remove HTML tags?
No. It converts applicable characters into entities. The tags remain in the string, but the browser displays them as text instead of interpreting them as markup.
If the requirement is to remove tags, strip_tags() performs a different operation. It is still not a complete HTML sanitiser for content that permits selected markup.
Conclusion
htmlentities() is useful when an application needs broad HTML entity conversion. A modern call should normally specify UTF-8 and use appropriate flags such as ENT_QUOTES, ENT_SUBSTITUTE, and ENT_HTML5.
The more important lesson is to encode for the destination. Store clean original data, use prepared statements for SQL, and escape values when they enter an HTML context.
For most everyday HTML output, htmlspecialchars() is the better default. Reach for htmlentities() when converting the wider set of supported characters is a deliberate requirement, not simply because its name sounds more thorough.