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.

Laravel Tech Community
Laravel Tech Community
Laravel Tech Community
Preventing XSS Attacks in PHP: Best Practices and Code Examples

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
;
 $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;
}

Method 3 – Global Filtering Function

<?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]);
            }
        }
    }
}
?>

The article concludes by encouraging readers to like and share if they found the content helpful.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

PHPXSSCode ExampleWeb Securityhtmlspecialcharsinput sanitization
Laravel Tech Community
Written by

Laravel Tech Community

Specializing in Laravel development, we continuously publish fresh content and grow alongside the elegant, stable Laravel framework.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.