I'm working on a general Requestmethod
class which sanitizes and recasts the input of users in an automatic fashion. I've also tried to do array-access in cookies.
My biggest question are:
- Is this too much for one class alone?
- Is the readability/thinking right on this?
Code:
Example: (<input type="checkbox" name="checkboxes[]" />)
$a = new Request('POST');
$b = $a->getArray('checkboxes');
$b->get(0);
$b->get(1);
$b->get(2);
class REQUESTCONF {
const XSS = false;
const SALT = 'anysalt';
const c_expire = 24;
const c_path = '/';
const c_domain = '';
const c_secure = false;
const c_httponly = false;
}
/**
* Class to get Secure Request Data
*
* XSS Levels:
* 0 / false = off
* 1 = htmlentities
* 2 = strip tags
*
* @package Request
*/
class Request {
private $DATA;
private $CURSOR = false;
private $XSS = false;
private $METHOD;
/**
* Constructor
*
* @package Request
* @param string $METHOD POST GET SESSION or COOKIE
* @param boolean $XSS XSS Prevent Level
* @uses sanitize(
);
* @return object Request
* @access public
*/
function __construct($METHOD,$XSS=false) {
$this->METHOD = strtoupper($METHOD);
$this->XSS = $XSS;
switch ($this->METHOD) {
case 'FILE':
$this->DATA = $_FILES;
break;
case 'GET':
$this->DATA = $_GET;
break;
case 'POST':
$this->DATA = $_POST;
break;
case 'COOKIE':
foreach($_COOKIE as $k => $v) {
// hiding Notice - but no other way :'(
$array = @unserialize($v);
if ($array && is_array($array)) {
$this->DATA[$k] = $array;
} else {
$this->DATA[$k] = $v;
}
}
break;
case 'SESSION':
$this->DATA = $_SESSION;
break;
default:
trigger_error('Parameter must be a valid Request Method (GET, POST, FILE, SESSION or COOKIE)',E_USER_ERROR);
die();
break;
}
$this->DATA = $this->sanitize($this->DATA);
return $this;
}
/**
* Destruct - clean up
*
* @package Request
* @access public
*/
function __destruct() {
$this->save();
if ( $this->METHOD == 'SESSION' )
session_regenerate_id();
unset($this->XSS);
unset($this->DATA);
unset($this->CURSOR);
unset($this->METHOD);
}
/**
* Removes a Value with $key of $this->DATA
*
* @package Request
* @param string $key Arraykey of Element in $DATA
* @access public
*/
public function remove($key){
if ( $this->CURSOR != false && isset($this->DATA[$this->CURSOR]) && is_array($this->DATA[$this->CURSOR]) ) {
unset($this->DATA[$this->CURSOR][$key]);
} elseif (isset($this->DATA[$key])) {
unset($this->DATA[$key]);
} else {
return false;
}
}
/**
* Dumps whole $DATA
*
* @package Request
* @access public
*/
public function dump(){
var_dump($this->DATA);
}
/**
* Set Value in $DATA
*
* @package Request
* @param string $key Arraykey of Element in $DATA
* @param mixed $value String Integer Float or Bool want to set in $DATA
* @return boolean
* @access public
*/
public function set($key,$value){
if ( $this->CURSOR != false && isset($this->DATA[$this->CURSOR]) && is_array($this->DATA[$this->CURSOR]) ) {
$this->DATA[$this->CURSOR][$key] = $value;
return 1;
}
if (is_array($value))
return false;
$this->DATA[$key] = $value;
$this->setToken();
return $this;
}
/**
* Get a Value from $DATA with validation
*
* @package Request
* @uses object validateString
* @param string $key Arraykey of Element in $DATA
* @param mixed $validate Regex Rule for validation or false
* @return mixed $this->DATA[$var] Contents of the Arraykey
* @access public
*/
public function validGet($key,$validateRegex){
if (!$this->checkToken())
return false;
if ( $string = $this->get($key) ) {
if (preg_match($validateRegex,$string))
return $string;
}
return false;
}
/**
* Get Filesize when Cursor is on a FILE Request
*
* @package Request
* @return int Filesize in Bytes of File
* @access public
*/
public function getFilesize(){
if ($this->METHOD != 'FILE' || !$this->CURSOR)
return false;
return $this->DATA[$this->CURSOR]['size'];
}
/**
* Get Filename when Cursor is on a FILE Request
*
* @package Request
* @return string Name of File
* @access public
*/
public function getFilename(){
if ($this->METHOD != 'FILE' || !$this->CURSOR)
return false;
return $this->DATA[$this->CURSOR]['name'];
}
/**
* Get MIME when Cursor is on a FILE Request
*
* @package Request
* @return string MIME-Type of File
* @access public
*/
public function getFileType(){
if ($this->METHOD != 'FILE' || !$this->CURSOR)
return false;
// When File is a Picture getimagesize() mime is more secure and can handle PSDs - exif not
if ($img = getimagesize($this->DATA[$this->CURSOR]['tmp_name'])) {
return $img['mime'];
} elseif (isset($this->DATA[$this->CURSOR]['type'])) {
return $this->DATA[$this->CURSOR]['type'];
} else {
return false;
}
}
/**
* Saves the File to a given destination
*
* @package Request
* @param string $dest Save Destination
* @return boolean
* @access public
*/
public function saveFile($dest){
if ($this->METHOD != 'FILE' || !$this->CURSOR)
return false;
if (move_uploaded_file($this->DATA[$this->CURSOR]['tmp_name'],$dest)) {
return true;
} else {
return false;
}
}
/**
* Sets the Cursor to a FILE Request
*
* @package Request
* @param string $key Arraykey of Element in $DATA
* @access public
*/
public function getFile($key){
if ($this->METHOD != 'FILE')
return false;
//sanitize filename => no leading dot
return $this->getArray($key);
}
/**
* Get a Value from $DATA
*
* @package Request
* @param string $key Arraykey of Element in $DATA
* @return mixed $this->DATA[$var] Contents of the Arraykey
* @access public
*/
public function get($key){
if (!$this->checkToken())
return false;
if ( $this->CURSOR != false && isset($this->DATA[$this->CURSOR][$key]))
return $this->DATA[$this->CURSOR][$key];
if (!isset($this->DATA[$key]))
return false;
return $this->DATA[$key];
}
/**
* Set a Array in $DATA
*
* @package Request
* @param array $array Array you want to Store in $DATA
* @return boolean true
* @access public
*/
public function setArray($key,$array){
if (!is_array($array) OR $this->METHOD == 'FILE')
return false;
$this->DATA[$key] = $array;
$this->setToken();
return $this;
}
/**
* Sets the Cursor to an existing arraykey from Data when its an Array
* Otherwise set it to false and return false
*
* @package Request
* @param string $key Key of an Array in $DATA
* @return object Request
* @access public
*/
public function getArray($key){
if (!isset($this->DATA[$key]) || !is_array($this->DATA[$key])) {
$this->CURSOR = false;
return false;
}
$this->CURSOR = $key;
return $this;
}
/* Sanitizer
*
*
* @package Request
* @return array sanitized and pseudotyped Array (since POST and GET is String only)
* @access private
*/
private function sanitize($array){
foreach ($array as $k => $v) {
if (is_numeric($v)) {
$array[$k] = $v + 0;
if ( is_int($v) ) {
$array[$k] = (int) $v;
} elseif ( is_float($v) ) {
$array[$k] = (float) $v;
}
} elseif (is_bool($v)) {
$array[$k] = (bool) $v;
} elseif (is_array($v)) {
$array[$k] = $this->sanitize($array[$k]);
} else {
if ($this->XSS > 0) {
switch ($this->XSS) {
case 1:
$array[$k] = htmlentities(trim($v));
break;
case 2:
$array[$k] = strip_tags(trim($v));
break;
}
} else {
$array[$k] = (string) trim($v);
}
}
}
return $array;
}
/**
* refill the original REQUEST
*
* @package Request
* @access public
*/
public function save() {
switch($this->METHOD) {
case "GET" :
$_GET = $this->DATA;
break;
case "POST" :
$_POST = $this->DATA;
break;
case "SESSION" :
$_SESSION = $this->DATA;
break;
case "COOKIE" :
$expire = time()+3600*REQUESTCONF::c_expire;
foreach ($this->DATA as $K => $V) {
if ( is_array($V)) {
setcookie($K,serialize($V),
$expire,
REQUESTCONF::c_path,
REQUESTCONF::c_domain,
REQUESTCONF::c_secure,
REQUESTCONF::c_httponly
);
} else {
setcookie($K,$V,
$expire,
REQUESTCONF::c_path,
REQUESTCONF::c_domain,
REQUESTCONF::c_secure,
REQUESTCONF::c_httponly
);
}
}
break;
}
return 1;
}
/**
* Generates a Token with data serializing and a given salt from Config
* saves it in the first level of Session or Cookie
*
* @package Request
* @access private
*/
private function setToken() {
if ($this->METHOD == 'SESSION' || $this->METHOD == 'COOKIE') {
if ( isset($this->DATA['TOKEN']))
unset($this->DATA['TOKEN']);
$this->DATA['TOKEN'] = crc32(serialize($this->DATA).REQUESTCONF::SALT);
}
}
/**
* checks the inserted Tokenhash with actual Data in Session or Cookie
*
* @package Request
* @return boolean true on success false on fail
* @access private
*/
private function checkToken() {
if ($this->METHOD != 'SESSION' && $this->METHOD != 'COOKIE' )
return 1;
if ( isset($this->DATA['TOKEN'])) {
$proof = $this->DATA['TOKEN'];
unset($this->DATA['TOKEN']);
if ( $proof != crc32(serialize($this->DATA).REQUESTCONF::SALT) ) {
return false;
} else {
$this->DATA['TOKEN'] = crc32(serialize($this->DATA).REQUESTCONF::SALT);
return 1;
}
} else {
return false;
}
}
}
function Request($method,$xss=false) {
if (!$xss)
$xss = REQUESTCONF::XSS;
return new Request($method,$xss);
}
?>