Yii Framework Forum: Need Help With File Upload Client Validation - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Need Help With File Upload Client Validation Rate Topic: -----

#1 User is offline   Ch3Pz 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 5
  • Joined: 19-October 11

Posted 17 October 2012 - 12:33 AM

Hi,

I need to enable file upload validation on clientside (to check file extension, maxsize, etc)
I tried setting 'enableClientValidation' => true, but no effect.

Here's my code snippet

model rules:
array('uploadedfile1', 'file', 
	'allowEmpty'=>false,
	'enableClientValidation' => true,
	'types'=>'jpg,jpeg,gif,png',
	'maxSize' => 1024 * 1024 * 1, // 1MB
), 


in the view file:
<?php $form=$this->beginWidget('bootstrap.widgets.TbActiveForm',array(
	'id'=>'users-form',
	'type'=>'horizontal',
	'enableClientValidation'=>true,
	'enableAjaxValidation'=>false,
	'clientOptions' => array(
	'validateOnSubmit'=>true,
	'validateOnType'=>false,
	'validateOnChange'=>false,
	)
)); 

....

<?php echo $form->fileFieldRow($model, 'uploadedfile1'); ?>

....

?>



Any Help? Thanks

fyi: there is no uploadedfile1 field in the database, it's just a variable in the class
1

#2 User is offline   felipe_Brz 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 6
  • Joined: 02-January 12
  • Location:Rio de Janeiro - Brazil

Posted 17 October 2012 - 12:42 PM

i think i'm having that same issue...

but i've never done file uploading with yii so I might be doing something wrong

will post here if I learn something...

EDIT

don't know whether it will help you but,

    'stateful' => true,
    'htmlOptions' => array('enctype' => 'multipart/form-data'),


is recommended as options for your activeform
0

#3 User is offline   shahdoost 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 14
  • Joined: 30-March 12

Posted 25 October 2012 - 10:51 AM

The problem is a little bit deeper than what you think,
Unfortunately clientValidateAttribute has not been implemented on CFileValidator, so the only solution is to implement the method all by yourself and it's like a piece of cake on the top of mount Everest

Good luck writing js ;)
0

#4 User is offline   shahdoost 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 14
  • Joined: 30-March 12

Posted 27 October 2012 - 05:09 AM

ok, i have just wrote the method to work on client side, here is the code

you must copy the following code into the CFileValidator class at framework/validators/CFileValidator.php

it checks the file extension and emptiness and has been tested on IE7, Firefox, Chrome and opera (i hope it saves a few hours of your precious time ;) )

    
   /**
     * Returns the JavaScript needed for performing client-side validation.
     * @param CModel $object the data object being validated
     * @param string $attribute the name of the attribute to be validated.
     * @return string the client-side validation script.
     * @see CActiveForm::enableClientValidation
     * @since 1.1.7
     */
    public function clientValidateAttribute($object, $attribute)
    {
        $js = '';

        if (!$this->allowEmpty) {

            $message = $this->message;
            if ($message == null)
                $message = Yii::t('yii', '{attribute} cannot be blank.');

            $message = strtr($message, array(
                '{attribute}' => $object->getAttributeLabel($attribute),
            ));
            $js .= '
            if($.trim(value)==""){messages.push(' . CJSON::encode($message) . ');}
            ';
        }

        if ($this->types !== null) {
            if (is_string($this->types))
                $types = preg_split('/[\s,]+/', strtolower($this->types), -1, PREG_SPLIT_NO_EMPTY);
            else
                $types = $this->types;

            $message = $this->message;
            if ($message == null)
                $message = Yii::t('yii', 'The file "{file}" cannot be uploaded. Only files with these extensions are allowed: {extensions}.');
            $message = strtr($message, array(
                '{file}' => ':file',
                '{extensions}' => implode(', ', $types),
            ));

            $js .= "
            if(['" . implode("','", $types) . "'].indexOf($.trim(value).split('.').pop().toLowerCase()) == -1)
            {
                messages.push('" . $message . "'.replace(':file', $.trim(value)));
            }
            ";
        }
        return $js;
    }

2

#5 User is offline   Andres Felipe Diaz 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 12
  • Joined: 13-August 12

Posted 12 July 2013 - 05:50 PM

View Postshahdoost, on 27 October 2012 - 05:09 AM, said:

ok, i have just wrote the method to work on client side, here is the code

you must copy the following code into the CFileValidator class at framework/validators/CFileValidator.php

it checks the file extension and emptiness and has been tested on IE7, Firefox, Chrome and opera (i hope it saves a few hours of your precious time ;) )

    
   /**
     * Returns the JavaScript needed for performing client-side validation.
     * @param CModel $object the data object being validated
     * @param string $attribute the name of the attribute to be validated.
     * @return string the client-side validation script.
     * @see CActiveForm::enableClientValidation
     * @since 1.1.7
     */
    public function clientValidateAttribute($object, $attribute)
    {
        $js = '';

        if (!$this->allowEmpty) {

            $message = $this->message;
            if ($message == null)
                $message = Yii::t('yii', '{attribute} cannot be blank.');

            $message = strtr($message, array(
                '{attribute}' => $object->getAttributeLabel($attribute),
            ));
            $js .= '
            if($.trim(value)==""){messages.push(' . CJSON::encode($message) . ');}
            ';
        }

        if ($this->types !== null) {
            if (is_string($this->types))
                $types = preg_split('/[\s,]+/', strtolower($this->types), -1, PREG_SPLIT_NO_EMPTY);
            else
                $types = $this->types;

            $message = $this->message;
            if ($message == null)
                $message = Yii::t('yii', 'The file "{file}" cannot be uploaded. Only files with these extensions are allowed: {extensions}.');
            $message = strtr($message, array(
                '{file}' => ':file',
                '{extensions}' => implode(', ', $types),
            ));

            $js .= "
            if(['" . implode("','", $types) . "'].indexOf($.trim(value).split('.').pop().toLowerCase()) == -1)
            {
                messages.push('" . $message . "'.replace(':file', $.trim(value)));
            }
            ";
        }
        return $js;
    }



Hello All,

Thank you very much for your contributions. This has helped us solved the problem to validate the file rules without having to actually send it to the server.

Shahdoost, thanks for your code. We did some additional things that helped us and we want to share back.

  • We created an Extension class that extends from CFileValidator so that we did not need to hack the framework
  • We changed the message for the types to $this->wrongType to get the appropriate message from our rules
  • We added another method to validate the file size. Note: This may only work on certain browsers (In other words..not in explorer)


class EFileValidator extends CFileValidator {

    /**
     * Returns the JavaScript needed for performing client-side validation.
     * @param CModel $object the data object being validated
     * @param string $attribute the name of the attribute to be validated.
     * @return string the client-side validation script.
     * @see CActiveForm::enableClientValidation
     * @since 1.1.7
     */
    public function clientValidateAttribute($object, $attribute) {
        $js = '';

        if (!$this->allowEmpty) {

            $message = $this->message;
            if ($message == null)
                $message = Yii::t('yii', '{attribute} cannot be blank.');

            $message = strtr($message, array(
                '{attribute}' => $object->getAttributeLabel($attribute),
                    ));
            $js .= '
            if($.trim(value)==""){messages.push(' . CJSON::encode($message) . ');}
            ';
        }

        if ($this->types !== null) {
            if (is_string($this->types))
                $types = preg_split('/[\s,]+/', strtolower($this->types), -1, PREG_SPLIT_NO_EMPTY);
            else
                $types = $this->types;

            $message = $this->wrongType;
            if ($message == null)
                $message = Yii::t('yii', 'The file "{file}" cannot be uploaded. Only files with these extensions are allowed: {extensions}.');
            $message = strtr($message, array(
                '{file}' => ':file',
                '{extensions}' => implode(', ', $types),
                    ));

            $js .= "
            if(['" . implode("','", $types) . "'].indexOf($.trim(value).split('.').pop().toLowerCase()) == -1)
            {
                messages.push('" . $message . "'.replace(':file', $.trim(value)));
            }
            ";
        }

        /**
         * Check the maxfile size setting
         */
        if ($this->maxSize !== null) {
            $message = $this->tooLarge;
            
            $inputId = get_class($object)."_".$attribute;
            
            $js .= "
                var fileSize = $('#$inputId')[0].files[0].size; 
                if(fileSize>$this->maxSize){
                    messages.push('" . $message . "');
                }
                ";
        }
        return $js;
    }

}


After this was done, we did our rules and worked like a charm.

array('photoFile','ext.fileValidatorOnSteroids.validators.EFileValidator','types'=>'jpg,gif,png,jpeg','maxSize'=>5242880,
                "tooLarge"=>"Please choose a file with size up to 5MB",
                "wrongType"=>"Your photo must be a jpg,gif or png.",
                "enableClientValidation"=>true
                )

Andrés Felipe Díaz
Andrés Felipe Díaz Digital Geek Blog Trickortip.com
My LinkedIn Profile
0

#6 User is offline   paskuale 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 349
  • Joined: 30-December 11
  • Location:Italy, Bari

Posted 31 July 2013 - 06:25 PM

Hi, I try it, seems don't work :(

I forgot to write in the form :
echo $form->error($model, attributeName);



many thanks :)
0

#7 User is offline   paskuale 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 349
  • Joined: 30-December 11
  • Location:Italy, Bari

Posted 02 August 2013 - 03:41 AM

Hi, I've in my view (CActiveForm) 3 fields :

<input type="file"...>   <!- binaryfile -->
<input type="password"...>
<input type="repeat_password"...>




my model rules here :
public function rules()
    {
        // NOTE: you should only define rules for those attributes that
        // will receive user inputs.
        return array(
            array('binaryfile','ext.validators.EFileValidator',
                'types'=>'jpg,gif,png,jpeg',
                'maxSize'=>5242880,
                "tooLarge"=>"Please choose a file with size up to 5MB",
                "wrongType"=>"Your photo must be a jpg,gif or png .",
                "allowEmpty" => true,
                "enableClientValidation"=>true
                ),

            array('new_password, new_password_repeat','required', 'on'=>'create',"enableClientValidation"=>true ),
            array('new_password','match', 'pattern'=>'#^[0-9A-Za-z]+$#', 'message'=>'Only the following characters are allowed: 0-9 A-Z a-z',"enableClientValidation"=>true ),
            array('new_password','length','max'=>25,"enableClientValidation"=>true),   // PW only 20 Chars
            array('new_password','length','min'=>6,"enableClientValidation"=>true),    // PW min 6 Chars
            array('new_password','compare', 'compareAttribute'=>'new_password_repeat',"enableClientValidation"=>true),//  -> PASSWORD REPEAT
            array('new_password, new_password_repeat','safe'),        //  -> PASSWORD REPEA
           
            array('personale_id', 'numerical', 'integerOnly'=>true),
            
            array('id, fileName, fileType, fileSize', 'safe'),
            array('id, personale_id, fileName, fileType, fileSize', 'safe', 'on'=>'search'),            
        );
    }


if I select a file the ClientValidation works for all three... if ignore it and put a password, the form is submitted ... :blink:
0

#8 User is offline   Sami Ghnaim 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 3
  • Joined: 08-July 13

Posted 28 August 2013 - 07:47 AM

View PostAndres Felipe Diaz, on 12 July 2013 - 05:50 PM, said:

Hello All,

Thank you very much for your contributions. This has helped us solved the problem to validate the file rules without having to actually send it to the server.

Shahdoost, thanks for your code. We did some additional things that helped us and we want to share back.

  • We created an Extension class that extends from CFileValidator so that we did not need to hack the framework
  • We changed the message for the types to $this->wrongType to get the appropriate message from our rules
  • We added another method to validate the file size. Note: This may only work on certain browsers (In other words..not in explorer)


class EFileValidator extends CFileValidator {

    /**
     * Returns the JavaScript needed for performing client-side validation.
     * @param CModel $object the data object being validated
     * @param string $attribute the name of the attribute to be validated.
     * @return string the client-side validation script.
     * @see CActiveForm::enableClientValidation
     * @since 1.1.7
     */
    public function clientValidateAttribute($object, $attribute) {
        $js = '';

        if (!$this->allowEmpty) {

            $message = $this->message;
            if ($message == null)
                $message = Yii::t('yii', '{attribute} cannot be blank.');

            $message = strtr($message, array(
                '{attribute}' => $object->getAttributeLabel($attribute),
                    ));
            $js .= '
            if($.trim(value)==""){messages.push(' . CJSON::encode($message) . ');}
            ';
        }

        if ($this->types !== null) {
            if (is_string($this->types))
                $types = preg_split('/[\s,]+/', strtolower($this->types), -1, PREG_SPLIT_NO_EMPTY);
            else
                $types = $this->types;

            $message = $this->wrongType;
            if ($message == null)
                $message = Yii::t('yii', 'The file "{file}" cannot be uploaded. Only files with these extensions are allowed: {extensions}.');
            $message = strtr($message, array(
                '{file}' => ':file',
                '{extensions}' => implode(', ', $types),
                    ));

            $js .= "
            if(['" . implode("','", $types) . "'].indexOf($.trim(value).split('.').pop().toLowerCase()) == -1)
            {
                messages.push('" . $message . "'.replace(':file', $.trim(value)));
            }
            ";
        }

        /**
         * Check the maxfile size setting
         */
        if ($this->maxSize !== null) {
            $message = $this->tooLarge;
            
            $inputId = get_class($object)."_".$attribute;
            
            $js .= "
                var fileSize = $('#$inputId')[0].files[0].size; 
                if(fileSize>$this->maxSize){
                    messages.push('" . $message . "');
                }
                ";
        }
        return $js;
    }

}


After this was done, we did our rules and worked like a charm.

array('photoFile','ext.fileValidatorOnSteroids.validators.EFileValidator','types'=>'jpg,gif,png,jpeg','maxSize'=>5242880,
                "tooLarge"=>"Please choose a file with size up to 5MB",
                "wrongType"=>"Your photo must be a jpg,gif or png.",
                "enableClientValidation"=>true
                )




Nice one it's help me but on

              $js .= "
                var fileSize = $('#$inputId')[0].files[0].size; 
                if(fileSize>$this->maxSize){
                    messages.push('" . $message . "');
                }
                ";

It must be

              $js .= "
                if ($('#$inputId')[0].files[0]){
                    var fileSize = $('#$inputId')[0].files[0].size; 
                    if(fileSize>$this->maxSize){
                        messages.push('" . $message . "');
                    }
                }
                ";


If the user not upload the file the js not work.

Regards,
Sami.
0

#9 User is offline   rosinghal 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 18
  • Joined: 05-March 13
  • Location:India

Posted 04 October 2013 - 05:37 AM

Awesome!! I was looking for this only..
Just one little bug..when allowEmpty is false and no file is uploaded in form, its gives "file type" error.
So change this
if(['" . implode("','", $types) . "'].indexOf($.trim(value).split('.').pop().toLowerCase()) == -1)

to
if(['" . implode("','", $types) . "'].indexOf($.trim(value).split('.').pop().toLowerCase()) == -1".($this->allowEmpty?" && $.trim(value)!=''":'').")

Xtendify - A marketplace for plugins and themes.
0

#10 User is offline   AndrewM 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 13
  • Joined: 27-March 12

Posted 24 October 2013 - 09:38 PM

Another minor problem:
            $message = $this->tooLarge;

should be:
            $message=$this->tooLarge!==null?$this->tooLarge : Yii::t('yii','The file is too large. Its size cannot exceed {limit} bytes.');
            $message = strtr($message, array(
                '{limit}' => $this->getSizeLimit()
                ));


Also don't forget to set enableClientValidation on your form - like I did!

Note that even with this there is still a problem with validation wrt the file size, because the user can still hit Submit and the input will fail silently. See this post for more info
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users