Here's the combination of constants you're looking for.
$escaped_string = htmlspecialchars($string, ENT_QUOTES & ~ENT_COMPAT, $encoding);
This will escape & ' < >
, but leaves "
alone. ENT_QUOTES & ~ENT_COMPAT
is bit manipulation language meaning "both quotes, minus the double quotes".
This works because of how these constants are defined. php-src/ext/standard/html.h
#define ENT_HTML_QUOTE_NONE 0
#define ENT_HTML_QUOTE_SINGLE 1
#define ENT_HTML_QUOTE_DOUBLE 2
#define ENT_COMPAT ENT_HTML_QUOTE_DOUBLE
#define ENT_QUOTES (ENT_HTML_QUOTE_DOUBLE | ENT_HTML_QUOTE_SINGLE)
#define ENT_NOQUOTES ENT_HTML_QUOTE_NONE
Why would you ever want to escape single quotes, but not double quotes? Well, the inverse of the reason you'd escape double quotes, but not single quotes: because you've got a string with lots of "
double quotes and only a few '
single quotes, so you'd like to stick it in a '
-delimited string.
An example:
<div data-myobject='<?= htmlspecialchars(json_encode($myobject), ENT_QUOTES & ~ENT_COMPAT, 'UTF-8') ?>'
json_encode()
creates lots of double quotes, so it makes sense to stick the result in a single-quote delimited attribute, and leave the double quotes unescaped.