escape_binary() without cleaning - used in API */ define('TYPE_BIN', 128); /**#@-*/ /** * Input Sanitizer * * This class is responsible for cleaning input. * * @author Blue Static * @copyright Copyright (c)2005 - 2009, Blue Static * @package ISSO * */ class BSInput { /** * An array of sanitized variables that have been cleaned for HTML tag openers and double quotes * @var array */ public $in = array(); /** * If we are running with magic_quotes_gpc on or off * @var int */ private $magicquotes = 0; /** * Constructor: set instance variables and execute input cleaning */ public function __construct() { // magic quotes $this->magicquotes = get_magic_quotes_gpc(); set_magic_quotes_runtime(0); // some debug info that's always useful BSApp::debug('magic_quotes_gpc = ' . $this->magicquotes); BSApp::debug('register_globals = ' . ini_get('register_globals')); $this->_sanitizeInputData(); } /** * Recursive XSS cleaner * * @param mixed Unsanitized REQUEST data * * @return mixed Sanitized data */ private function _sanitizeDataRecursive($data) { foreach ($data as $key => $value) { if (is_array($value)) { $data["$key"] = $this->_sanitizeDataRecursive($value); } else { if ($this->magicquotes) { $value = str_replace("\'", "'", $value); } $data["$key"] = $this->sanitize($value); } } return $data; } /** * Simple way to protect against HTML attacks with Unicode support * * @param string Unsanitzed text * * @return string Properly protected text that only encodes potential threats */ public function sanitize($text) { if ($this->magicquotes) { return str_replace(array('<', '>', '\"', '"'), array('<', '>', '"', '"'), $text); } else { return str_replace(array('<', '>', '"'), array('<', '>', '"'), $text); } } /** * Unicode-safe entity encoding system; similar to sanitize() * * @param string Unsanitized text * * @return string Unicode-safe sanitized text with entities preserved */ public function entityEncode($text) { $text = str_replace('&', '&', $text); $text = $this->sanitize($text); return $text; } /** * Takes text that has been processed for HTML and unsanitizes it * * @param string Text that needs to be turned back into HTML * * @return string Unsanitized text */ public function unsanitize($text) { return str_replace(array('<', '>', '"'), array('<', '>', '"'), $text); } /** * Smart addslashes() that only applies itself it the Magic Quotes GPC * is off. This should only be run on database query values that come * from ISSO->in[] input; data that needs sanitization should be run * through Db->escapeString() * * @param string Some string * @param bool Force magic quotes to be off * * @return string String that has slashes added */ public function escape($str, $force = true) { $db = BSApp::$db; if ($this->magicquotes && !$force) { if ($db) { return $db->escapeString(str_replace(array("\'", '\"'), array("'", '"'), $str)); } return $str; } else { if ($db) { return $db->escapeString($str); } return addslashes($str); } } /** * Runs through all of the input data and sanitizes it. */ private function _sanitizeInputData() { $this->in = $this->_sanitizeDataRecursive(array_merge($_GET, $_POST, $_COOKIE)); } /** * Sanitize function for something other than a string (which * everything is sanitized for if you use _sanitizeInputData(). Cleaned * data is placed back into Input->in; this makes it so you don't have * to constantly intval() [etc.] data. * * @param array Array of elements to clean as varname => type */ public function inputCleanArray($vars) { foreach ($vars as $varname => $type) { $this->inputClean($varname, $type); } } /** * Sanitize function that does a single variable as oppoesd to an array * (see inputCleanArray() for more details) * * @param string Variable name in ISSO->in[] * @param integer Sanitization type constant */ public function inputClean($varname, $type) { if (isset($this->in["$varname"])) { $this->in["$varname"] = $this->clean($this->in["$varname"], $type); } else { $this->in["$varname"] = $this->clean(null, $type); } return $this->in["$varname"]; } /** * Runs Input->escape() on a variable on Input->in[]. This is just a * short-hand wrapper so that queries can be shortened. When this is used, * the actual value in Input->in[] is not changed, only the return value * is escaped. * * @param string Input variable * * @return string Escaped input */ public function inputEscape($varname) { if (isset($this->in["$varname"])) { return $this->escape($this->in["$varname"]); } else { return $this->escape(null); } } /** * Cleaning function that does the work for inputClean(); this is * moved here so it can be used to clean things that aren't in * Input->in[] * * @param mixed Data * @param integer Sanitization type constant * * @return mixed Cleaned data */ public function clean($value, $type) { if (is_array($value)) { return $this->_cleanArray($value, $type); } if ($type == TYPE_INT) { $value = intval($value); } else if ($type == TYPE_UINT) { $value = (($val = intval($value)) < 0 ? 0 : $val); } else if ($type == TYPE_FLOAT) { $value = floatval($value); } else if ($type == TYPE_BOOL) { $value = (bool)$value; } else if ($type == TYPE_STR) { $value = $value; } else if ($type == TYPE_STRUN) { $value = $this->unsanitize($value); } else if ($type == TYPE_NONE) { if ($this->magicquotes) { $value = str_replace(array('\"', "\'"), array('"', "'"), $value); } else { $value = $value; } } else if ($type == TYPE_BIN) { $value = $value; } else { throw new Exception('Invalid clean type specified in BSInput::clean()'); return; } return $value; } /** * Recursion function for Input->clean() * * @param array Uncleaned array * @param integer Sanitization type constant * * @return array Cleaned array of data */ private function _cleanArray($array, $type) { foreach ($array as $key => $value) { $array["$key"] = $this->clean($value, $type); } return $array; } /** * Returns the lowercase version of the HTTP method (post or get) * * @return string HTTP method */ public function getHttpMethod() { $method = strtolower($_SERVER['REQUEST_METHOD']); if (!in_array($method, array('get', 'post'))) { throw new Exception('Invalid server request method: ' . $method); } return $method; } /** * Checks to see if a POST refer is actually from us */ public function checkPostReferer() { if ($this->getHttpMethod() == 'post') { $host = ($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_ENV['HTTP_HOST']; if ($host && $_SERVER['HTTP_REFERER']) { $parts = parse_url($_SERVER['HTTP_REFERER']); $ourhost = $parts['host'] . (isset($parts['port']) ? ":$parts[port]" : ''); if ($ourhost != $host) { throw new Exception('No external hosts are allowed to POST to this application'); exit; } BSApp::debug('remote post check = ok'); } else { BSApp::debug('remote post check = FAILED'); } } } } ?>