Файл: classes/filter.class.php
Строк: 173
<?php
defined('_VALID') or die('Restricted Access!');
define('TIDY_CLEAN', false);
class VFilter
{
public function get( $var, $type='STRING', $method='POST')
{
$method = strtoupper($method);
$type = strtoupper($type);
switch ( $method ) {
case 'POST':
$input = $_POST;
break;
case 'GET':
$input = $_GET;
break;
case 'COOKIE':
$input = $_COOKIE;
break;
case 'REQUEST':
$input = $_REQUEST;
break;
case 'SERVER':
$input = $_SERVER;
break;
default:
trigger_error('Invalid filter method!', E_USER_ERROR);
}
$source = ( isset($input[$var]) ) ? trim($input[$var]) : NULL;
if ( !$source ) {
return $source;
}
return $this->xss_filter($source);
}
function xss_filter($content){
require_once('htmlpurifier/HTMLPurifier.auto.php');
$conf_Purifier = HTMLPurifier_Config::createDefault();
$conf_Purifier->set('HTML.Allowed', 'p,b,strong,i');
$sanitiser = new HTMLPurifier($conf_Purifier);
$output = $sanitiser->purify($content);
return $output;
}
private function _clean( $source, $type )
{
$source = $this->_decode($source);
switch ( $type ) {
case 'INT':
case 'INTEGER':
$source = intval($source);
break;
case 'FLOAT':
case 'DOUBLE':
$source = floatval($source);
break;
case 'BOOL':
case 'BOOLEAN':
$source = (bool) $source;
case 'STRING':
$source = $this->process($source);
break;
case 'RAW':
return $source;
default:
$source = $this->process($source);
break;
}
return $source;
}
public function process( $source, $allowedTags=array(), $allowedAttr=array() )
{
if ( is_array($source) ) {
foreach ( $source as $key => $value ) {
if ( is_string($value) ) {
$source[$key] = $this->_filter($value, $allowedTags, $allowedAttr);
}
}
return $source;
} elseif ( is_string($source) ) {
return $this->_filterTags($source, $allowedTags, $allowedAttr);
} else {
return $source;
}
}
private function _filter( $source, $allowedTags, $allowedAttr )
{
$loopCounter = 0;
while ( $source != $this->_filterTags($source, $allowedTags, $allowedAttr) ) {
$source = $this->_filterTags($source, $allowedTags, $allowedAttr);
$loopCounter++;
}
return $source;
}
private function _tidyClean( $source )
{
if (TIDY_CLEAN) {
if ( function_exists('tidy_parse_string') ) {
$source = tidy_parse_string($source);
tidy_clean_repair($source);
}
}
return trim($source);
}
private function _filterTags( $source, $allowedTags, $allowedAttr )
{
$source = $this->_tidyClean($source);
$tagBlacklist = array('applet', 'body', 'bgsound', 'base', 'basefont', 'embed', 'frame', 'frameset', 'head', 'html', 'id', 'iframe', 'ilayer', 'layer', 'link', 'meta', 'name', 'object', 'script', 'style', 'title', 'xml');
$preTag = NULL;
$postTag = $source;
$currentSpace = false;
$tagOpen_start = strpos($source, '<');
while ( $tagOpen_start !== false ) {
$preTag .= substr($postTag, 0, $tagOpen_start);
$postTag = substr($postTag, $tagOpen_start);
$fromTagOpen = substr($postTag, 1);
$tagOpen_end = strpos($fromTagOpen, '>');
if ( $tagOpen_end === false ) {
$postTag = substr($postTag, $tagOpen_start +1);
$tagOpen_start = strpos($postTag, '<');
continue;
}
$tagOpen_nested = strpos($fromTagOpen, '<');
if ( ($tagOpen_nested !== false) && ($tagOpen_nested < $tagOpen_start) ) {
$preTag .= substr($postTag, 0, ($tagOpen_nested+1));
$postTag = substr($postTag, ($tagOpen_nested+1));
$tagOpen_star = strpos($postTag, '<');
continue;
}
$tagOpen_nested = (strpos($fromTagOpen, '<') + $tagOpen_start + 1);
$currentTag = substr($fromTagOpen, 0, $tagOpen_end);
$tagLength = strlen($currentTag);
if ( !$tagOpen_end ) {
$preTag .= $postTag;
$tagOpen_start = strpos($postTag, '<');
}
$tagLeft = $currentTag;
$attrSet = array();
$currentSpace = strpos($tagLeft, ' ');
if ( substr($currentTag, 0, 1) == '/' ) {
$isCloseTag = TRUE;
list($tagName) = explode(' ', $currentTag);
$tagName = substr($tagName, 1);
} else {
$isCloseTag = FALSE;
list($tagName) = explode(' ', $currentTag);
}
$tag_blacklisted = false;
$tag_name = strtolower($tagName);
foreach ( $tagBlacklist as $key => $value ) {
if ( $tag_name == $value ) {
$tag_blacklisted = true;
break;
}
}
if ( (!preg_match("/^[a-z][a-z0-9]*$/i",$tagName)) || (!$tagName) || $tag_blacklisted ) {
$postTag = substr($postTag, ($tagLength + 2));
$tagOpen_start = strpos($postTag, '<');
continue;
}
while ( $currentSpace !== FALSE ) {
$fromSpace = substr($tagLeft, ($currentSpace+1));
$nextSpace = strpos($fromSpace, ' ');
$openQuotes = strpos($fromSpace, '"');
$closeQuotes = strpos(substr($fromSpace, ($openQuotes+1)), '"') + $openQuotes + 1;
if ( strpos($fromSpace, '=' ) !== FALSE) {
if ( ($openQuotes !== FALSE) && (strpos(substr($fromSpace, ($openQuotes+1)), '"') !== FALSE) ) {
$attr = substr($fromSpace, 0, ($closeQuotes+1));
} else {
$attr = substr($fromSpace, 0, $nextSpace);
}
} else {
$attr = substr($fromSpace, 0, $nextSpace);
}
if ( !$attr ) {
$attr = $fromSpace;
}
$attrSet[] = $attr;
$tagLeft = substr($fromSpace, strlen($attr));
$currentSpace = strpos($tagLeft, ' ');
}
$tagFound = false;
$tag_name = strtolower($tag_name);
foreach ( $allowedTags as $key => $value ) {
if ( $tag_name == $value ) {
$tagFound = true;
break;
}
}
if ( $tagFound ) {
if ( !$isCloseTag ) {
$attrSet = $this->_filterAttr($attrSet, $allowedAttr);
$preTag .= '<' . $tagName;
for ( $i = 0; $i < count($attrSet); $i++ ) {
$preTag .= ' ' . $attrSet[$i];
}
if ( strpos($fromTagOpen, '</' . $tagName) ) {
$preTag .= '>';
} else {
$preTag .= ' />';
}
} else {
$preTag .= '</' . $tagName . '>';
}
}
$postTag = substr($postTag, ($tagLength + 2));
$tagOpen_start = strpos($postTag, '<');
}
$preTag .= $postTag;
$source = $this->_tidyClean($preTag);
return $preTag;
}
private function _filterAttr( $attrSet, $allowedAttr = array() )
{
$attrBlacklist = array('action', 'background', 'codebase', 'dynsrc', 'lowsrc');
$newSet = array();
for ( $i = 0; $i <count($attrSet); $i++ ) {
if ( !$attrSet[$i] ) {
continue;
}
$attrSubSet = explode('=', trim($attrSet[$i]));
list($attrSubSet['0']) = explode(' ', $attrSubSet['0']);
$attr_blacklisted = false;
$attr = strtolower($attrSubSet['0']);
foreach ( $attrBlacklist as $key => $value ) {
if ( $attr == $value ) {
$attr_blacklisted = true;
break;
}
}
if ( !preg_match("/^[a-z]*$/i", $attrSubSet['0']) || $attr_blacklisted || substr($attrSubSet['0'], 0, 2) == 'on' ) {
continue;
}
if ( $attrSubSet['1'] ) {
$attrSubSet['1'] = str_replace('&#', '', $attrSubSet['1']);
$attrSubSet['1'] = preg_replace('/s+/', '', $attrSubSet['1']);
$attrSubSet['1'] = str_replace('"', '', $attrSubSet['1']);
if ((substr($attrSubSet['1'], 0, 1) == "'") && (substr($attrSubSet['1'], (strlen($attrSubSet['1']) - 1), 1) == "'")) {
$attrSubSet['1'] = substr($attrSubSet['1'], 1, (strlen($attrSubSet['1']) - 2));
}
$attrSubSet[1] = stripslashes($attrSubSet['1']);
}
if ( ((strpos(strtolower($attrSubSet['1']), 'expression') !== false) && (strtolower($attrSubSet['0']) == 'style')) ||
(strpos(strtolower($attrSubSet[1]), 'javascript:') !== false) ||
(strpos(strtolower($attrSubSet[1]), 'behaviour:') !== false) ||
(strpos(strtolower($attrSubSet[1]), 'vbscript:') !== false) ||
(strpos(strtolower($attrSubSet[1]), 'mocha:') !== false) ||
(strpos(strtolower($attrSubSet[1]), 'livescript:') !== false) ) {
continue;
}
$attrFound = false;
foreach ( $allowedAttr as $key => $value ) {
if ( $attr == $value ) {
$attrFound = true;
break;
}
}
if ( $attrFound ) {
if ( $attrSubSet['1'] ) {
$newSet[] = $attrSubSet['0'] . '="' . $attrSubSet['1'] . '"';
} elseif ( $attrSubSet['1'] == '0' ) {
$newSet[] = $attrSubSet['0'] . '="0"';
} else {
$newSet[] = $attrSubSet['0'] . '="' . $attrSubSet['0'] . '"';
}
}
}
return $newSet;
}
private function _decode( $source )
{
$source = html_entity_decode($source, ENT_QUOTES, 'UTF-8');
$source = preg_replace('/&#(d+);/me',"chr(\1)", $source);
$source = preg_replace('/&#x([a-f0-9]+);/mei',"chr(0x\1)", $source);
return $source;
}
}
?>