tagsArray = (array) $tagsArray; $this->attrArray = (array) $attrArray; $this->tagsMethod = $tagsMethod; $this->attrMethod = $attrMethod; $this->xssAuto = $xssAuto; } function process($source) { if (is_array($source)) { foreach($source as $key => $value) if (is_string($value)) $source[$key] = $this->remove($this->decode($value)); return $source; } else if (is_string($source)) { return $this->remove($this->decode($source)); } else return $source; } function remove($source) { $loopCounter=0; while($source != $this->filterTags($source)) { $source = $this->filterTags($source); $loopCounter++; } return $source; } function filterTags($source) { $preTag = NULL; $postTag = $source; $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) break; $tagOpen_nested = strpos($fromTagOpen, '<'); if (($tagOpen_nested !== false) && ($tagOpen_nested < $tagOpen_end)) { $preTag .= substr($postTag, 0, ($tagOpen_nested+1)); $postTag = substr($postTag, ($tagOpen_nested+1)); $tagOpen_start = 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); } if ((!preg_match("/^[a-z][a-z0-9]*$/i",$tagName)) || (!$tagName) || ((in_array(strtolower($tagName), $this->tagBlacklist)) && ($this->xssAuto))) { $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 = in_array(strtolower($tagName), $this->tagsArray); if ((!$tagFound && $this->tagsMethod) || ($tagFound && !$this->tagsMethod)) { if (!$isCloseTag) { $attrSet = $this->filterAttr($attrSet); $preTag .= '<' . $tagName; for ($i = 0; $i < count($attrSet); $i++) $preTag .= ' ' . $attrSet[$i]; if (strpos($fromTagOpen, "'; else $preTag .= ' />'; } else $preTag .= ''; } $postTag = substr($postTag, ($tagLength + 2)); $tagOpen_start = strpos($postTag, '<'); } $preTag .= $postTag; return $preTag; } function filterAttr($attrSet) { $newSet = array(); for ($i = 0; $i xssAuto) && ((in_array(strtolower($attrSubSet[0]), $this->attrBlacklist)) || (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 = in_array(strtolower($attrSubSet[0]), $this->attrArray); if ((!$attrFound && $this->attrMethod) || ($attrFound && !$this->attrMethod)) { if ($attrSubSet[1]) $newSet[] = $attrSubSet[0] . '="' . $attrSubSet[1] . '"'; else if ($attrSubSet[1] == "0") $newSet[] = $attrSubSet[0] . '="0"'; else $newSet[] = $attrSubSet[0] . '="' . $attrSubSet[0] . '"'; } } return $newSet; } function decode($source) { $source = html_entity_decode($source, ENT_QUOTES, "ISO-8859-1"); $source = preg_replace('/&#(\d+);/me',"chr(\\1)", $source); $source = preg_replace('/&#x([a-f0-9]+);/mei',"chr(0x\\1)", $source); return $source; } function safeSQL($source, &$connection) { if (is_array($source)) { foreach($source as $key => $value) if (is_string($value)) $source[$key] = $this->quoteSmart($this->decode($value), $connection); return $source; } else if (is_string($source)) { if (is_string($source)) return $this->quoteSmart($this->decode($source), $connection); } else return $source; } function quoteSmart($source, &$connection) { if (get_magic_quotes_gpc()) $source = stripslashes($source); $source = $this->escapeString($source, $connection); return $source; } function escapeString($string, &$connection) { if (version_compare(phpversion(),"4.3.0", "<")) mysql_escape_string($string); else mysql_real_escape_string($string); return $string; } } ?>