Yii 1.1: input

The suite you need to clean the input coming from users
60 followers

This component is everything you need in order to be sure that the input coming from your users is santitized and the data is safe.
It wraps HtmlPurifier and Codeigniter Security class in a single component that does an awesome job.
Regarding Codeigniter Security class, it has the best xss filter that i know of(excepting html purifier) and it is very fast (comparing to html purifier).
Why including both you may ask, well, the answer is simple, the HtmlPurifier being a large and kind of slow library, it is used only for HTML content cleaning, say a textarea from CKEDITOR or TINYMCE, while Codeigniter XSS filter is used for any other input type because it is way faster and does the job as it should.

Note

This extension is not meant to protect you against sql injection, use Yii's param binding feature for that.

Requirements

Yii 1.1.x

Usage

Say we have a model having a CKEDITOR textarea and other text fields that doesn't allow any html content. We need to use html purifier to be sure the CKEDITOR textarea is treated correctly, but we also need to be sure that the other fields are stripped of html and also cleaned so that the cannot contain dangerous data.

if(isset($_POST['Example']))  
{
    $purify=array('content');  
    foreach($_POST['Example'] AS $key=>$value)  
    {  
        if(in_array($key, $purify))  
            $_POST['Example'][$key]=Yii::app()->input->purify($value);  
        else  
            $_POST['Example'][$key]=Yii::app()->input->stripClean($value);  
    }  
 
    $model->attributes=$_POST['Example'];  
 
    if($model->save())  
        $this->redirect(array('view','id'=>(int)$model->id));  
}

In case our model doesn't have a textarea having HTML content, we can just clean everything from one move:

if(isset($_POST['Example']))  
{
 
    // this will apply stripTags() then xssClean() methods to the array.  
    $_POST['Example']=Yii::app()->input->stripClean($_POST['Example']);  
 
    // also you can do:  
    $_POST['Example']=Yii::app()->input->xssClean($_POST['Example']);      
 
    $model->attributes=$_POST['Example'];  
 
    if($model->save())  
        $this->redirect(array('view','id'=>(int)$model->id));  
}

Handling $_GET and $_POST. Say you want to get a $_GET/$_POST variable and use it:

$post=Yii::app()->input->post('username');  
$get=Yii::app()->input->get('username');

In both cases, the $_POST['username'] and $_GET['username'] are sanitized and returned.

Available methods

/*    
*   1) HtmlPurifier Filter.  
*   Method: purify($str);
*/  
$clean=Yii::app()->input->purify($string);    
$clean=Yii::app()->input->purify($array);  
 
/*  
*   2) XssClean Filter  
*   Method: xssClean($str);
*   This will use the Codeigniter Xss Filter to clean the content   
*/  
$clean=Yii::app()->input->xssClean($string);  
$clean=Yii::app()->input->xssClean($array);  
 
/*  
*   3) stripTags($str, $encode=false)  
*   This is a wrapper for strip_tags but it also supports an array as it's param  
*/  
$clean=Yii::app()->input->stripTags($string);  
$clean=Yii::app()->input->stripTags($array);  
 
/*  
*   4) stripClean($str)  
*   This will use the above stripTags() method, then the xssClean() method.  
*/  
$clean=Yii::app()->input->stripClean($string);  
$clean=Yii::app()->input->stripClean($array);  
 
/*
*   5) stripCleanEncode($str)  
*   Similar to the above stripClean() method, only it also encodes the input  
*/  
$clean=Yii::app()->input->stripCleanEncode($string);  
$clean=Yii::app()->input->stripCleanEncode($array);  
 
/*  
*   6) encode($str)  
*   A wrapper for CHtml::encode() but also can take an array as param  
*/  
$clean=Yii::app()->input->encode($string);  
$clean=Yii::app()->input->encode($array);  
 
/*  
*   7) get($str, $defaultValue='', $xssClean=true)  
*   The get() method will fetch a $_GET item, clean and return it
*/  
$clean=Yii::app()->input->get($string);  
 
/*  
*   8) post($str, $defaultValue='', $xssClean=true)  
*   The post() method will fetch a $_POST item, clean and return it
*/  
$clean=Yii::app()->input->post($string);  
 
/*  
*   9) getPost($str, $defaultValue='', $xssClean=true)  
*   The getPost() method will try to fetch a $_GET item, if it doesn't exists, it'll try a $_POST item.  
*   The returned content is cleaned.
*/  
$clean=Yii::app()->input->getPost($string);

Installation:

1)
Extract the archive and paste the contents of the "protected" folder from within the archive over your project protected folder.
The archive protected folder contains :
/config/htmlpurifier.php
/components/CmsInput.php
/vendors/Codeigniter/CI_Security.php


Note on htmlpurifier.php from config folder.
This file is the configuration for HtmlPurifier, so if you want to add extra configuration for the purifier, do it in this file.


2)
Open main.php and make it look like:

'preload'=>array('log', 'input'),  
'components'=>array(  
    [...]  
    'input'=>array(   
            'class'         => 'CmsInput',  
            'cleanPost'     => false,  
            'cleanGet'      => false,   
        ),
    [...]  
),

The component has the ability to be used as a global cleaning tool, so that if you set:

'input'=>array(   
            'class'         => 'CmsInput',  
            'cleanPost'     => true,  
            'cleanGet'      => true,  
        ),

The $_GET/$_POST will be cleaned right when the application starts, at the onBeginRequest event.
In case you use this approach (i wouldn't recommend it, but there are cases when you might need it) you should know that the $_GET/$_POST are cleaned using Yii::app()->input->xssClean() which might remove HTML markup that you want to keep. If this happens, you have following methods available to access the original global arrays:

Yii::app()->input->getOriginalPost();//returns the original, uncleaned $_POST array()  
Yii::app()->input->getOriginalGet();//returns the original, uncleaned $_GET array()

Changelog

VERSION 1.1

  • Added public $cleanMethod, which allows to specify which filter should be used to clean globals.You can use the following methods for cleaning:

->stripCleanEncode();
->stripTags();
->stripClean(); //default one
->xssClean();
->encode();
->purify();
->cleanEncode();
->stripEncode();

  • Added stripEncode method, which will strip tags and encode.
  • Added cleanEncode method that will xssClean and encode
  • Added decode method to decode a string/array
  • post/get methods can now retrieve the entire array at once
  • getOriginalPost()/getOriginalGet() can retrieve a single key or the entire array
  • Fixed a bug in the encode method
  • Added logging for global filtering
  • The cleaning of the globals is now set to true by default, it is safer this way
  • Other various changes.

Changelog for 1.2

  • added getQuery(), a wrapper for get() to be more yii like.
  • getPost will now retrieve a value from $_POST, being a post() wrapper to be more yii like.
  • fixed a bug in get/post where if the $defaultValue was set and the variable didn't existed  it would return an empty string(thanks to Wiseon3 [http://www.yiiframework.com/user/13664/] who pointed it out)
  • logging will occur just in debug mode from now on.
  • changed the default cleaning method to from stripCleanEncode to stripClean

This is a pretty large component, so it might take a while to fully understand how it works, but in the end, it is a tool that is needed to be sure the user input is sanitized and clean.

Also, worth taking a look inside the CmsInput.php file to understand it better.

Total 12 comments

#16334 report it
zitter at 2014/02/11 07:53pm
Little change

Me too, I need allowed tags sometimes. So, I've added

public $allowedTags = '';

property, then I've changed stripTags() like this:

public function stripTags($str, $encode=false, $allowed = '')
    {
        if(is_array($str))
        {
            foreach($str AS $k=>$v)
                $str[$k]=$this->stripTags($v, $encode, $this->allowedTags);
            return $str;
        }
        $str=trim(strip_tags($str,$this->allowedTags));
 
        if($encode)
            $str=$this->encode($str);
        return $str;
    }

Finally, I can use this syntax:

Yii::app()->input->allowedTags = '<tag1><tag2>';
Yii::app()->input->stripTags($htmlToPurify);
#15382 report it
Daniel at 2013/11/03 11:16pm
input + redactor

I am using redactor for field content of my model. Below is the actionCreate method,

public function actionCreate() {
        $model = new Post;
 
        // Uncomment the following line if AJAX validation is needed
        // $this->performAjaxValidation($model);
 
        if (isset($_POST['Post'])) {
            $model->attributes = $_POST['Post'];
 
            // Get the original `content` and putify it
            $oriPost = Yii::app()->input->getOriginalPost('Post');
            $model->content = Yii::app()->input->purify($oriPost['content']);
            $model->content = Yii::app()->input->xssClean($model->content);
 
            if ($model->save()) {
                $this->redirect(array('view', 'id' => $model->id));
            }
        }
 
        $this->render('create', array(
            'model' => $model,
        ));
    }

I purify and xssClean in order to get a save content. However, when I set the style (set size, float, margin, etc) of an image, I got a problem. After click create, style attribute of the image will not be saved. It seems that purify and/or the xssClean method has deleted it.

Any help to use which method? Thank you in advance.

Cheers,

Daniel

#10726 report it
Boaz at 2012/11/19 09:02am
Documentation bug

Hi,

An update to the documentation is needed: getPost() now does not query GET then POST if it didn't find the value in GET. Rather, it checks only in POST. The documentation above says otherwise, probably reflecting past API and I guess it better be updated.

Thanks for this extension!

#6780 report it
twisted1919 at 2012/02/05 05:37am
...

Ah yes, you are right, i modified the 1.2 archive and uploaded it again, this time with !empty($value) condition.

#6776 report it
Wiseon3 at 2012/02/04 08:46am
Bug when using stripClean as the $cleanMethod

@twisted1919 The bug is still present in the new version. Please note that in the code I posted there was an extra condition in the if for post() and get(), namely && !empty($value).

Without this condition you still get an empty string instead of NULL, because applying the function strip_tags() to a NULL element returns an empty string.

#6772 report it
twisted1919 at 2012/02/03 07:44pm
Thanks

@Wiseon3 - Thanks for pointing this out. I adjusted the file and uploaded a new version with a few other changes (see changelog).
Please let me know in case you find something else.

#6770 report it
Wiseon3 at 2012/02/03 05:51pm
Bug when using stripClean as the $cleanMethod

I found a small bug when using stripClean as the $cleanMethod, namely if you have the $defaultValue=NULL and you get() or post() a variable which doesn't exist it will return an empty string instead of $defaultValue which is set as NULL. To fix it replace in function get() at the end:

if($clean===true && $this->cleanGetCompleted===false)
            return $this->$cleanMethod(Yii::app()->request->getQuery($key, $defaultValue));
        return Yii::app()->request->getQuery($key, $defaultValue);

with

$value = Yii::app()->request->getQuery($key, $defaultValue);
        if($clean===true && $this->cleanGetCompleted===false && !empty($value))
            return $this->$cleanMethod($value);
        return $value;

And in function post() at the end:

if($clean===true && $this->cleanPostCompleted===false)
            return $this->$cleanMethod(Yii::app()->request->getPost($key, $defaultValue));
        return Yii::app()->request->getPost($key, $defaultValue);

with

$value = Yii::app()->request->getPost($key, $defaultValue);
        if($clean===true && $this->cleanPostCompleted===false && !empty($value))
            return $this->$cleanMethod($value);
        return $value;
#6285 report it
matricks at 2011/12/25 07:10am
Very nice!

Thank you for this exceptionally extension.

I changed a little, because sometime I need to allow some tags when I use ->stripTags:

public function stripTags($str, $encode=false, $allowed=false)
    {
        if(is_array($str))
        {
            foreach($str AS $k=>$v) 
                $str[$k]=$this->stripTags($v, $encode, $allowed);
            return $str;
        }
    $str=trim(strip_tags($str, $allowed));
 
        if($encode) 
            $str=$this->encode($str);
        return $str;              
    }
#6046 report it
twb at 2011/12/07 09:32pm
thank you boss!

:)

#6040 report it
twisted1919 at 2011/12/07 10:05am
Component updated.

The component has been updated, please take the time and update your files with the new ones and report any bug you might find.
Thanks.

#4908 report it
twisted1919 at 2011/08/27 04:40pm
Thanks

thanks for the kind words, i really appreciate :)

#4826 report it
hollyii at 2011/08/19 01:10pm
Fantastic!

Thank you for sharing your terrific extension. I've looked at several different options for this absolutely necessary functionality, and I decided to go with yours. I appreciate the flexibility your extension provides.

Good work!

Leave a comment

Please to leave your comment.

Create extension