[geeklog-cvs] Geeklog-2/system Filter.php,NONE,1.1

tony at iowaoutdoors.org tony at iowaoutdoors.org
Wed Jan 5 17:36:17 EST 2005


Update of /var/cvs/Geeklog-2/system
In directory www:/tmp/cvs-serv13948

Added Files:
	Filter.php 
Log Message:
Port of Blaine Lang's GL 1.3.x version written in PHP4 over to PHP5.  I took liberty to remove reference to global variables and change it to meet the GL2 coding standards.


--- NEW FILE: Filter.php ---
<?php

/* Reminder: always indent with 4 spaces (no tabs). */
/**
 * Geeklog 2
 *
 * License Details To Be Determined
 *
 */
 
/**
 * This is a basic filter class that allows for quick and effective filtering of potentially
 * harmfull stuff.  This includes SQL injection, XSS vulnerabilties and unwanted HTML.
 *
 * @copyright 2005 Tony Bibbs, Vincent Furia
 * @author Blaine Lang
 * @author Tony Bibbs <tony at geeklog.net>
 *
 */

/**
 * Include the base kses class if not already loaded
 */
require_once 'Kses.php';

class Geeklog_Filter extends Geeklog_Kses {

    protected $string = '';
    protected $permissions = '';
    protected $isNumeric = false;
    protected $logging = false;
    protected $setGlobal = false;
    protected $censorData = false;
	protected $options;
	
	/**
	 * Constructor
	 *
	 * @author Tony Bibbs <tony at geeklog.net>
	 * @access public
	 * @param array $options Array of options to this class. Current supported options are:
	 * 'allowedProtocols' => array()
	 * 'allowedHTML' => array()
	 * 'censorMode' => int (const)
	 * 'censorList' => array(0
	 * 'censorReplace'=> string
	 *
	 */
	public function __construct($options)
	{		
	}
	
    /**
     * Filter or sanitize single parm 
     */
    public function filterparm($parm) 
    {
        global $HTTP_SERVER_VARS;

        $p = $this->parse($parm);

        if ($this->isNumeric ) {
            // Note: PHP's is_numeric() accepts values like 4e4 as numeric
            if (!is_numeric($p) OR (preg_match( '/^([0-9]+)$/', $p) == 0)) {
               $p = 0;
            }
        } else {
            $p = preg_replace( '/\/\*.*/', '', $p );
            $pa = explode( "'", $p );
            $pa = explode( '"', $pa[0] );
            $pa = explode( '`', $pa[0] );
            $pa = explode( ';', $pa[0] );
            $pa = explode( '\\', $pa[0] );
            $p = $pa[0];
        }

        /*if ($this->logging) {
            if (strcmp($p, $parm) != 0)
            {
                COM_errorLog( "Filter applied: >> $parm << filtered to $p [IP {$HTTP_SERVER_VARS['REMOTE_ADDR']}]", 1);
            }
        }*/
        return $p;
    }

    /**
     *  Prepare data for SQL insert and apply filtering 
     *  Supports passing a single parm or array of parms
     */
    public function prepareForDB($data) 
    {
        if (is_array($data)) {
            // loop through array and apply the filters
            foreach ($data as $var) {
                //$return_data[] = addslashes($this->filterHTML($var));
                // Removed addslashes() call because Propel/Creole should handle this in GL2
                $return_data[] = $this->filterHTML($var);
            }
            return $return_data;
        } else {
            $data = $this->filterHTML($data);
            //$data = addslashes($data);
            // Removed addslashes() call because Propel/Creole should handle this in GL2
            return $data;
        }
    }

    public function filterHTML($message) 
    {
        // strip_tags() gets confused by HTML comments ...
        $message = preg_replace( '/<!--.+?-->/', '', $message );

        if (isset($this->allowedProtocols) AND is_array($this->allowedProtocols) 
        	AND (sizeof($this->allowedProtocols) > 0)) {
            $this->protocols($this->allowedProtocols);
        } else {
            $this->protocols(array('http:','https:','ftp:'));
        }

        if (empty($this->permissions) OR !SEC_hasRights($this->permissions) OR
                empty($this->$adminHTML))
        {
            $html = $this->userHTML;
        } else {
            $html = array_merge_recursive($this->userHTML,$this->adminHTML);
        }

        foreach ($html as $tag => $attr) {
            $this->addHTML($tag, $attr);
        }

        $message = $this->parse( $message );
        $message = $this->formatCode($message);
        $message = $this->censor($message);
        return $message;

    }


    /** 
     * Apply filtering to a single parm or array of parms
     * Parms may be in either $_POST or $_GET input parms array
     * If type (GET or POST) is not set then POST is checked first
     * Optionally Parms can be made global
     */
    public function sanitizeParms($vars,$type='')  
    {
      $return_data = array();

      //setup common reference to SuperGlobals depending which array is needed
      if ($type == 'GET' OR $type == 'POST') {
        if ($type =='GET') { 
        	$SG_Array =& $_GET; 
        }
        if ($type =='POST') { 
        	$SG_Array =& $_POST; 
        }

        // loop through SuperGlobal data array and grab out data for allowed fields if found
        foreach ($vars as $key)  {
          if (array_key_exists($key,$SG_Array)) { 
          	$return_data[$key]=$SG_Array[$key]; 
          }
        }

      } else {
        foreach ($vars as $key) {
          if (array_key_exists($key, $_POST)) { 
            $return_data[$key] = $_POST[$key];
          } elseif (array_key_exists($key, $_GET)) { 
            $return_data[$key] = $_GET[$key];
          }
        }
      }

      // loop through $vars array and apply the filter
      foreach ($vars as $value)  {
        $return_data[$value]  = $this->filterparm($return_data[$value]);
      }

      // Optionally set $GLOBALS or return the array
      if ($this->setGlobal) {
          // loop through final data and define all the variables using the $GLOBALS array
          foreach ($return_data as $key=>$value)  {
            $GLOBALS[$key]=$value;
          }
      } else {
         return $return_data;
      }

    }

    public function formatCode($message)  
    {
        // Get rid of any newline characters
        $message = preg_replace("/\n/", '', $message);

        // Replace any $ with $ (HTML equiv)
        $message = str_replace('$', '$', $message);

        // handle [code] ... [/code]
        do {
            $start_pos = strpos( strtolower($message), '[code]');
            if ($start_pos !== false) {
                $end_pos = strpos(strtolower($message), '[/code]');
                if ($end_pos !== false) {
                    $encoded = $this->_handleCode(substr( $message, $start_pos + 6,
                            $end_pos - ( $start_pos + 6 )));
                    $encoded = '<pre><code>' . $encoded . '</code></pre>';
                    $message = substr( $message, 0, $start_pos ) . $encoded
                         . substr( $message, $end_pos + 7 );
                } else {
                	// missing [/code]
                    // Treat the rest of the text as code (so as not to lose any
                    // special characters). However, the calling entity should
                    // better be checking for missing [/code] before calling this
                    // function ...
                    $encoded = $this->handleCode( substr( $message, $start_pos + 6 ));
                    $encoded = '<pre><code>' . $encoded . '</code></pre>';
                    $message = substr( $message, 0, $start_pos ) . $encoded;
                }
            }
        }
        while ($start_pos !== false);

        return $message;

    }

    /**
    * Handles the part within a [code] ... [/code] section, i.e. escapes all
    * special characters.
    *
    * @param   string  $str  the code section to encode
    * @return  string  $str with the special characters encoded
    *
    */
    private function handleCode($str)
    {
        $search  = array('&', '\\', '<', '>', '[', ']');
        $replace = array('&', '\', '<', '>', '[', ']');

        $str = str_replace($search, $replace, $str);

        return $str;
    }


    /**
    * This censors inappropriate content
    *
    * This will replace 'bad words' with something more appropriate
    *
    * @param        string      $message        String to check
    * @return   string  Edited $Message
    *
    */
    public function censor($message)
    {
        $editedMessage = $message;

        if ($this->censorData) {
            if (is_array($this->censorList)) {
                $replacement = $this->censorReplace;

                switch($this->censorMode)
                {
                    case 1: // Exact match
                        $regExPrefix = '(\s*)';
                        $regExSuffix = '(\W*)';
                        break;

                    case 2: // Word beginning
                        $regExPrefix = '(\s*)';
                        $regExSuffix = '(\w*)';
                        break;

                    case 3: // Word fragment
                        $regExPrefix   = '(\w*)';
                        $regExSuffix   = '(\w*)';
                        break;
                }

                for ($i = 0; $i < count($this->censorList); $i++ ) {
                    $editedMessage = eregi_replace($regExPrefix . $this->censorList[$i] . 
                    	$regExSuffix, "\\1$replacement\\2", $editedMessage );
                }
            }
        }

        return $editedMessage;
    }


    public function setPermissions($permissions) 
    {
        $this->permissions = $permissions;
    }

    public function setLogging($state=false) 
    {
        $this->logging = $state;
    }

}

?>



More information about the geeklog-cvs mailing list