Zend - The PHP Company




Security

Add Code


PHP Input Filter  

Type: class
Added by: animachine
Entered: 22/03/2005
Last modified: 03/12/2004
Rating: - (fewer than 3 votes)
Views: 8243
Filter out unwanted PHP / Javascript / HTML tags. This class can filter input of stray or malicious PHP, Javascript or HTML tags and to prevent cross-site scripting (XSS) attacks. It should be used to filter input supplied by the user, such as an HTML code entered in form fields. I have tried to make this class as easy as possible to use. You have control over the filter process unlike other alternatives, and can input a string or an entire array to be cleaned (such as $_POST).


<?php

/** @class: InputFilter;
  * @project: Filter User Input Source;
  * @date: 18-03-2005;
  * @version: 1.1.1_php5;
  * @author: Daniel Morris;
  * @copyright: Daniel Morris;
  * @email: dan@rootcube.com;
  * @license: GNU General Public License (GPL); 
  */
class InputFilter {
    
// class config vars
    
private $tagsArray;       // required
    
private $attrArray;        // default = empty array
    
private $tagsMethod;   // default = 0
    
private $attrMethod;        // default = 0
        
    /** 
      * Constructor for inputFilter class. Only first parameter is required.
      * @access constructor
      * @param Array $tagsArray - list of user-defined tags
      * @param Array $attrArray - list of user-defined attributes
      * @param int $tagsMethod - 0= allow just user-defined, 1= allow all but user-defined
      * @param int $attrMethod - 0= allow just user-defined, 1= allow all but user-defined
      */
    
public function __construct($tagsArray$attrArray = array(), $tagsMethod 0$attrMethod 0) {        
        
$this->tagsArray $tagsArray;
        
$this->attrArray $attrArray;
        
$this->tagsMethod $tagsMethod;
        
$this->attrMethod $attrMethod;
    }
    
    
/** 
      * Method to be called by another php script. 
      * @access public
      * @param Mixed $source - input string/array-of-string to be 'cleaned'
      * @return String $source - 'cleaned' version of input parameter
      */
    
public function process($source) {
        if (
is_array($source))     {                                                                                    // clean all elements in this array
            
for ($i 0$i count($source); $i++)
                if (
is_string($source[$i])) $source[$i] = $this->remove($source[$i]);
            return 
$source;
        } else if (
is_string($source)) return $this->remove($source);                            // clean this string
        
else return $source;                                                                                        // return parameter as given
    
}

    
/** 
      * Internal method to iteratively remove all unwanted tags and attributes
      * @access private
      * @param String $source - input string to be 'cleaned'
      * @return String $source - 'cleaned' version of input parameter
      */
    
private function remove($source) {
        
$loopCounter=0;
        
// provides nested-tag protection
        
while($source != $this->filterTags($source)) {
            
$source $this->filterTags($source);
            
$loopCounter++;
        }
        return 
$source;
    }    
    
/** 
      * Internal method to strip a string of certain tags
      * @access private
      * @param String $source - input string to be 'cleaned'
      * @return String $source - 'cleaned' version of input parameter
      */
    
private function filterTags($source) {
        
// filter pass setup
        
$preTag NULL;
        
$postTag $source;
        
// find initial tag's position
        
$tagOpen_start strpos($source'<');
        
// interate through string until no tags left
        
while($tagOpen_start !== FALSE) {
            
// tag setup
            
$fromTagOpen substr($postTag$tagOpen_start);
            
$tagOpen_end strpos($fromTagOpen'>');
            
$tagOpen_nested = (strpos(substr($fromTagOpen1), '<')+1);
            
$tagOpen_length $tagOpen_end 1;
            
$currentTag substr($fromTagOpen1$tagOpen_length);
            
// iterate through tag finding attribute pairs - setup
            
$tagLeft $currentTag;
            
$attrSet = array();
            
$currentSpace strpos($tagLeft' ');
            
// is end tag
            
if (substr($currentTag01) == "/") {
                
$isCloseTag TRUE;
                list(
$tagName) = explode(' '$currentTag);
                
$tagName substr($tagName1);
            
// is start tag
            
} else {
                
$isCloseTag FALSE;
                list(
$tagName) = explode(' '$currentTag);
            }        
            
            
// this while is needed to support attribute values with spaces in!
            
while ($currentSpace !== FALSE) {
                
$fromSpace substr($tagLeft, ($currentSpace+1));
                
$nextSpace strpos($fromSpace' ');
                
$openQuotes strpos($fromSpace'"');
                
$closeQuotes strpos(substr($fromSpace, ($openQuotes+1)), '"') + $openQuotes 1;
                
// another equals exists
                
if (strpos($fromSpace'=') !== FALSE) {
                    
// opening and closing quotes exists
                    
if (($openQuotes !== FALSE) && (strpos(substr($fromSpace, ($openQuotes+1)), '"') !== FALSE))
                        
$attr substr($fromSpace0, ($closeQuotes+1));
                    
// one or neither exist
                    
else $attr substr($fromSpace0$nextSpace);
                
// no more equals exist
                
} else $attr substr($fromSpace0$nextSpace);
                
// last attr pair
                
if (!$attr$attr $fromSpace;
                
// add to attribute pairs array
                
$attrSet[] = $attr;
                
// next inc
                
$tagLeft substr($fromSpacestrlen($attr));
                
$currentSpace strpos($tagLeft' ');
            }
            
// deals with nexted tags
            
if (($tagOpen_nested $tagOpen_end) && ($fromTagOpen[$tagOpen_nested] == '<')) {
                
$preTag .= substr($postTag0, ($tagOpen_start + ($tagOpen_end $tagOpen_nested) - 1));
                
$postTag substr($fromTagOpen$tagOpen_nested);
                
$tagOpen_start strpos($postTag'<');            
                continue;
            
// doesn't contain nested tag
            
} else $preTag .= substr($postTag0$tagOpen_start);
            
// appears in array specified by user
            
$tagFound in_array(strtolower($tagName), $this->tagsArray);            
            
// remove this tag on condition
            
if ((!$tagFound && $this->tagsMethod) || ($tagFound && !$this->tagsMethod)) {
                
// reconstruct tag with allowed attributes
                
if (!$isCloseTag) {
                    
$attrSet $this->filterAttr($attrSet);
                    
$preTag .= '<' $tagName;
                    for (
$i 0$i count($attrSet); $i++)
                        
$preTag .= ' ' $attrSet[$i];
                    
// reformat single tags to XHTML
                    
if (strpos($fromTagOpen"</" $tagName))    $preTag .= '>';
                    else                                                                
$preTag .= ' />';
                
// just the tagname
                
} else $preTag .= '</' $tagName '>';
            }
            
// find next tag's start
            
$postTag substr($postTag, ($tagOpen_start $tagOpen_length 2));
            
$tagOpen_start strpos($postTag'<');            
        }
        
// append any code after end of tags
        
$preTag .= $postTag;
        return 
$preTag;
    }

    
/** 
      * Internal method to strip a tag of certain attributes
      * @access private
      * @param Array $attrSet
      * @return Array $newSet
      */
    
private function filterAttr($attrSet) {
        
$newSet = array();
        
// has attributes
        
for ($i 0$i <count($attrSet); $i++) {
            
$attrSubSet explode('='$attrSet[$i]);
            list(
$attrSubSet[0]) = explode(' '$attrSubSet[0]);
            
$attrFound in_array(strtolower($attrSubSet[0]), $this->attrArray);
            
// keep this attr on condition
            
if ((!$attrFound && $this->attrMethod) || ($attrFound && !$this->attrMethod)) {
                
// attr has value
                
if ($attrSubSet[1]) $newSet[] = $attrSubSet[0] . '=' $attrSubSet[1];
                
// reformat single attributes to XHTML
                
else $newSet[] = $attrSubSet[0] . '="' $attrSubSet[0] . '"';
            }    
        }
        return 
$newSet;
    }
}

?>


Usage Example


See the example


Rate This Script





Search



This Category All Categories