sanitize();
}
// deal with array's or array emulating objects
elseif (is_array($var) or ($var instanceOf \Traversable and $var instanceOf \ArrayAccess))
{
// recurse on array values
foreach($var as $key => $value)
{
$var[$key] = static::clean($value, $filters, $type);
}
}
// deal with all other variable types
else
{
is_null($filters) and $filters = \Config::get($type, array());
$filters = is_array($filters) ? $filters : array($filters);
foreach ($filters as $filter)
{
// is this filter a callable local function?
if (is_string($filter) and is_callable('static::'.$filter))
{
$var = static::$filter($var);
}
// is this filter a callable function?
elseif (is_callable($filter))
{
$var = call_user_func($filter, $var);
}
// assume it's a regex of characters to filter
else
{
$var = preg_replace('#['.$filter.']#ui', '', $var);
}
}
}
return $var;
}
public static function xss_clean($value, array $options = array())
{
if ( ! is_array($value))
{
if ( ! function_exists('htmLawed'))
{
import('htmlawed/htmlawed', 'vendor');
}
return htmLawed($value, array_merge(array('safe' => 1, 'balanced' => 0), $options));
}
foreach ($value as $k => $v)
{
$value[$k] = static::xss_clean($v);
}
return $value;
}
public static function strip_tags($value)
{
if ( ! is_array($value))
{
$value = filter_var($value, FILTER_SANITIZE_STRING);
}
else
{
foreach ($value as $k => $v)
{
$value[$k] = static::strip_tags($v);
}
}
return $value;
}
public static function htmlentities($value, $flags = null, $encoding = null, $double_encode = null)
{
static $already_cleaned = array();
is_null($flags) and $flags = \Config::get('security.htmlentities_flags', ENT_QUOTES);
is_null($encoding) and $encoding = \Fuel::$encoding;
is_null($double_encode) and $double_encode = \Config::get('security.htmlentities_double_encode', false);
// Nothing to escape for non-string scalars, or for already processed values
if (is_bool($value) or is_int($value) or is_float($value) or in_array($value, $already_cleaned, true))
{
return $value;
}
if (is_string($value))
{
$value = htmlentities($value, $flags, $encoding, $double_encode);
}
elseif (is_object($value) and $value instanceOf \Sanitization)
{
$value->sanitize();
return $value;
}
elseif (is_array($value) or ($value instanceof \Iterator and $value instanceof \ArrayAccess))
{
// Add to $already_cleaned variable when object
is_object($value) and $already_cleaned[] = $value;
foreach ($value as $k => $v)
{
$value[$k] = static::htmlentities($v, $flags, $encoding, $double_encode);
}
}
elseif ($value instanceof \Iterator or get_class($value) == 'stdClass')
{
// Add to $already_cleaned variable
$already_cleaned[] = $value;
foreach ($value as $k => $v)
{
$value->{$k} = static::htmlentities($v, $flags, $encoding, $double_encode);
}
}
elseif (is_object($value))
{
// Check if the object is whitelisted and return when that's the case
foreach (\Config::get('security.whitelisted_classes', array()) as $class)
{
if (is_a($value, $class))
{
// Add to $already_cleaned variable
$already_cleaned[] = $value;
return $value;
}
}
// Throw exception when it wasn't whitelisted and can't be converted to String
if ( ! method_exists($value, '__toString'))
{
throw new \RuntimeException('Object class "'.get_class($value).'" could not be converted to string or '.
'sanitized as ArrayAccess. Whitelist it in security.whitelisted_classes in app/config/config.php '.
'to allow it to be passed unchecked.');
}
$value = static::htmlentities((string) $value, $flags, $encoding, $double_encode);
}
return $value;
}
/**
* Check CSRF Token
*
* @param string $value CSRF token to be checked, checks post when empty
* @return bool
*/
public static function check_token($value = null)
{
$value = $value ?: \Input::param(static::$csrf_token_key, \Input::json(static::$csrf_token_key, 'fail'));
// always reset token once it's been checked and still the same
if (static::fetch_token() == static::$csrf_old_token and ! empty($value))
{
static::set_token(true);
}
return $value === static::$csrf_old_token;
}
/**
* Fetch CSRF Token for the next request
*
* @return string
*/
public static function fetch_token()
{
if (static::$csrf_token !== false)
{
return static::$csrf_token;
}
static::set_token();
return static::$csrf_token;
}
/**
* Generate new token. Based on an example from OWASP
*
* @return string
*/
public static function generate_token()
{
// generate a random token base
if (function_exists('random_bytes'))
{
$token_base = \Config::get('security.token_salt', '') .random_bytes(64);
}
elseif (function_exists('openssl_random_pseudo_bytes'))
{
$token_base = \Config::get('security.token_salt', '') . openssl_random_pseudo_bytes(64);
}
else
{
$token_base = time() . uniqid() . \Config::get('security.token_salt', '') . mt_rand(0, mt_getrandmax());
}
// return the hashed token
if (function_exists('hash_algos'))
{
foreach (array('sha512', 'sha384', 'sha256', 'sha224', 'sha1', 'md5') as $hash)
{
if (in_array($hash, hash_algos()))
{
return hash($hash, $token_base);
}
}
}
// if all else fails
return md5($token_base);
}
protected static function set_token($reset = false)
{
// re-use old token when found (= not expired) and expiration is used (otherwise always reset)
if ( ! $reset and static::$csrf_old_token and \Config::get('security.csrf_expiration', 0) > 0)
{
static::$csrf_token = static::$csrf_old_token;
}
// set new token for next session when necessary
else
{
static::$csrf_token = static::generate_token();
$expiration = \Config::get('security.csrf_expiration', 0);
\Cookie::set(static::$csrf_token_key, static::$csrf_token, $expiration);
}
}
/**
* JS fetch token
*
* Produces JavaScript fuel_csrf_token() function that will return the current
* CSRF token when called. Use to fill right field on form submit for AJAX operations.
*
* @return string
*/
public static function js_fetch_token()
{
$output = ''.PHP_EOL;
return $output;
}
/**
* JS set token
*
* Produces JavaScript fuel_set_csrf_token() function that will update the current
* CSRF token in the form when called, based on the value of the csrf cookie
*
* @return string
*/
public static function js_set_token()
{
$output = ''.PHP_EOL;
return $output;
}
}