Added: library/trunk/lib/filter.class.php (21 => 22)
--- library/trunk/lib/filter.class.php 2006-09-24 01:07:26 UTC (rev 21)
+++ library/trunk/lib/filter.class.php 2006-10-13 16:53:49 UTC (rev 22)
@@ -0,0 +1,844 @@
+<?php
+/**
+ * filter.class.php - variable manipulation, force typing, input and output filtering
+ *
+ * This class is used everywhere to keep variables clean and shiny - notice this is not validation!
+ *
+ * This is released under the GPL, see license.txt for details
+ *
+ * @author Elizabeth Smith <emsmith@callicore.net>
+ * @copyright Elizabeth Smith (c)20050-2006
+ * @link http://callicore.net
+ * @license http://www.opensource.org/licenses/gpl-license.php GPL
+ * @version $Id$
+ * @since Php 5.1.0
+ * @package callicore
+ * @subpackage library
+ * @category lib
+ * @filesource
+ */
+
+/**
+ * CC_Filter - variable typing and manipulation
+ *
+ * Some usage is similiar to new php filter extension - the general idea
+ * is input filtering (cookie/session/get/post/files/server), output filtering
+ * and string charset manipulation
+ *
+ * This does NOT do straight validation! instead it will sanitize all data! If you
+ * want validation - use CC_Validate, eh?
+ *
+ * TODO: additional option of FORMAT in addition to strip, callback, et al
+ * format has pretty options in addition to strip functionality
+ */
+class CC_Filter
+{
+
+ //-------------- Input Source Constants -------------
+
+ /**
+ * @const GET from $_GET
+ */
+ const GET = 1;
+
+ /**
+ * @const POST from $_POST and $_FILES
+ */
+ const POST = 2;
+
+ /**
+ * @const COOKIE from Kal_Http_Cookie (we don't use straight $_COOKIE)
+ */
+ const COOKIE = 3;
+
+ /**
+ * @const SESSION from Kal_Http_Session (we don't use php sessions at ALL)
+ */
+ const SESSION = 4;
+
+ /**
+ * @const SERVER from $_SERVER
+ */
+ const SERVER = 5;
+
+ //-------------- Type Forcing Constants -------------
+
+ /**
+ * @const INT regular integer
+ */
+ const INT = 1;
+
+ /**
+ * @const BOOL boolean
+ * supports t, f, true, false , y, n, yes, no, on, off, 1, 0 (case insensitive)
+ */
+ const BOOL = 2;
+
+ /**
+ * @const FLOAT float
+ */
+ const FLOAT = 3;
+
+ /**
+ * @const STR string
+ */
+ const STR = 4;
+
+ /**
+ * @const ARR array(array is reserved word...sigh)
+ */
+ const ARR = 5;
+
+ /**
+ * @const OBJ object
+ */
+ const OBJ = 6;
+
+ //-------------- Special Items -------------
+
+ /**
+ * @const CALLBACK use function callback
+ */
+ const CALLBACK = 7;
+
+ /**
+ * @const REGEX use predefined or user regex
+ */
+ const REGEX = 8;
+
+ /**
+ * @const STRIP strip the string according to options
+ */
+ const STRIP = 9;
+
+ /**
+ * @const FORMAT format a string for display according to options
+ */
+ const FORMAT = 10;
+
+ //-------------- Publicly Changeable -------------
+
+ /**
+ * array of int -> string for mapping pathinfo vars to get vars
+ * set this before calling getInput if using pathinfo with nonstandard map
+ *
+ * @var $map array
+ */
+ public static $map = array('module', 'class', 'method', 'page');
+
+ /**
+ * multi dimensional array with allowed tags and allowed attr
+ *
+ * @var $whitelist array
+ */
+ public static $whitelist = array('a' => array('href'), 'span', 'br', 'p', 'attr' => array('class', 'title'));
+
+ //-------------- Internal only -------------
+
+ /**
+ * regex to use for REGEX filter
+ *
+ * @var $regex array
+ */
+ private static $regex = array(
+ 'ucase' => '/[^A-Z]/', //all uppercase letters
+ 'lcase' => '/[^a-z]/', //all lowercase letters
+ 'alpha' => '/[^A-Za-z]/', //entire alphabet
+ 'numeric' => '/[^0-9]/', //all numbers
+ 'int' => '/[^0-9+-]/', //integer notation
+ 'float' => '/[^0-9+-.,eE]/', //float notation including fractions, thousand, scientific notation
+ 'alphanumeric' => '/[^A-Za-z0-9_]/', //all letters and numbers and underscore
+ 'filename' => '/[^a-z0-9_-\.]/', //adds _-., no uppercase
+ 'url' => '/[^A-Za-z0-9_-\.%\+]/', //adds % and + to filename
+ 'email' => '/[a-zA-Z0-9"!#$%&\'*+-\/=?^_`{|}~@.\[\]]/', //valid items for email
+ 'username' => '/[^A-Za-z0-9_-\.&#\*~\'",\|]/', //adds some special characters and space
+ 'password' => '/[^A-Za-z0-9~!@#$%\^&\*\(\)-=\+:;\'",\.\?]/', //adds lots of special characters and space
+ );
+
+ /**
+ * array of pathinfo vars
+ *
+ * @var $pathinfo array
+ */
+ private static $pathinfo;
+
+ /**
+ * magic quotes gpc status
+ *
+ * @var $magicquotes bool
+ */
+ private static $magicquotes;
+
+ /**
+ * magic_quotes_sybase status
+ *
+ * @var $sybasequotes bool
+ */
+ private static $sybasequotes;
+
+ //----------------------------------------------------------------
+ // Setup
+ //----------------------------------------------------------------
+
+ /**
+ * private function setup
+ *
+ * basically a static __construct
+ *
+ * @return void
+ */
+ private static function setup()
+ {
+ self::$magicquotes = (bool) ini_get('magic_quotes_gpc');
+ self::$sybasequotes = (bool) ini_get('magic_quotes_sybase');
+ if(self::hasInput(self::SERVER, 'path_info'))
+ {
+ $pathinfo = self::input(self::SERVER, 'path_info', self::STRIP);
+ }
+ //if we're apache doing 404 redirect as rewriting we do this
+ elseif(self::hasInput(self::SERVER, 'redirect_status'))
+ {
+ $pathinfo = str_replace(self::input(self::SERVER, 'script_name', self::STRIP), '', self::input(self::SERVER, 'request_uri', self::STRIP));
+ }
+ //if we're IIS doing 404 redirect rewriting this can get messy
+ elseif(self::hasInput(self::SERVER, 'query_string') and strncmp('404;', self::input(self::SERVER, 'script_name', self::STRIP), 4) == 0)
+ {
+ $pathinfo = str_replace('404;'.((self::hasInput(self::SERVER, 'https') and self::input(self::SERVER, 'https', self::STRIP) != 'off') ?
+ 'https' : 'http').'://'.$this->getInput(self::SERVER, 'server_name', self::STRIP)
+ .dirname(self::input(self::SERVER, 'orig_path_info', self::STRIP)).'/', '', self::input(self::SERVER, 'query_string', self::STRIP));
+ }
+ else
+ {
+ $pathinfo = '';
+ }
+ self::$pathinfo = preg_split('#/|//#u', $pathinfo, -1, PREG_SPLIT_NO_EMPTY);
+ }
+
+ //----------------------------------------------------------------
+ // Actual public methods (all three of them)
+ //----------------------------------------------------------------
+
+ /**
+ * public function input
+ *
+ * grabs input
+ *
+ * @param type $name about
+ * @return type about
+ */
+ public static function input($source, $name, $filter, $default = NULL, $options = array())
+ {
+ if(is_null(self::$magicquotes))
+ {
+ self::setup();
+ }
+ if(self::hasInput($source, $name) == FALSE)
+ {
+ return $default;
+ }
+ $source = self::checkInput($source);
+ switch($source)
+ {
+ case(self::POST):
+ {
+ if(isset($_FILES[$name]))
+ {
+ $var = $_FILES[$name];
+ }
+ else
+ {
+ $var = self::deslash($_POST[$name]);
+ }
+ break;
+ }
+ case(self::COOKIE):
+ {
+ if(isset(Kalfu::$obj->cookie))
+ {
+ $var = Kalfu::$obj->cookie->$name;
+ }
+ else
+ {
+ $var = $_COOKIE[$name];
+ }
+ break;
+ }
+ case(self::SESSION):
+ if(isset(Kalfu::$obj->session))
+ {
+ $var = Kalfu::$obj->session->$name;
+ }
+ else
+ {
+ $var = $_SESSION[$name];
+ }
+ break;
+ case(self::SERVER):
+ $var = $_SERVER[strtoupper($name)];
+ break;
+ default:
+ {
+ if(isset($_GET[$name]))
+ {
+ $var = self::deslash($_GET[$name]);
+ }
+ else
+ {
+ $var = self::checkPathinfo($name);
+ }
+ break;
+ }
+ }
+ return self::dispatch($var, $filter, $options);
+ }
+
+ /**
+ * public function hasInput
+ *
+ * description
+ *
+ * @param type $name about
+ * @return type about
+ */
+ public static function hasInput($source, $name)
+ {
+ $source = self::checkInput($source);
+ // yeah switch is slow, bite me
+ switch($source)
+ {
+ case(self::POST):
+ $set = isset($_POST[$name]);
+ if($set == FALSE)
+ {
+ $set = isset($_FILES[$name]);
+ }
+ return $set;
+ case(self::COOKIE):
+ if(isset(Kalfu::$obj->cookie))
+ {
+ return isset(Kalfu::$obj->cookie->$name);
+ }
+ else
+ {
+ return isset($_COOKIE[$name]);
+ }
+ case(self::SESSION):
+ if(isset(Kalfu::$obj->session))
+ {
+ return isset(Kalfu::$obj->session->$name);
+ }
+ else
+ {
+ return isset($_SESSION[$name]);
+ }
+ case(self::SERVER):
+ return isset($_SERVER[strtoupper($name)]);
+ default:
+ {
+ $set = isset($_GET[$name]);
+ if($set == FALSE)
+ {
+ $set = self::checkPathinfo($name);
+ }
+ return $set;
+ }
+ }
+ }
+
+ /**
+ * public function output
+ *
+ * identical to input only instead of grabbing a superglobal/input value, the
+ * variable is provided by the user
+ *
+ * @param mixed $var variable we're cleaning and checking
+ * @param str|int $filter filter type to use
+ * @return type about
+ */
+ public static function output(&$var, $filter, $default = NULL, $options = array())
+ {
+ if(!isset($var))
+ {
+ return $default;
+ }
+ return self::dispatch($var, $filter, $options);
+ }
+
+ //----------------------------------------------------------------
+ // Type Forcing Functions
+ //----------------------------------------------------------------
+
+ /**
+ * private function toInt
+ *
+ * casts whatever to an int
+ *
+ * @param mixed $var
+ * @return int
+ */
+ private static function toInt($var)
+ {
+ if(is_int($var))
+ {
+ return $var;
+ }
+ elseif(is_float($var))
+ {
+ return intval($var);
+ }
+ else
+ {
+ // settype does weird stuff, so we'll add 0 first
+ $var += 0;
+ // this is probably redundant
+ settype($var, 'int');
+ return $var;
+ }
+ }
+
+ /**
+ * private function toBool
+ *
+ * casts whatever to a boolean
+ *
+ * @param mixed $var
+ * @return bool
+ */
+ private static function toBool($var)
+ {
+ if(is_bool($var))
+ {
+ return $var;
+ }
+ else
+ {
+ //match all TRUE values case insensitively
+ if(preg_match('/t|true|y|yes|on/i', $var))
+ {
+ return TRUE;
+ }
+ //match all FALSE values case insensitively
+ elseif(preg_match('/f|false|n|no|off/i', $var))
+ {
+ return FALSE;
+ }
+ //otherwise you're doomed to php's settype guessing
+ else
+ {
+ settype($var, 'bool');
+ return $var;
+ }
+ }
+ }
+
+ /**
+ * private function toFloat
+ *
+ * casts whatever to a float
+ *
+ * @param mixed $var
+ * @return float
+ */
+ private static function toFloat($var)
+ {
+ if(is_float($var))
+ {
+ return $var;
+ }
+ else
+ {
+ return floatval($var);
+ }
+ }
+
+ /**
+ * private function toString
+ *
+ * casts whatever to a string AND TRIMS IT
+ *
+ * @param mixed $var
+ * @return string
+ */
+ private static function toString($var)
+ {
+ if(is_string($var))
+ {
+ return trim($var);
+ }
+ else
+ {
+ return trim(strval($var));
+ }
+ }
+
+ /**
+ * private function toArray
+ *
+ * forces whatever to an array
+ *
+ * @param mixed $var
+ * @return array
+ */
+ private static function toArray($var)
+ {
+ if(is_array($var))
+ {
+ return $var;
+ }
+ else
+ {
+ //we'll assume if there's an equal sign then it's parseable
+ if(preg_match('/^(.+)=(.+)$/', $var))
+ {
+ $array = array();
+ parse_str($var, $array);
+ return $array;
+ }
+ else
+ {
+ return array($var);
+ }
+ }
+ }
+
+ /**
+ * private function toObject
+ *
+ * casts whatever to an object
+ *
+ * @param mixed $var
+ * @return string
+ */
+ private static function toObject($var, $options = array())
+ {
+ if(!isset($options['class']))
+ {
+ $class = 'stdClass';
+ }
+ else
+ {
+ $class = $options['class'];
+ }
+ // remember - this will attempt to autoload classes so they better be somewhere
+ if(!(is_object($var) and $var instanceof $class))
+ {
+ //if this is NOT an object and it's not a stdclass, we'll pass the var as a constructor argument
+ if(!is_object($var) and $class == 'StdClass')
+ {
+ settype($var, 'object');
+ }
+ else
+ {
+ $var = new $class($var);
+ }
+ }
+ return $var;
+ }
+
+ //----------------------------------------------------------------
+ // Special Items
+ //----------------------------------------------------------------
+
+ /**
+ * private function doCallback
+ *
+ * performs a callback
+ *
+ * @param mixed $callback
+ * @return mixed
+ */
+ private static function doCallback($var, $options = NULL)
+ {
+ if(!isset($options['callback']))
+ {
+ $callback = array(__CLASS__, 'toString');
+ }
+ else
+ {
+ $callback = $options['callback'];
+ unset($options['callback']);
+ }
+ $options = array_unshift($options, $var);
+ if(is_callable($callback))
+ {
+ $var = call_user_func_array($callback, $options);
+ }
+ return $var;
+ }
+
+ /**
+ * private function doRegex
+ *
+ * performs a regex replace call
+ *
+ * @param mixed $var
+ * @return mixed
+ */
+ private static function doRegex($var, $options = NULL)
+ {
+ if(isset($options['custom']))
+ {
+ $regex = '/'.preg_quote($options['custom'], '/').'/';
+ }
+ elseif(isset($options['filter']) and isset(self::$regex[$options['filter']]))
+ {
+ $regex = self::$regex[$options['filter']];
+ }
+ else
+ {
+ $regex = self::$regex['alphanumeric'];
+ }
+ return preg_replace($regex, '', $var);
+ }
+
+ /**
+ * private function doStrip
+ *
+ * decodes options and farms out to appropriate methods
+ *
+ * @param mixed $var
+ * @return mixed
+ */
+ private static function doStrip($var, $options = NULL)
+ {
+ return $var;
+ }
+
+ /**
+ * private function doFormat
+ *
+ * decodes options and farms out to appropriate methods
+ *
+ * @param mixed $var
+ * @return mixed
+ */
+ private function doFormat($var, $options = NULL)
+ {
+ }
+
+ //----------------------------------------------------------------
+ // Helper Functions
+ //----------------------------------------------------------------
+
+ /**
+ * private function dispatch
+ *
+ * matches string or int to make sure it's one of the desired types
+ *
+ * @param mixed $type type we're checking
+ * @return int
+ */
+ private static function dispatch($var, $type, $options)
+ {
+ if(is_int($type))
+ {
+ // yeah switch is slow, bite me
+ switch($type)
+ {
+ case(self::INT):
+ return self::toInt($var);
+ case(self::BOOL):
+ return self::toBool($var);
+ case(self::FLOAT):
+ return self::toFloat($var);
+ case(self::STR):
+ return self::toString($var);
+ case(self::ARR):
+ return self::toArray($var);
+ case(self::OBJ):
+ return self::toObject($var, $options);
+ case(self::CALLBACK):
+ return self::doCallback($var, $options);
+ case(self::REGEX):
+ return self::doRegex($var, $options);
+ case(self::FORMAT):
+ return self::doFormat($var, $options);
+ default:
+ return self::doStrip($var, $options);
+ }
+ }
+ else
+ {
+ // yeah switch is slow, bite me
+ switch(strtolower($type))
+ {
+ case('int'):
+ case('integer'):
+ return self::toInt($var);
+ case('bool'):
+ case('boolean'):
+ return self::toBool($var);
+ case('float'):
+ case('double'):
+ case('decimal'):
+ return self::toFloat($var);
+ case('str'):
+ case('string'):
+ return self::toString($var);
+ case('arr'):
+ case('array'):
+ return self::toArray($var);
+ case('obj'):
+ case('object'):
+ return self::toObject($var, $options);
+ case('call'):
+ case('callback'):
+ case('function'):
+ return self::doCallback($var, $options);
+ case('regex'):
+ case('filter'):
+ case('pcre'):
+ return self::doRegex($var, $options);
+ case('format'):
+ case('output'):
+ case('display'):
+ return self::doFormat($var, $options);
+ default:
+ return self::doStrip($var, $options);
+ }
+ }
+ }
+
+ /**
+ * private function checkInput
+ *
+ * matches string or int to make sure it's one of the desired inputs
+ *
+ * @param mixed $type type we're checking
+ * @return int
+ */
+ private static function checkInput($source)
+ {
+ if(is_int($source))
+ {
+ // yeah switch is slow, bite me
+ switch($source)
+ {
+ case(self::POST):
+ return self::POST;
+ case(self::COOKIE):
+ return self::COOKIE;
+ case(self::SESSION):
+ return self::SESSION;
+ case(self::SERVER):
+ return self::SERVER;
+ default:
+ return self::GET;
+ }
+ }
+ else
+ {
+ // yeah switch is slow, bite me
+ switch(strtolower($source))
+ {
+ case('post'):
+ return self::POST;
+ case('cookie'):
+ return self::COOKIE;
+ case('session'):
+ return self::SESSION;
+ case('server'):
+ return self::SERVER;
+ default:
+ return self::GET;
+ }
+ }
+ }
+
+ /**
+ * private function deslash
+ *
+ * undoes any magic quotes
+ *
+ * @param mixed $var, var to clean
+ * @return mixed cleaned var
+ */
+ private static function deslash($var)
+ {
+ if(self::$magicquotes or self::$sybasequotes)
+ {
+ if(is_scalar($var))
+ {
+ if(self::$sybasequotes)
+ {
+ $var = str_replace('\'\'', '\'', $var);
+ }
+ elseif(self::$magicquotes)
+ {
+ $var = stripslashes($var);
+ }
+ }
+ else
+ {
+ foreach($var as &$item)
+ {
+ $item = self::deslash($item);
+ }
+ }
+ }
+ return $var;
+ }
+
+ /**
+ * private function getPathinfo
+ *
+ * given a get var -> return a mapped pathinfo spot
+ *
+ * @return void
+ */
+ private static function getPathinfo($var)
+ {
+ // actually look for the pathinfo
+ if(in_array($var, self::$map))
+ {
+ $key = array_search($var, self::$map);
+ if(isset(self::$pathinfo[$key]))
+ {
+ return self::$pathinfo[$key];
+ }
+ }
+ return;
+ }
+
+ /**
+ * private function getPathinfo
+ *
+ * given a get var -> return a mapped pathinfo spot
+ *
+ * @return void
+ */
+ private static function checkPathinfo($var)
+ {
+ if(in_array($var, self::$map))
+ {
+ $key = array_search($var, self::$map);
+ if(isset(self::$pathinfo[$key]))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+
+ //----------------------------------------------------------------
+ // Strip and Format sub-functions
+ //----------------------------------------------------------------
+
+// strip only: toTxt
+// strip only: toXhtml
+// strip only: force min/max length with chop/pad option
+
+// both: charset conversion (will need hard convert in kal_string)
+// both: specialchars/htmlentities (will need hard specialchars/entities in kal_string)
+// both: extended strip tags with normalize/tidy
+
+// format only: chop long words
+// format only: beautify html/xhtml
+// format only: indent
+// format only: encode emails
+// format only: linkify urls
+// format only: wordwrap
+// format only: format callback (for wiki/bbcode/textify/smilies or other markup -> html)
+}
+?>
Property changes on: library/trunk/lib/filter.class.php
___________________________________________________________________
Name: tsvn:logminsize
+ 15
Name: svn:keywords
+ Id