I'm a complete neophyte when it comes to PHP, so I suspect this question has a simple answer that I'm just not able to find yet.
I'm using PHP Code Sniffer with WordPress Coding Standards to put together a basic wordpress plugin. A bunch of tutorial code I've encountered encouraged echoing content along the lines of:
echo $before_widget . $before_title . $title . $after_title;
Which works fine, but which PHP Code Sniffer raises a warning before each variable echoed of expected next thing to be an escaping function not $VariableName
.Intuitively, I don't want to escape these variables - HTML contained in them should render properly, and it's hard to see how an attacker could have changed the instance $args
object where $before_widget
etc. come from to introduce XSS vulnerabilities. But as I said, I'm new to PHP, WordPress, etc. and I'm not aware of what will have had access to these variables in full before I get them.
Long story short: Given I want the HTML to be rendered as HTML (I do not want to escape it), how should I either prepare them such that I am protected from any XSS issues I'm not aware of, or inform PHP Code Sniffer that these are not user input, and therefore are safe?
Ok, the answer it looks like I was after was to make use of the wp_kses()
function on the output prior to printing it. According to the documentation, this
makes sure that only the allowed HTML element names, attribute names and attribute values plus only sane HTML entities will occur in $string
It also makes PHP Code Sniffer stop moaning about echoing a sting without any escaping taking place.
Without digging into the implementation, I can't say for sure that this covers all bases (sane HTML entities could be interpreted in a number of ways, after all), but intuitively, it feels like the kind of thing I might want to do to code that's come in from - albeit trusted - external sources in case they, you know, take down the webpage due to malforming.
Final code ended up looking like:
$html = '';
$html .= $args['before_widget'];
$html .= $args['before_title'];
$html .= esc_html( $title );
$html .= $args['after_title'];
$allowed_tags = wp_kses_allowed_html( 'post' );
echo wp_kses( $html, $allowed_tags );
As a note, it's worth noting that in my travels identifying kses
, I found a number of places suggesting it's a pretty slow function to pass content through. For the purpose, it seems right, but I'll listen if anyone knows a lighter weight approach.