Preventing XSS Attacks in PHP: Best Practices and Code Examples
This article explains various methods to prevent XSS injection in PHP, covering the limitations of built‑in filters, proper use of htmlspecialchars and htmlentities, replacement techniques, and provides comprehensive PHP functions with code examples for sanitizing user input and removing malicious scripts.
Websites can be attacked via XSS in many ways, and relying solely on PHP built‑in filtering functions such as filter_var, mysql_real_escape_string, htmlentities, htmlspecialchars, or strip_tags does not guarantee safety.
To prevent XSS, the article suggests treating all user input as potentially malicious, ensuring type consistency in weakly‑typed languages, using thorough regular expressions, employing strip_tags and htmlspecialchars, not trusting external JavaScript, paying special attention to quote filtering, and removing unnecessary HTML comments.
Method 1 – Using htmlspecialchars
Use htmlspecialchars($string, ENT_QUOTES) to encode both single and double quotes; ENT_NOQUOTES can be used when no quoting is needed. The article advises preferring htmlspecialchars over htmlentities for Chinese text because htmlentities also converts unrecognizable characters.
All output functions such as echo or print should be filtered with htmlspecialchars (or htmlentities with appropriate charset) before rendering.
Method 2 – Replacement Technique
function xss_clean($data){
// Fix &entity\n;
$data=str_replace(array('&','<','>'),array('&','<','>'),$data);
$data=preg_replace('/(&#*\w+)[\x00-\x20]+;/u','$1;',$data);
$data=preg_replace('/(&#x*[0-9A-F]+);*/iu','$1;',$data);
$data=html_entity_decode($data,ENT_COMPAT,'UTF-8');
// Remove any attribute starting with "on" or xmlns
$data=preg_replace('#(<[^>]+?[\x00-\x20"\'\])(?:on|xmlns)[^>]*+>#iu','$1>',$data);
// Remove javascript: and vbscript: protocols
$data=preg_replace('#([a-z]*)[\x00-\x20]*=([`\'\"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu','$1=$2nojavascript...',$data);
$data=preg_replace('#([a-z]*)[\x00-\x20]*=([\'\"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu','$1=$2novbscript...',$data);
$data=preg_replace('#([a-z]*)[\x00-\x20]*=([\'\"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u','$1=$2nomozbinding...',$data);
// Remove IE expression() style
$data=preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'\"]*.*?expression[\x00-\x20]*\([^>]*+>#i','$1>',$data);
$data=preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'\"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i','$1>',$data);
$data=preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'\"]*.*?script[\x00-\x20]*:*[^>]*+>#iu','$1>',$data);
// Remove namespaced elements
$data=preg_replace('#</?\w+:\w[^>]*+>#i','',$data);
do{
$old_data=$data;
$data=preg_replace('#</?(applet|base|gsound|link|embed|frame|frameset|iframe|layer|link|meta|object|script|style|title|xml)[^>]*+>#i','',$data);
}while($old_data!==$data);
return $data;
}
</code>
<p><strong>Method 3 – Global Filtering Function</strong></p>
<code>
<?php
// PHP universal filter for injection and XSS
$_GET && SafeFilter($_GET);
$_POST && SafeFilter($_POST);
$_COOKIE && SafeFilter($_COOKIE);
function SafeFilter(&$arr){
$ra = array(
'/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/',
'/script/', '/javascript/', '/vbscript/', '/expression/', '/applet/', '/meta/', '/xml/',
'/blink/', '/link/', '/style/', '/embed/', '/object/', '/frame/', '/layer/', '/title/',
'/bgsound/', '/base/', '/onload/', '/onunload/', '/onchange/', '/onsubmit/', '/onreset/',
'/onselect/', '/onblur/', '/onfocus/', '/onabort/', '/onkeydown/', '/onkeypress/', '/onkeyup/',
'/onclick/', '/ondblclick/', '/onmousedown/', '/onmousemove/', '/onmouseout/', '/onmouseover/',
'/onmouseup/', '/onunload/'
);
if(is_array($arr)){
foreach($arr as $key=>$value){
if(!is_array($value)){
if(!get_magic_quotes_gpc()){
$value = addslashes($value);
}
$value = preg_replace($ra,'',$value);
$arr[$key] = htmlentities(strip_tags($value));
}else{
SafeFilter($arr[$key]);
}
}
}
}
?>
</code>
<p>The article concludes by encouraging readers to like and share if they found the content helpful.</p>Laravel Tech Community
Specializing in Laravel development, we continuously publish fresh content and grow alongside the elegant, stable Laravel framework.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.