Source code for file /joomla/filter/input.php
Documentation is available at input.php
* @version $Id: functions.php 4277 2006-07-19 20:35:35Z friesengeist $
* @package Joomla.Framework
* @copyright Copyright (C) 2005 - 2007 Open Source Matters. All rights reserved.
* @license GNU/GPL, see LICENSE.php
* Joomla! is free software. This version may have been modified pursuant to the
* GNU General Public License, and as distributed it includes or is derivative
* of works licensed under the GNU General Public License or other free or open
* source software licenses. See COPYRIGHT.php for copyright notices and
// Check to ensure this file is within the rest of the framework
* JInputFilter is a class for filtering input from any data source
* Original Contributors: Gianpaolo Racca, Ghislain Picard, Marco Wandschneider, Chris Tobin and Andrew Eddie.
* @package Joomla.Framework
var $tagBlacklist =
array ('applet', 'body', 'bgsound', 'base', 'basefont', 'embed', 'frame', 'frameset', 'head', 'html', 'id', 'iframe', 'ilayer', 'layer', 'link', 'meta', 'name', 'object', 'script', 'style', 'title', 'xml');
var $attrBlacklist =
array ('action', 'background', 'codebase', 'dynsrc', 'lowsrc'); // also will strip ALL event handlers
* Constructor for inputFilter class. Only first parameter is required.
* @param array $tagsArray list of user-defined tags
* @param array $attrArray list of user-defined attributes
* @param int $tagsMethod WhiteList method = 0, BlackList method = 1
* @param int $attrMethod WhiteList method = 0, BlackList method = 1
* @param int $xssAuto Only auto clean essentials = 0, Allow clean blacklisted tags/attr = 1
function __construct($tagsArray =
array(), $attrArray =
array(), $tagsMethod =
0, $attrMethod =
0, $xssAuto =
1)
// Make sure user defined arrays are in lowercase
$tagsArray =
array_map('strtolower', (array)
$tagsArray);
$attrArray =
array_map('strtolower', (array)
$attrArray);
// Assign member variables
* Returns a reference to an input filter object, only creating it if it doesn't already exist.
* This method must be invoked as:
* <pre> $filter = & JInputFilter::getInstance();</pre>
* @param array $tagsArray list of user-defined tags
* @param array $attrArray list of user-defined attributes
* @param int $tagsMethod WhiteList method = 0, BlackList method = 1
* @param int $attrMethod WhiteList method = 0, BlackList method = 1
* @param int $xssAuto Only auto clean essentials = 0, Allow clean blacklisted tags/attr = 1
* @return object The JInputFilter object.
function & getInstance($tagsArray =
array(), $attrArray =
array(), $tagsMethod =
0, $attrMethod =
0, $xssAuto =
1)
$sig =
md5(serialize(array($tagsArray,$attrArray,$tagsMethod,$attrMethod,$xssAuto)));
if (!isset
($instances)) {
if (empty ($instances[$sig])) {
$instances[$sig] =
new JInputFilter($tagsArray, $attrArray, $tagsMethod, $attrMethod, $xssAuto);
* Method to be called by another php script. Processes for XSS and
* @param mixed $source Input string/array-of-string to be 'cleaned'
* @param string $type Return type for the variable (INT, FLOAT, WORD, BOOLEAN, STRING)
* @return mixed 'Cleaned' version of input parameter
function clean($source, $type=
'string')
// Handle the type constraint
// Only use the first integer value
$result =
@ (int)
$matches[0];
// Only use the first floating point value
@ preg_match('/-?[0-9]+(\.[0-9]+)?/', $source, $matches);
$result =
@ (float)
$matches[0];
$result = (bool)
$source;
// Are we dealing with an array?
foreach ($source as $key =>
$value)
// filter element for XSS and other 'bad' code etc.
if (is_string($source) &&
!empty ($source)) {
// filter source for XSS and other 'bad' code etc.
// Not an array or string.. return the passed parameter
* Function to determine if contents of an attribute is safe
* @param array $attrSubSet A 2 element array for attributes name,value
* @return boolean True if bad code is detected
return (((strpos($attrSubSet[1], 'expression') !==
false) &&
($attrSubSet[0]) ==
'style') ||
(strpos($attrSubSet[1], 'javascript:') !==
false) ||
(strpos($attrSubSet[1], 'behaviour:') !==
false) ||
(strpos($attrSubSet[1], 'vbscript:') !==
false) ||
(strpos($attrSubSet[1], 'mocha:') !==
false) ||
(strpos($attrSubSet[1], 'livescript:') !==
false));
* Internal method to iteratively remove all unwanted tags and attributes
* @param string $source Input string to be 'cleaned'
* @return string 'Cleaned' version of input parameter
// Iteration provides nested tag protection
* Internal method to strip a string of certain tags
* @param string $source Input string to be 'cleaned'
* @return string 'Cleaned' version of input parameter
* In the beginning we don't really have a tag, so everything is
// Is there a tag? If so it will certainly start with a '<'
$tagOpen_start =
strpos($source, '<');
while ($tagOpen_start !==
false)
// Get some information about the tag we are processing
$preTag .=
substr($postTag, 0, $tagOpen_start);
$postTag =
substr($postTag, $tagOpen_start);
$fromTagOpen =
substr($postTag, 1);
$tagOpen_end =
strpos($fromTagOpen, '>');
// Let's catch any non-terminated tags and skip over them
if ($tagOpen_end ===
false) {
$postTag =
substr($postTag, $tagOpen_start +
1);
$tagOpen_start =
strpos($postTag, '<');
// Do we have a nested tag?
$tagOpen_nested =
strpos($fromTagOpen, '<');
$tagOpen_nested_end =
strpos(substr($postTag, $tagOpen_end), '>');
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, '<');
// Lets get some information about our tag and setup attribute pairs
$tagOpen_nested =
(strpos($fromTagOpen, '<') +
$tagOpen_start +
1);
$currentTag =
substr($fromTagOpen, 0, $tagOpen_end);
$tagLength =
strlen($currentTag);
$currentSpace =
strpos($tagLeft, ' ');
// Are we an open tag or a close tag?
if (substr($currentTag, 0, 1) ==
"/") {
list
($tagName) =
explode(' ', $currentTag);
$tagName =
substr($tagName, 1);
list
($tagName) =
explode(' ', $currentTag);
* Exclude all "non-regular" tagnames
* OR remove if xssauto is on and tag is blacklisted
$postTag =
substr($postTag, ($tagLength +
2));
$tagOpen_start =
strpos($postTag, '<');
* Time to grab any attributes from the tag... need this section in
* case attributes have spaces in the values.
while ($currentSpace !==
false)
$fromSpace =
substr($tagLeft, ($currentSpace +
1));
$nextSpace =
strpos($fromSpace, ' ');
$openQuotes =
strpos($fromSpace, '"');
$closeQuotes =
strpos(substr($fromSpace, ($openQuotes +
1)), '"') +
$openQuotes +
1;
// Do we have an attribute to process? [check for equal sign]
if (strpos($fromSpace, '=') !==
false) {
* If the attribute value is wrapped in quotes we need to
* grab the substring from the closing quote, otherwise grab
if (($openQuotes !==
false) &&
(strpos(substr($fromSpace, ($openQuotes +
1)), '"') !==
false)) {
$attr =
substr($fromSpace, 0, ($closeQuotes +
1));
$attr =
substr($fromSpace, 0, $nextSpace);
* No more equal signs so add any extra text in the tag into
* the attribute array [eg. checked]
$attr =
substr($fromSpace, 0, $nextSpace);
// Add attribute pair to the attribute array
// Move search point and continue iteration
$currentSpace =
strpos($tagLeft, ' ');
// Is our tag in the user input array?
// If the tag is allowed lets append it to the output string
// Reconstruct tag with allowed attributes
for ($i =
0; $i <
count($attrSet); $i ++
)
$preTag .=
' '.
$attrSet[$i];
// Reformat single tags to XHTML
if (strpos($fromTagOpen, "</".
$tagName)) {
$preTag .=
'</'.
$tagName.
'>';
// Find next tag's start and continue iteration
$postTag =
substr($postTag, ($tagLength +
2));
$tagOpen_start =
strpos($postTag, '<');
// Append any code after the end of tags and return
* Internal method to strip a tag of certain attributes
* @param array $attrSet Array of attribute pairs to filter
* @return array Filtered array of attribute pairs
// Iterate through attribute pairs
for ($i =
0; $i <
count($attrSet); $i ++
)
// Split into name/value pairs
list
($attrSubSet[0]) =
explode(' ', $attrSubSet[0]);
* Remove all "non-regular" attribute names
* AND blacklisted attributes
// XSS attribute value filtering
// strips unicode, hex, etc
$attrSubSet[1] =
str_replace('&#', '', $attrSubSet[1]);
// strip normal newline within attr value
// convert single quotes from either side to doubles (Single quotes shouldn't be used to pad attr value)
if ((substr($attrSubSet[1], 0, 1) ==
"'") &&
(substr($attrSubSet[1], (strlen($attrSubSet[1]) -
1), 1) ==
"'")) {
$attrSubSet[1] =
substr($attrSubSet[1], 1, (strlen($attrSubSet[1]) -
2));
// Is our attribute in the user input array?
// If the tag is allowed lets keep it
// Does the attribute have a value?
$newSet[] =
$attrSubSet[0].
'="'.
$attrSubSet[1].
'"';
} elseif ($attrSubSet[1] ==
"0") {
$newSet[] =
$attrSubSet[0].
'="0"';
$newSet[] =
$attrSubSet[0].
'="'.
$attrSubSet[0].
'"';
* Try to convert to plaintext
* @return string Plaintext string
foreach($trans_tbl as $k =>
$v) {
$source =
strtr($source, $ttr);
$source =
preg_replace('/&#(\d+);/me', "chr(\\1)", $source); // decimal notation
$source =
preg_replace('/&#x([a-f0-9]+);/mei', "chr(0x\\1)", $source); // hex notation