-
Notifications
You must be signed in to change notification settings - Fork 1
Context HTML Attribute
Use when the value lands inside an HTML attribute:
<span title="HERE">,<a href="HERE">,<input value=HERE>.
escHtmlAttr() is strict by design. It whitelists [A-Za-z0-9,.\-_] — every other character is rewritten as an HTML entity. The output is therefore safe inside quoted, single-quoted and unquoted attribute values.
Three rules drive the output:
-
C0 controls (
U+0000–U+001F) except tab/LF/CR →�(the Unicode replacement character). -
C1 controls (
U+007F–U+009F) →�. This check is performed on the decoded code point, so it catches the multibyte UTF-8 form (\xC2\x80…\xC2\x9F) too. -
Everything else outside the whitelist → named entity if one exists (
",&,<,>), otherwise numeric reference (&#xHH;for ≤ 255,&#xHHHH;for BMP, full hex for supplementary plane).
public function escHtmlAttr(string $str): string;Or via the facade:
Esc::esc(string $str, 'attr', ?string $encoding = null): string;| Throws | When |
|---|---|
InvalidUtf8Exception |
$str is not valid UTF-8 (after any encoding conversion). |
EncodingConversionException |
iconv / mbstring fail during UTF-8 conversion. |
Both extend EscaperException.
Esc::esc('plain', 'attr'); // plain
Esc::esc('abc,XYZ.-_0123', 'attr'); // abc,XYZ.-_0123Esc::esc('with space', 'attr');
// with space
Esc::esc('" or 1=1', 'attr');
// " or 1=1
Esc::esc('faketitle onmouseover=alert(1);', 'attr');
// faketitle onmouseover=alert(1);$untrusted = 'faketitle onmouseover=alert(1);';
echo '<span title=' . Esc::esc($untrusted, 'attr') . '>hello</span>';
// <span title=faketitle onmouseover=alert(1);>hello</span>The browser sees a single attribute value (the encoded space ends the value parse), not an extra onmouseover handler.
The four characters in the named-entity map use the shorter form:
Esc::esc('"', 'attr'); // "
Esc::esc('&', 'attr'); // &
Esc::esc('<', 'attr'); // <
Esc::esc('>', 'attr'); // >Esc::esc('ş', 'attr'); // ş
Esc::esc('🚀', 'attr'); // 🚀Esc::esc("\x00", 'attr'); // �
Esc::esc("\x1B", 'attr'); // �
Esc::esc("\x7F", 'attr'); // �
Esc::esc("\xC2\x80", 'attr'); // � ← U+0080 in proper UTF-8
Esc::esc("\xC2\x9F", 'attr'); // � ← U+009F in proper UTF-8Tab / LF / CR are explicitly exempted (they are valid in HTML):
Esc::esc("\t", 'attr'); // 	
Esc::esc("\n", 'attr'); // 

Esc::esc("\r", 'attr'); // 
U+00A0 (NO-BREAK SPACE) sits one code point above the C1 range and is escaped as a normal character, not replaced:
Esc::esc("\xC2\xA0", 'attr'); //  Esc::esc('', 'attr'); // ''
Esc::esc('12345', 'attr'); // 12345Those inputs are already attribute-safe; the matcher is skipped entirely.
| Location | Why | Use instead |
|---|---|---|
href="", src="", action=""
|
escHtmlAttr only protects the attribute delimiters. javascript: survives. |
escUrl + scheme whitelist |
style="..." |
The attribute is safe, but its content is CSS. |
escCss for the inner value |
onclick="..." and other on*
|
The attribute is safe, but its content is JavaScript. |
escJs for the inner |
Bare <script> body |
Wrong context entirely — entities aren't decoded in scripts. | escJs |
Even when the configured output encoding is, say, windows-1252, the matcher needs to address individual code points to apply the C0/C1 control-replacement and named-entity rules. The pipeline is:
[input in $encoding]
↓ iconv/mbstring
[input in UTF-8]
↓ preg_replace_callback with the matcher
[escaped in UTF-8]
↓ iconv/mbstring
[output in $encoding]
If iconv/mbstring fails at either end, EncodingConversionException is raised. If the converted input is not well-formed UTF-8, InvalidUtf8Exception is raised. See Encodings and Exceptions.
- HTML body context
- JavaScript context — for inline event handlers
- URL context — for href/src
- Security Notes
- API Reference →
escHtmlAttr
Getting Started
Entry Points
Output Contexts
Reference
Production
Migration & Help