Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: suralc/yii
...
head fork: suralc/yii
Checking mergeability… Don't worry, you can still create the pull request.
  • 9 commits
  • 12 files changed
  • 0 commit comments
  • 1 contributor
View
1  CHANGELOG
@@ -35,6 +35,7 @@ Version 1.1.13 work in progress
- Enh: Fixed the check for ajaxUpdate false value in jquery.yiilistview.js as that never happens (mdomba)
- Enh: Requirements checker: added check for Oracle database (pdo_oci extension) and MSSQL (pdo_dblib, pdo_sqlsrv and pdo_mssql extensions) (resurtm)
- Enh: Added CChainedLogFilter class to allow adding multiple filters to a logroute (cebe)
+- Enh: Added support for attribute sanatization following the scheme of validation rules (suralc)
- Chg: MSSQL unit tests updated and actualized, added SQLSRV driver support (resurtm)
- Chg: Added Oracle unit tests (resurtm)
- Chg: Updated CHttpCacheFilter to use dates as specified by RFC 1123 (bramp)
View
7 framework/YiiBase.php
@@ -702,8 +702,8 @@ public static function registerAutoloader($callback, $append=false)
'CMssqlColumnSchema' => '/db/schema/mssql/CMssqlColumnSchema.php',
'CMssqlCommandBuilder' => '/db/schema/mssql/CMssqlCommandBuilder.php',
'CMssqlPdoAdapter' => '/db/schema/mssql/CMssqlPdoAdapter.php',
- 'CMssqlSqlsrvPdoAdapter' => '/db/schema/mssql/CMssqlSqlsrvPdoAdapter.php',
'CMssqlSchema' => '/db/schema/mssql/CMssqlSchema.php',
+ 'CMssqlSqlsrvPdoAdapter' => '/db/schema/mssql/CMssqlSqlsrvPdoAdapter.php',
'CMssqlTableSchema' => '/db/schema/mssql/CMssqlTableSchema.php',
'CMysqlColumnSchema' => '/db/schema/mysql/CMysqlColumnSchema.php',
'CMysqlCommandBuilder' => '/db/schema/mysql/CMysqlCommandBuilder.php',
@@ -730,6 +730,7 @@ public static function registerAutoloader($callback, $append=false)
'CGettextFile' => '/i18n/gettext/CGettextFile.php',
'CGettextMoFile' => '/i18n/gettext/CGettextMoFile.php',
'CGettextPoFile' => '/i18n/gettext/CGettextPoFile.php',
+ 'CCombinedLogFilter' => '/logging/CCombinedLogFilter.php',
'CDbLogRoute' => '/logging/CDbLogRoute.php',
'CEmailLogRoute' => '/logging/CEmailLogRoute.php',
'CFileLogRoute' => '/logging/CFileLogRoute.php',
@@ -739,6 +740,10 @@ public static function registerAutoloader($callback, $append=false)
'CLogger' => '/logging/CLogger.php',
'CProfileLogRoute' => '/logging/CProfileLogRoute.php',
'CWebLogRoute' => '/logging/CWebLogRoute.php',
+ 'CInlineSanitizer' => '/sanitizers/CInlineSanitizer.php',
+ 'CNumberSanitizer' => '/sanitizers/CNumberSanitizer.php',
+ 'CSanitizer' => '/sanitizers/CSanitizer.php',
+ 'CTrimSanitizer' => '/sanitizers/CTrimSanitizer.php',
'CDateTimeParser' => '/utils/CDateTimeParser.php',
'CFileHelper' => '/utils/CFileHelper.php',
'CFormatter' => '/utils/CFormatter.php',
View
206 framework/base/CModel.php
@@ -28,8 +28,15 @@
*/
abstract class CModel extends CComponent implements IteratorAggregate, ArrayAccess
{
+ /**
+ * @var boolean Wether to sanitize the attributes of this instance before validation
+ * rules should be executed
+ * @since 1.1.13
+ */
+ public $sanitizeBeforeValidate=false;
private $_errors=array(); // attribute name => array of errors
private $_validators; // validators
+ private $_sanitizers; // sanitizers
private $_scenario=''; // scenario
/**
@@ -89,6 +96,57 @@ public function rules()
}
/**
+ * Returns the sanitizing rules for attributes.
+ *
+ * This method should be overridden to declare sanitizing rules.
+ * Each rule is an array with the following structure:
+ * <pre>
+ * array('attribute list', 'sanitizer name', 'on'=>'scenario name', ...parameters...)
+ * </pre>
+ * where
+ * <ul>
+ * <li>attribute list: specifies the attributes (separated by commas) to be validated;</li>
+ * <li>sanitizer name: specifies the validator to be used. It can be the name of a model class
+ * method, the name of a built-in validator, or a sanitizer class (or its path alias).
+ * A sanitizing method must have the following signature:
+ * <pre>
+ * // $params refers to sanitizing parameters given in the rule
+ * function sanitizerName($attribute,$params)
+ * </pre>
+ * A built-in sanitizer refers to one of the validators declared in {@link CSanitizer::builtInSanitizers}.
+ * And a sanitizer class is a class extending {@link CSanitizer}.</li>
+ * <li>on: this specifies the scenarios when the sanitizing rule should be performed.
+ * Separate different scenarios with commas. If this option is not set, the rule
+ * will be applied in any scenario that is not listed in "except". Please see {@link scenario} for more details about this option.</li>
+ * <li>except: this specifies the scenarios when the sanitization rule should not be performed.
+ * Separate different scenarios with commas. Please see {@link scenario} for more details about this option.</li>
+ * <li>additional parameters are used to initialize the corresponding sanitizors properties.
+ * Please refer to individal sanitizer class API for possible properties.</li>
+ * </ul>
+ *
+ * The following are some examples:
+ * <pre>
+ * array(
+ * array('attribute', 'trim'),
+ * array('attribute', 'shorten', 'max'=>12),
+ * array('attribute', 'identical', 'as'=>'password2', 'on'=>'register'),
+ * array(attribute', 'authenticate', 'on'=>'login'),
+ * );
+ * </pre>
+ *
+ * Note, in order to inherit rules defined in the parent class, a child class needs to
+ * merge the parent rules with child rules using functions like array_merge().
+ *
+ * @return array sanitization rules to be applied when {@link sanitizationRules()} is called.
+ * @see scenario
+ * @since 1.1.13
+ */
+ public function sanitizationRules()
+ {
+ return array();
+ }
+
+ /**
* Returns a list of behaviors that this model should behave as.
* The return value should be an array of behavior configurations indexed by
* behavior names. Each behavior configuration can be either a string specifying
@@ -151,6 +209,8 @@ public function attributeLabels()
*/
public function validate($attributes=null, $clearErrors=true)
{
+ if($this->sanitizeBeforeValidate)
+ $this->sanitize($attributes, $clearErrors);
if($clearErrors)
$this->clearErrors();
if($this->beforeValidate())
@@ -165,6 +225,41 @@ public function validate($attributes=null, $clearErrors=true)
}
/**
+ * Performs the Sanitization.
+ *
+ * This method executes the sanitization rules as declared in {@link sanitizationRules}.
+ * Only the rules applicable to the current {@link scenario} will be executed.
+ * A rule is considered applicable to a scenario if its 'on' option is not set
+ * or contains the scenario.
+ *
+ * Errors occured during the sanitization can be retrieved via {@link getErrors}.
+ *
+ * @param array $attributes list of attributes that should be sanitized. Defaults to null,
+ * meaning any attribute listed in the applicable sanitization rules should be
+ * validated. If this parameter is given as a list of attributes, only
+ * the listed attributes will be sanitized.
+ * @param boolean $clearErrors whether to call {@link clearErrors} before performing sanitization
+ * @return boolean whether the sanitization is successful without any error.
+ * @see beforeSanitize
+ * @see afterSanitize
+ * @since 1.1.13
+ */
+ public function sanitize($attributes=null, $clearErrors=true)
+ {
+ if($clearErrors)
+ $this->clearErrors();
+ if($this->beforeSanitize())
+ {
+ foreach($this->getSanitizers() as $sanitizer)
+ $sanitizer->sanitize($this,$attributes);
+ $this->afterSanitize();
+ return !$this->hasErrors();
+ }
+ else
+ return false;
+ }
+
+ /**
* This method is invoked after a model instance is created by new operator.
* The default implementation raises the {@link onAfterConstruct} event.
* You may override this method to do postprocessing after model creation.
@@ -192,6 +287,22 @@ protected function beforeValidate()
}
/**
+ * This method is invoked before sanitization starts.
+ * The default implementation calls {@link onBeforeSanitize} to raise an event.
+ * You may override this method to do preliminary checks before sanitization.
+ * Make sure the parent implementation is invoked so that the event can be raised.
+ * @return boolean whether sanitization should be executed. Defaults to true.
+ * If false is returned, the sanitization will stop and the model is considered invalid.
+ * @since 1.1.13
+ */
+ protected function beforeSanitize()
+ {
+ $event=new CModelEvent($this);
+ $this->onBeforeSanitize($event);
+ return $event->isValid;
+ }
+
+ /**
* This method is invoked after validation ends.
* The default implementation calls {@link onAfterValidate} to raise an event.
* You may override this method to do postprocessing after validation.
@@ -201,6 +312,18 @@ protected function afterValidate()
{
$this->onAfterValidate(new CEvent($this));
}
+
+ /**
+ * This method is invoked after sanitization ends.
+ * The default implementation calls {@link onAfterSanitize} to raise an event.
+ * You may override this method to do postprocessing after sanitization.
+ * Make sure the parent implementation is invoked so that the event can be raised.
+ * @since 1.1.13
+ */
+ protected function afterSanitize()
+ {
+ $this->onAfterSanitize(new CEvent($this));
+ }
/**
* This event is raised after the model instance is created by new operator.
@@ -221,6 +344,26 @@ public function onBeforeValidate($event)
}
/**
+ * This event is raised before the sanitization is performed.
+ * @param CModelEvent $event the event parameter
+ * @since 1.1.13
+ */
+ public function onBeforeSanitize($event)
+ {
+ $this->raiseEvent('onBeforeSanitize',$event);
+ }
+
+ /**
+ * This event is raised after the sanitization is performed.
+ * @param CEvent $event the event parameter
+ * @since 1.1.13
+ */
+ public function onAfterSanitize($event)
+ {
+ $this->raiseEvent('onAfterSanitize',$event);
+ }
+
+ /**
* This event is raised after the validation is performed.
* @param CEvent $event the event parameter
*/
@@ -290,6 +433,69 @@ public function createValidators()
}
return $validators;
}
+
+ /**
+ * Returns all the sanitizers declared in the model.
+ * This method differs from {@link getSanitizers} in that the latter
+ * would only return the sanitizers applicable to the current {@link scenario}.
+ * Also, since this method returns a {@link CList} object, you may
+ * manipulate it by inserting or removing sanitizers (useful in behaviors).
+ * For example, <code>$model->sanitizerList->add($newValidator)</code>.
+ * The change made to the {@link CList} object will persist and reflect
+ * in the result of the next call of {@link getValidators}.
+ * @return CList all the validators declared in the model.
+ * @since 1.1.13
+ */
+ public function getSanitizerList()
+ {
+ if($this->_sanitizers===null)
+ $this->_sanitizers=$this->createSanitizers();
+ return $this->_sanitizers;
+ }
+
+ /**
+ * Returns the sanitizers applicable to the current {@link scenario}.
+ * @param string $attribute the name of the attribute whose sanitizers should be returned.
+ * If this is null, the sanitizers for ALL attributes in the model will be returned.
+ * @return array the sanitizers applicable to the current {@link scenario}.
+ * @since 1.1.13
+ */
+ public function getSanitizers($attribute=null)
+ {
+ if($this->_sanitizers===null)
+ $this->_sanitizers=$this->createSanitizers();
+ $sanitizers=array();
+ $scenario=$this->getScenario();
+ foreach($this->_sanitizers as $sanitizer)
+ {
+ if($sanitizer->applyTo($scenario))
+ {
+ if($attribute===null || in_array($attribute,$sanitizer->attributes,true))
+ $sanitizers[]=$sanitizer;
+ }
+ }
+ return $sanitizers;
+ }
+
+ /**
+ * Creates sanitizer objects based on the specification in {@link sanitizationRules}.
+ * This method is mainly used internally.
+ * @return CList sanitizers built based on {@link sanitizationRules()}.
+ * @since 1.1.13
+ */
+ public function createSanitizers()
+ {
+ $sanitizers=new CList;
+ foreach($this->sanitizationRules() as $rule)
+ {
+ if(isset($rule[0],$rule[1])) // attributes, sanitizer name
+ $sanitizers->add(CSanitizer::createSanitizer($rule[1],$this,$rule[0],array_slice($rule,2)));
+ else
+ throw new CException(Yii::t('yii','{class} has an invalid sanitization rule. The rule must specify attributes to be sanitized and the sanitizers name.',
+ array('{class}'=>get_class($this))));
+ }
+ return $sanitizers;
+ }
/**
* Returns a value indicating whether the attribute is required.
View
10 framework/gii/generators/model/templates/default/model.php
@@ -96,7 +96,15 @@ public function rules()
array('<?php echo implode(', ', array_keys($columns)); ?>', 'safe', 'on'=>'search'),
);
}
-
+
+ /**
+ * @return array sanitization rules for the <?php echo $modelClass; ?>-model
+ */
+ public function sanitizationRules()
+ {
+ return array();
+ }
+
/**
* @return array relational rules.
*/
View
41 framework/sanitizers/CInlineSanitizer.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * CInlineSanitizer class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2012 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+/**
+ * CInlineSanitizer represents a sanitizer which is defined as a method in the object being sanitized.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @author Suralc <thesurwaveing@googlemail.com>
+ * @package system.sanitizers
+ * @since 1.1.13
+ */
+class CInlineSanitizer extends CSanitizer
+{
+ /**
+ * @var string the name of the sanitization method defined in the model class
+ */
+ public $method;
+ /**
+ * @var array additional parameters that are passed to the sanitiazion method
+ */
+ public $params;
+
+ /**
+ * Sanitizes the attribute of the object.
+ * If there is any error, the error message is added to the object.
+ * @param CModel $object the object being sanitized
+ * @param string $attribute the attribute being sanitized
+ */
+ protected function sanitizeAttribute($object,$attribute)
+ {
+ $method=$this->method;
+ $object->$method($attribute,$this->params);
+ }
+}
View
128 framework/sanitizers/CNumberSanitizer.php
@@ -0,0 +1,128 @@
+<?php
+/**
+ * CNumberSanatizer class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2012 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+/**
+ * CNumberSanitizer sanotizes an attribute containing a number.
+ *
+ * CNumberSanatizer has a couple of custom settings:
+ * <ul>
+ * <li>{min}: when using {@link tooSmall}, replaced with the lower limit of the number {@link min}.</li>
+ * <li>{max}: when using {@link tooBig}, replaced with the upper limit of the number {@link max}.</li>
+ * <li>{allowEmpty}: Wether to allow an empty attribute. If this is set to false, the empty attribute is replaced with $emptyValue {@link allowEmpty}.</li>
+ * <li>{emptyValue}: If {@link allowEmpty} is set to false this value is used to fill an empty attribute {@link emptyValue}.</li>
+ * <li>{to}: Target type of the sanotization. One of the following values: int, uint, float, ufloat {@link to}.</li>
+ * <li>{fallBackValue}: Value used if attribute cannot be transformed into a number {@link fallBackValue}.</li>
+ * <li>{precision}: precision used while transforming a number to a float {@link max}.</li>
+ * </ul>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @author Suralc <thesurwaveing@googlemail.com>
+ * @package system.sanitizers
+ * @since 1.1.13
+ */
+class CNumberSanitizer extends CSanitizer
+{
+ /**
+ * @var boolean whether the attribute value can be null or empty. Defaults to true,
+ * meaning that if the attribute is empty, it is considered valid.
+ */
+ public $allowEmpty=true;
+ /**
+ * @var integer|float This value is used as a default value if allowEmpty is set to false.
+ */
+ public $emptyValue=0;
+ /**
+ * @var string String indicating the target of the sanitization.
+ * Possible values: int, uint, float, ufloat
+ */
+ public $to='uint';
+ /**
+ * @var mixed If value cannot be casted or modified this value is used.
+ */
+ public $fallBackValue=-1;
+ /**
+ * @var int|float|string Maximum value of the attribute. If value is higher it is lowered to this value.
+ */
+ public $max;
+ /**
+ * @var int|float|string Maximum value of the attribute. If value is higher it is lowered to this value
+ */
+ public $min;
+ /**
+ * @var integer Only in use if $to is a float or ufloat
+ */
+ public $precision=null;
+ /**
+ * @var string the regular expression for matching numbers.
+ */
+ public $numberPattern='/^\s*[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\s*$/';
+
+ /**
+ * Sanitizes the attribute of the object.
+ * If there is any error, the error message is added to the object.
+ * @param CModel $object the object being sanatized
+ * @param string $attribute the attribute being sanatized
+ */
+ protected function sanitizeAttribute($object,$attribute)
+ {
+ if($this->allowEmpty&&empty($object->$attribute))
+ return true;
+ elseif($this->allowEmpty!=true&&empty($object->$attribute))
+ {
+ $object->$attribute=$this->emptyValue;
+ return true;
+ }
+ $value=$object->$attribute;
+ if(preg_match($this->numberPattern,$value)&&!is_int($value))
+ $value=floatval($value);
+ if(!is_numeric($value))
+ {
+ $object->$attribute=$this->fallBackValue;
+ }
+ $value=$this->padToBoundaries($value);
+ $unsinged=stripos($this->to,'u')!==false?true:false;
+ $type=!$unsinged?$this->to:substr($this->to,1);
+ switch((strtolower($type)))
+ {
+ case 'int':
+ $value=intval($value);
+ $value=$unsinged?abs($value):$value;
+ break;
+ case 'float':
+ $value=floatval($value);
+ $value=$unsinged?abs($value):$value;
+ if($this->precision!==null)
+ $value=round($value,$this->precision);
+ break;
+ default:
+ throw new CException(Yii::t('yii', 'Type "{type}" is not supported in {class}',
+ array('{type}'=>(string)$this->to,'{class}'=>get_class($this))));
+ }
+ $object->$attribute=$value;
+ return true;
+ }
+ /**
+ * Pads a value to the upper or lower limit pecified in this sanitizer
+ * @param string $value The value to be assigned
+ */
+ protected function padToBoundaries($value)
+ {
+ if(is_numeric($this->max))
+ {
+ if($value>$this->max)
+ $value=$this->max;
+ }
+ if(is_numeric($this->min)){
+ if($value<$this->min)
+ $value=$this->min;
+ }
+ return $value;
+ }
+}
View
230 framework/sanitizers/CSanitizer.php
@@ -0,0 +1,230 @@
+<?php
+/**
+ * CSanitizer class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2012 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+/**
+ * CSanitizer is the base class for all sanitizors.
+ *
+ * Child classes must implement the {@link sanitizeAttribute} method.
+ *
+ * The following properties are defined in CSanitizer:
+ * <ul>
+ * <li>{@link attributes}: array, list of attributes to be sanitized;</li>
+ * <li>{@link on}: string, in which scenario should the sanitizer be in effect.
+ * This is used to match the 'on' parameter supplied when calling {@link CModel::sanitize}.</li>
+ * </ul>
+ *
+ * When using {@link createSanitizer} to create a sanitizer, the following aliases
+ * are recognized as the corresponding built-in sanitizer classes:
+ * <ul>
+ * <li>trim: {@link CTrimSanitizer}</li>
+ * <li>number: {@link CNumberSanitizer}</li>
+ * </ul>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @author Suralc <thesurwaveing@googlemail.com>
+ * @package system.sanitizers
+ * @since 1.1.13
+ */
+abstract class CSanitizer extends CComponent
+{
+ /**
+ * @var array list of built-in sanitizers (name=>class)
+ */
+ public static $builtInSanitizers=array(
+ 'number'=>'CNumberSanitizer',
+ 'trim'=>'CTrimSanitizer',
+ );
+
+ /**
+ * @var array list of attributes to be sanitized.
+ */
+ public $attributes;
+ /**
+ * @var boolean whether this sanitizion rule should be skipped when there is already a sanitzing
+ * error for the current attribute. Defaults to false.
+ */
+ public $skipOnError=false;
+ /**
+ * @var array list of scenarios that the sanitizer should be applied.
+ * Each array value refers to a scenario name with the same name as its array key.
+ */
+ public $on;
+ /**
+ * @var array list of scenarios that the sanitizer should not be applied to.
+ * Each array value refers to a scenario name with the same name as its array key.
+ */
+ public $except;
+ /**
+ * @var boolean whether attributes listed with this sanitizer should be considered safe for massive assignment.
+ * Defaults to true.
+ */
+ public $safe=true;
+
+ /**
+ * The model the sanitizer is called on.
+ * @var CModel
+ */
+ private $_model;
+
+ /**
+ * Sanitizes a single attribute.
+ * This method should be overridden by child classes.
+ * @param CModel $object the data object being sanitized
+ * @param string $attribute the name of the attribute to be sanitized.
+ */
+ abstract protected function sanitizeAttribute($object,$attribute);
+
+
+ /**
+ * Creates a santizer object.
+ * @param string $name the name or class of the sanitizer
+ * @param CModel $object the data object being sanitized that may contain the inline sanitization method
+ * @param mixed $attributes list of attributes to be sanitized. This can be either an array of
+ * the attribute names or a string of comma-separated attribute names.
+ * @param array $params initial values to be applied to the sanitizers properties
+ * @return CValidator the validator
+ */
+ public static function createSanitizer($name,$object,$attributes,$params=array())
+ {
+ if(is_string($attributes))
+ $attributes=preg_split('/[\s,]+/',$attributes,-1,PREG_SPLIT_NO_EMPTY);
+ if(isset($params['on']))
+ {
+ if(is_array($params['on']))
+ $on=$params['on'];
+ else
+ $on=preg_split('/[\s,]+/',$params['on'],-1,PREG_SPLIT_NO_EMPTY);
+ }
+ else
+ $on=array();
+
+ if(isset($params['except']))
+ {
+ if(is_array($params['except']))
+ $except=$params['except'];
+ else
+ $except=preg_split('/[\s,]+/',$params['except'],-1,PREG_SPLIT_NO_EMPTY);
+ }
+ else
+ $except=array();
+
+ if(method_exists($object,$name))
+ {
+ $sanitizer=new CInlineSanitizer();
+ $sanitizer->attributes=$attributes;
+ $sanitizer->method=$name;
+ $sanitizer->params=$params;
+ if(isset($params['skipOnError']))
+ $sanitizer->skipOnError=$params['skipOnError'];
+ }
+ else
+ {
+ $params['attributes']=$attributes;
+ if(isset(self::$builtInSanitizers[$name]))
+ $className=Yii::import(self::$builtInSanitizers[$name],true);
+ else
+ $className=Yii::import($name,true);
+ $sanitizer=new $className;
+ foreach($params as $name=>$value)
+ $sanitizer->$name=$value;
+ }
+
+ $sanitizer->on=empty($on)?array():array_combine($on,$on);
+ $sanitizer->except=empty($except)?array():array_combine($except,$except);
+ $sanitizer->setModel($object);
+
+ return $sanitizer;
+ }
+
+ /**
+ * Sanitizes the specified object.
+ * @param CModel $object the data object being sanitized
+ * @param array $attributes the list of attributes to be sanitized. Defaults to null,
+ * meaning every attribute listed in {@link attributes} will be santized.
+ */
+ public function sanitize($object,$attributes=null)
+ {
+ if(is_array($attributes))
+ $attributes=array_intersect($this->attributes,$attributes);
+ else
+ $attributes=$this->attributes;
+ foreach($attributes as $attribute)
+ {
+ if(!$this->skipOnError || !$object->hasErrors($attribute))
+ $this->sanitizeAttribute($object,$attribute);
+ }
+ }
+
+ /**
+ * Returns a value indicating whether the sanatizer applies to the specified scenario.
+ * A sanatizer applies to a scenario as long as any of the following conditions is met:
+ * <ul>
+ * <li>the sanatizer's "on" property is empty</li>
+ * <li>the sanatizer's "on" property contains the specified scenario</li>
+ * </ul>
+ * @param string $scenario scenario name
+ * @return boolean whether the sanatizer applies to the specified scenario.
+ */
+ public function applyTo($scenario)
+ {
+ if(isset($this->except[$scenario]))
+ return false;
+ return empty($this->on) || isset($this->on[$scenario]);
+ }
+
+ /**
+ * Adds an error about the specified attribute to the active record.
+ * This is a helper method that performs message selection and internationalization.
+ * @param CModel $object the data object being sanatized
+ * @param string $attribute the attribute being sanatized
+ * @param string $message the error message
+ * @param array $params values for the placeholders in the error message
+ */
+ protected function addError($object,$attribute,$message,$params=array())
+ {
+ $params['{attribute}']=$object->getAttributeLabel($attribute);
+ $object->addError($attribute,strtr($message,$params));
+ }
+
+ /**
+ * Checks if the given value is empty.
+ * A value is considered empty if it is null, an empty array, or the trimmed result is an empty string.
+ * Note that this method is different from PHP empty(). It will return false when the value is 0.
+ * @param mixed $value the value to be checked
+ * @param boolean $trim whether to perform trimming before checking if the string is empty. Defaults to false.
+ * @return boolean whether the value is empty
+ */
+ protected function isEmpty($value,$trim=false)
+ {
+ return $value===null || $value===array() || $value==='' || $trim && is_scalar($value) && trim($value)==='';
+ }
+ /**
+ * Sets the model this sanatizer is based on
+ * @param CModel $value The model this sanatizer is based on.
+ */
+ public function setModel($value)
+ {
+ if($this->_model===null)
+ {
+ if($value instanceof CModel)
+ $this->_model=$value;
+ else
+ throw new CException(Yii::t('yii', 'You may only use a model as sanitization target.'));
+ }
+ }
+ /**
+ * Returns the model used in this sanatizer
+ * @return CModel the model used in this sanatizer
+ */
+ public function getModel()
+ {
+ return $this->_model;
+ }
+}
View
139 framework/sanitizers/CTrimSanitizer.php
@@ -0,0 +1,139 @@
+<?php
+
+/**
+ * CTrimSanitizer class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2012 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+/**
+ * This sanitizer is used to trim an attribute using a given characterlist.
+ *
+ * Sanatizes an attribute using the mode given in {@see CTrimSanatizer::$mode}.
+ * By default trim, ltrim and rtrim are supported, but mode can be used to use
+ * any callable value as trim function. Additionally you may override {@see CTrimSanatizer::trim()}
+ * to use your own function instead of trim, ltrim or rtrim.
+ * Any callable value passed to {@see CTrimSanatizer::$mode} has to support the following signature:
+ * <pre>
+ * string trim(CModel $object, string $attribute, CTrimSanitizer $sanitizer)
+ * </pre>
+ * Your callback has to return the trimmed value.
+ *
+ * The value passed to {@see CTrimSanatizer::$charlist} will be used as second parameter
+ * of phps native 'trim'.
+ *
+ * Configuration of this sanitizer is aviable through the thirs parameter of your callback.
+ *
+ * @author Suralc <thesurwaveing@googlemail.com>
+ * @package system.sanitizers
+ * @since 1.1.13
+ */
+class CTrimSanitizer extends CSanitizer
+{
+ /**
+ * @var string List of trimmable characters.
+ * Defaults to null meaning:
+ * <pre>
+ * " " (ASCII 32 (0x20)), whitespace.
+ * "\t" (ASCII 9 (0x09)), a tab.
+ * "\n" (ASCII 10 (0x0A)), a new line (line feed).
+ * "\r" (ASCII 13 (0x0D)), a carriage return.
+ * "\0" (ASCII 0 (0x00)), the NUL-byte.
+ * "\x0B" (ASCII 11 (0x0B)), a vertical tab.
+ * </pre>
+ */
+ public $charlist=null;
+ /**
+ * @var string|callable
+ */
+ public $mode='trim';
+ /**
+ * @var int Maximum length of the trimmed string. Defaults to 'null' meaning infinite length.
+ */
+ public $length=null;
+ /**
+ * @var array List of supported trimming methods.
+ */
+ private $supportedModes=array('trim','ltrim','rtrim');
+
+ /**
+ * Trims an attribute according to the configuration rules presented in the model.
+ * @param CModel $object The model the attribute belongs to
+ * @param string $attribute Name of the attribute.
+ * @return boolean
+ */
+ protected function sanitizeAttribute($object, $attribute)
+ {
+ $value=(string)$object->$attribute;
+ if(is_string($this->mode)&&in_array(strtolower($this->mode),$this->supportedModes))
+ $object->$attribute=$this->cut($this->trim($value,$this->mode,$this->charlist),$this->length);
+ elseif(is_callable($this->mode))
+ {
+ $trimmedValue=call_user_func_array($this->mode, array($object, $attribute, $this));
+ if($trimmedValue !== false)
+ $object->$attribute=$this->cut($trimmedValue,$this->length);
+ else
+ return false;
+ }
+ else
+ throw new CException(Yii::t('yii','{class}::$mode should be a string or a valid callback',
+ array('{class}'=>get_class($this))));
+ }
+ /**
+ * Trims a string according to the given paramaters
+ * @param string $value The string to be trimmed
+ * @param string $mode The mode the string should be trimmed, defaults to 'trim'. Possible values:
+ * <ul>
+ * <li>trim</li>
+ * <li>rtrim</li>
+ * <li>ltrim</li>
+ * </ul>
+ * @param string $charlist The characters to be trimmed.
+ * Defaults to 'null' using phps default charlist.
+ * @return string The trimmed string
+ * @throws CException
+ */
+ protected function trim($value, $mode='trim', $charlist=null)
+ {
+ switch(strtolower($mode))
+ {
+ case 'trim':
+ if($this->charlist===null)
+ return trim($value);
+ else
+ return trim($value,$this->charlist);
+ break;
+ case 'rtrim':
+ if($this->charlist===null)
+ return rtrim($value);
+ else
+ return rtrim($value,$this->charlist);
+ break;
+ case 'ltrim':
+ if($this->charlist===null)
+ return ltrim($value);
+ else
+ return ltrim($value,$this->charlist);
+ break;
+ default:
+ throw new CException(Yii::t('yii', 'Mode "{mode}" is not supported in {class}',
+ array('{mode}'=>(string)$mode,'{class}'=>get_class($this))));
+ }
+ }
+ /**
+ * Cuts a string to a given length
+ * @param string $value The value to be cut.
+ * @param null|integer $length The max length of the given string.
+ * @return string The cut string.
+ */
+ protected function cut($value,$length=null,$offset=0)
+ {
+ if($length===null)
+ return $value;
+ else
+ return substr($value,$offset,(int)$length);
+ }
+}
View
13 tests/framework/db/data/models2.php
@@ -182,4 +182,17 @@ public function tableName()
{
return 'yii_types';
}
+}
+
+class ModelForSanatizeTest extends CActiveRecord
+{
+ public static function model($class=__CLASS__)
+ {
+ return parent::model($class);
+ }
+
+ public function tableName()
+ {
+ return 'test.users';
+ }
}
View
53 tests/framework/sanitizers/CNumberSanitizerTest.php
@@ -0,0 +1,53 @@
+<?php
+
+class CNumberSanitizerTest extends CTestCase
+{
+ public function getTestModel()
+ {
+ $model = new SanitizeNumberTestModel;
+ $model->int = 45.4231;
+ $model->uint = -234.12;
+ $model->float = "456.33";
+ $model->ufloat = "-65.466434";
+ $model->intNotBelowZero = "-4545.34";
+ return $model;
+ }
+
+ public function testSanitizeAttributes()
+ {
+ $model = $this->getTestModel();
+ $model->sanitize();
+ $this->assertEquals(45, $model->int);
+ $this->assertTrue(is_int($model->int));
+ $this->assertEquals(234, $model->uint);
+ $this->assertTrue(is_int($model->uint));
+ $this->assertEquals(430.23, $model->float);
+ $this->assertTrue(is_float($model->float));
+ $this->assertEquals(65.47, $model->ufloat);
+ $this->assertTrue(is_float($model->ufloat));
+ $this->assertEquals(0, $model->intNotBelowZero);
+ $this->assertEquals(45, $model->emptyValue);
+ }
+}
+
+class SanitizeNumberTestModel extends CFormModel
+{
+ public $int;
+ public $uint;
+ public $float;
+ public $ufloat;
+ public $intNotBelowZero;
+ public $emptyValue;
+
+ public function sanitizationRules()
+ {
+ return array(
+ array('int', 'number', 'to'=>'int'),
+ array('uint', 'number', 'to'=>'uint'),
+ array('float', 'number', 'to'=>'float', 'max'=>430.23),
+ array('ufloat', 'number', 'to'=>'ufloat', 'precision'=>2),
+ array('intNotBelowZero', 'number', 'min'=>0),
+ array('emptyValue', 'number', 'allowEmpty'=>false, 'emptyValue'=>45),
+ );
+ }
+}
View
113 tests/framework/sanitizers/CSanitizerTest.php
@@ -0,0 +1,113 @@
+<?php
+
+class CSanitizerTest extends CTestCase
+{
+ /**
+ * @var CModel
+ */
+ private $model;
+ public function setUp()
+ {
+ $this->model = new SanitizeTestModel();
+ $this->model->foo = " Some String ";
+ $this->model->bar = "\nRemove Only Left Newline\n";
+ $this->model->foobar = "some value";
+ }
+ /**
+ *
+ * @covers CModel::sanitize
+ */
+ public function testSanitize()
+ {
+ $this->model->sanitize();
+ $this->assertEquals("Some String", $this->model->foo);
+ $this->assertEquals("Remove Only Left Newline\n", $this->model->bar);
+ $this->assertEquals("succeeded", $this->model->foobar);
+ }
+
+ public function testScenarios()
+ {
+ $model = new SanitizerScenariosTestModel();
+ $testmodel = clone $model;
+ //scenario 1
+ $testmodel->setScenario('scenario1');
+ $testmodel->sanitize();
+ $this->assertEquals('title', $testmodel->title);
+ $this->assertEquals('firstName', $testmodel->firstName);
+ $this->assertEquals("\nbirthday", $testmodel->birthday);
+ $testmodel = clone $model;
+ // scenario 3
+ $testmodel->setScenario('scenario3');
+ $testmodel->sanitize();
+ $this->assertEquals("\nfirstName", $testmodel->firstName);
+ $this->assertEquals('nickName', $testmodel->nickName);
+
+ }
+}
+
+class SanitizeTestModel extends CFormModel
+{
+ public $foo;
+ public $bar;
+ public $foobar;
+ public $barfoo;
+
+ public function sanitizationRules()
+ {
+ return array(
+ array('foo', 'trim'),
+ array('bar', 'trim', 'mode'=>'ltrim'),
+ array('foobar', 'sanatizeFooBar'),
+ );
+ }
+
+ public function sanatizeFooBar($attribute, $params)
+ {
+ $this->foobar = 'succeeded';
+ return true;
+ }
+}
+
+class SanitizerScenariosTestModel extends CFormModel
+{
+ public $title = "\ntitle";
+ public $firstName = "\nfirstName";
+ public $lastName = "\nlastName";
+ public $patronymic = "\npatronymic";
+ public $nickName = "\nnickName";
+
+ public $login = "\nlogin";
+ public $password = "\npassword";
+
+ public $birthday = "\nbirthday";
+
+ public function sanitizationRules()
+ {
+ return array(
+ // scenario1
+ array('title', 'trim', 'on'=>'scenario1'),
+
+ // scenario1 and scenario2
+ array('firstName', 'trim', 'except'=>'scenario3, scenario4'),
+
+ // scenario1, scenario2 and scenario3
+ array('lastName', 'trim', 'on'=>array('scenario1', 'scenario2', 'scenario3')),
+
+ // scenario1, scenario2 and scenario3
+ array('patronymic', 'trim', 'except'=>array('scenario4')),
+
+ // scenario1 and scenario3
+ array('nickName', 'trim', 'on'=>array('scenario1', 'scenario2', 'scenario3'), 'except'=>'scenario2'),
+
+ // scenario1, scenario2, scenario3 and scenario4
+ array('login', 'trim'),
+
+ // useless rule
+ array('password', 'trim', 'on'=>'scenario1,scenario2,scenario3,scenario4',
+ 'except'=>array('scenario1', 'scenario2', 'scenario3', 'scenario4')),
+
+ // scenario2
+ array('birthday', 'trim', 'on'=>'scenario2', 'except'=>'scenario3'),
+ );
+ }
+}
View
67 tests/framework/sanitizers/CTrimSanitizerTest.php
@@ -0,0 +1,67 @@
+<?php
+
+class CTrimSanitizerTest extends CTestCase
+{
+ public function getTestModel()
+ {
+ $model = new SanitizeTrimTestModel;
+ $model->foo = "\nfoo\n";
+ $model->bar = "\r\n this is bar\n";
+ $model->foobar = 'foobar';
+ $model->barfoo = 'barfoo';
+ $model->barfood = "\r\nbarfood\n";
+ return $model;
+ }
+
+ public function testSanitizeAttribute()
+ {
+ $model = $this->getTestModel();
+ $model->sanitize();
+ $this->assertEquals('foo',$model->foo);
+ $this->assertEquals("this is bar\n",$model->bar);
+ $this->assertEquals('succeeded', $model->foobar);
+ $this->assertEquals('succeeded2', $model->barfoo);
+ $this->assertEquals("\r\nbarfood", $model->barfood);
+ $this->assertEquals('trimmed', $model->callback);
+ }
+}
+
+class SanitizeTrimTestModel extends CFormModel
+{
+ public $foo;
+ public $bar;
+ public $barfood;
+ public $foobar;
+ public $barfoo;
+ public $callback;
+
+ public function sanitizationRules()
+ {
+ return array(
+ array('foo', 'trim'),
+ array('bar', 'trim', 'mode'=>'ltrim'),
+ array('barfood', 'trim', 'mode'=>'rtrim'),
+ array('foobar', 'sanatizeFooBar'),
+ array('barfoo', 'sanatizeBarFoo'),
+ /*
+ * Bad example. Should be another class or a closure in realworld.
+ */
+ array('callback', 'trim', 'mode'=>array($this, 'myTrim')),
+ );
+ }
+ public function myTrim($model, $attribute, $sanitizer)
+ {
+ return 'trimmed';
+ }
+ public function sanatizeFooBar($attribute, $params)
+ {
+ $this->foobar = 'succeeded';
+ return true;
+ }
+
+ public function sanatizeBarFoo($attribute, $params)
+ {
+ $this->$attribute='succeeded2';
+ return true;
+ }
+}

No commit comments for this range

Something went wrong with that request. Please try again.