Source for file XSSFilter.class.php

Documentation is available at XSSFilter.class.php

  1. <?php
  2. /**
  3.  * Simple configurable data filter.
  4.  * Note that it is not perfect but should provide a good starting point for
  5.  * filtering input.
  6.  *
  7.  * LICENSE: LGPLv3+
  8.  *
  9.  * Example:
  10.  * <code>
  11.  * $f = new XSSFilter(True, True, False, False, True);
  12.  * $safer = $f->filter($_GET);
  13.  *
  14.  * $f = new XSSFilter(True, True, False, False, True);
  15.  * $result = $f->filter($input);
  16.  * if ($result->changes) {
  17.  *     print('Your input has been modified');
  18.  * }
  19.  * return $result->data;
  20.  * </code>
  21.  *
  22.  * @author Steve 'Ashcrow' Milner
  23.  * @author Lisa Lu
  24.  * @category security
  25.  * @license LGPLv3+
  26.  * @link http://bitbucket.org/ashcrow/php-xssfilter
  27.  * @package XSSFilter
  28.  * @version 1.0.0
  29.  */
  30.  
  31.  
  32. /**
  33.  * Array wrapper for safe arrays.
  34.  */
  35. class ExtendedResponseArray extends ArrayObject {
  36.  
  37.     /**
  38.      * Class variable noting if the data had been changed.
  39.      * @var bool 
  40.      */
  41.     private $changes;
  42.  
  43.     /**
  44.      * Extended response of filtered array data.
  45.      * @param data array input array which is already safe.
  46.      * @param changes bool if changes had to be made.
  47.      */
  48.     function __construct(Array $data$changes)
  49.     {
  50.         $this->changes $changes;
  51.         foreach($data as $key => $value{
  52.             $this->offsetSet($key$value);
  53.         }
  54.     }
  55.  
  56.     /**
  57.      * Converts the instance to a String.
  58.      */
  59.     function __toString()
  60.     {
  61.         return 'Array';
  62.     }
  63.  
  64.     /**
  65.      * Used to return data requested.
  66.      * @param property string requested attribute.
  67.      */
  68.     function __get($property)
  69.     {
  70.         if ($property == 'changes'{
  71.             return $this->changes;
  72.         elseif ($property == 'data'{
  73.             return $this->getArrayCopy();
  74.         }
  75.     }
  76. }
  77.  
  78.  
  79. /**
  80.  * String wrapper for safer strings.
  81.  */
  82.  
  83.     /**
  84.      * Class variable noting if the data had been changed.
  85.      * @var bool 
  86.      */
  87.     private $changes;
  88.     /**
  89.      * Class variable holding the data directly.
  90.      * @var string 
  91.      */
  92.     private $data;
  93.  
  94.     /**
  95.      * Extended response of filtered string data.
  96.      * @param string data input array which is already safe.
  97.      * @param bool change if changes had to be made.
  98.      */
  99.     function __construct($data$changes)
  100.     {
  101.         $this->data $data;
  102.         $this->changes $changes;
  103.     }
  104.  
  105.     /**
  106.      * Converts instance to a String.
  107.      * @return string 
  108.      */
  109.     function __toString()
  110.     {
  111.         return (string) $this->data;
  112.     }
  113.  
  114.     /**
  115.      * Used to return data requested.
  116.      * @param string property requested attribute.
  117.      * @return string 
  118.      */
  119.     function __get($property)
  120.     {
  121.         if ($property == 'changes'{
  122.             return $this->changes;
  123.         elseif ($property == 'data'{
  124.             return $this->__toString();
  125.         }
  126.     }
  127. }
  128.  
  129.  
  130. /**
  131.  * Configurable XSSFilter for use by developers.
  132.  */
  133. class XSSFilter {
  134.  
  135.     /**
  136.      * Class variable noting if html should be removed.
  137.      * @var bool 
  138.      */
  139.     public $remove_html;
  140.     /**
  141.      * Class variable noting if javascript should be removed.
  142.      * @var bool 
  143.      */
  144.     public $remove_javascript;
  145.     /**
  146.      * Class variable noting if html should be escaped.
  147.      * @var bool 
  148.      */
  149.     public $escape_html;
  150.     /**
  151.      * Class variable noting if html should be urlencoded.
  152.      * @var bool 
  153.      */
  154.     public $urlencode_html;
  155.     /**
  156.      * Class variable noting if the return value should be a structure
  157.      * which includes the scrubbed data and a boolean noting if the data
  158.      * was modified or not.
  159.      * A return of False means no changes, True means changes.
  160.      * @var bool 
  161.      */
  162.     public $extended_return;
  163.  
  164.  
  165.     /**
  166.      * A filter object that attempts to strip out evil data.
  167.      * @param bool remove_html if html should be removed.
  168.      * @param bool remove_javascript if javascript should be removed.
  169.      * @param bool escape_html if html should be escaped.
  170.      * @param bool urlencode_html if html should be urlencoded.
  171.      * @param bool extended_return if an extended object should be used.
  172.      */
  173.     function __construct($remove_html=False$remove_javascript=False,
  174.         $escape_html=True$urlencode_html=False$extended_return=False{
  175.         $this->remove_html = $remove_html;
  176.         $this->remove_javascript = $remove_javascript;
  177.         $this->escape_html = $escape_html;
  178.         $this->urlencode_html = $urlencode_html;
  179.         $this->extended_return = $extended_return;
  180.     }
  181.  
  182.     /**
  183.      * Forward method for filtering input.
  184.      * @param string data the data to filter.
  185.      */
  186.     function filter($data{
  187.         if (is_array($data)) {
  188.             return $this->filter_array($data);
  189.         }
  190.         return $this->filter_string($data);
  191.     }
  192.  
  193.     /**
  194.      * Filters a single input item
  195.      * @param string data the data to filter.
  196.      * @return string a safer string.
  197.      */
  198.     function filter_string($data{
  199.         $original_data $data;
  200.         if ($this->remove_javascript{
  201.             $data preg_replace(
  202.                 "@<script[^>]*?>.*?</script[^>]*?>@si"""$data);
  203.         }
  204.         if ($this->remove_html{
  205.             // The regex should catch it all, but can't hurt to double check it
  206.             $data strip_tags(preg_replace(
  207.                 "@<.*[^>]*?>.*?</.*>@si"""$data));
  208.         }
  209.         if ($this->escape_html{
  210.             $data htmlspecialchars($data);
  211.         }
  212.         if ($this->urlencode_html{
  213.             $data urlencode($data);
  214.         }
  215.         if ($this->extended_return{
  216.             return new ExtendedResponseString(
  217.                 $data$original_data != $data True False);
  218.         }
  219.         return $data;
  220.     }
  221.  
  222.     /**
  223.      * Filters a single level array.
  224.      * @param array data the data filled array to filter.
  225.      * @return array a safer array.
  226.      */
  227.     function filter_array($data{
  228.         $safe array();
  229.         $changes False;
  230.         foreach ($data as $key => $value{
  231.             $result $this->filter($value);
  232.             if ($this->extended_return{
  233.                 $safe[$key$result->data;
  234.                 $result->changes and $changes True;
  235.             else {
  236.                 $safe[$key$result;
  237.             }
  238.         }
  239.         if ($this->extended_return{
  240.             return new ExtendedResponseArray($safe$changes);
  241.         }
  242.         return $safe;
  243.     }
  244. }
  245. ?>

Documentation generated on Tue, 12 Oct 2010 16:47:11 -0400 by phpDocumentor 1.4.3