Yii User File Upload Problem

I’m using the Yii-User extension and trying to use the file upload widget. It doesn’t upload the file no matter what I try. It updates the filename to the database, but for some reason it is apparently failing validation. The code in UWfile that is failing is this:

public function setAttributes($value,$model,$field_varname) {


	....


	[b]	if ($model->validate()) {

[/b] if ($old_file&&file_exists($old_file))

				unlink($old_file);


			$value->saveAs($file_name);


		}


		$value = $file_name;


	} else {

The $model->validate() call is failing, but I have no idea why. I’m not including any additional validation on this field, and I’m not getting a flash of anything failing, it just skips the code where it saves the file.

Any help here?

Shawn

If the model is failing validation one of the easiest ways to see why is to just print out a list of all the errors for that model.

if($model->validate())

{

}else

print_r($model->errors);

I wouldn’t use this in practice of course but for debugging its a quick way to see what issues you’re running into.

Also, just a shot in the dark but make sure that your upload field for your file is marked as ‘safe’ in the model. I ran into this problem myself.

Almost the same thing I encounter… Hopefully someone can help me?

In a profile made with the yii-user module, I added a file upload field that uses the UWfile widget. This field is set ‘Required: No, but show on registration form’.

When a user registers an account and NOT upload a file, everything is ok. Also when the user logs in and then update the profile with a file upload, this works perfectly.

The problem is that when a ‘guest’ fills out the registration form and tries to upload a file, no error is given but the file is NOT written to disk (nowhere found on the system!). But the path/to/the/file is indeed updated in the database.

Is this perhaps intended behaviour or is this a bug? Does anyone has a solution?

I will have a look to the validation rules more closely, thank you for pointing that out enotirab.

Greetings,

Ametad

I did find my problem, which had to do with PHP’s settings for maximum file size. What was happening is that PHP wasn’t allowing the file upload because of php.ini’s upload_max_filesize setting, which was 2M on php.ini, but the file was 5M.

Shawn

Shawn,

Have you also tried to upload a file on a blank registration? In my case the upload works fine when logged in, when the user or admin edits the profile with a file upload.

I think I understand why it is not working… Because the model is not filled with values YET, it will never validate… I think the file only needs to be written to disk ‘onAfterSave’! I mean, then the whole model is indeed validated and the CUploadedFile can be safely written down.

But how is this possible…?

(I have to go now, but I’ll be back!)

After the last post I have still no solution… I will try to describe the problem a little better. Hopefully someone can give me a tip on how to proceed.

On the registration form I put (among other fields) a VARCHAR field with the UWfile widget. As described earlier the problem does NOT occur with an existing profile. The problem is that the file not is written to disk, but the path/to/file stored in the database.

A simple test added to the UWfile.php (look for the print_r() as proposed by enotirab)




public function setAttributes($value,$model,$field_varname) {

        $value = CUploadedFile::getInstance($model,$field_varname);

        

        if ($value) {

            $old_file = $model->getAttribute($field_varname);

            $file_name = $this->params['path'].'/'.$value->name;

            if (file_exists($file_name)) {

                $file_name = str_replace('.'.$value->extensionName,'-'.time().'.'.$value->extensionName,$file_name);

            }

            if ($model->validate()) {

                if ($old_file&&file_exists($old_file))

                    unlink($old_file);

                $value->saveAs($file_name);

            } else { //TEST

                print_r($model->getErrors());

                Yii::app()->end();

            }

            $value = $file_name;

        } else {

            if (isset($_POST[get_class($model)]['uwfdel'][$field_varname])&&$_POST[get_class($model)]['uwfdel'][$field_varname]) {

                $old_file = $model->getAttribute($field_varname);

                if ($old_file&&file_exists($old_file))

                    unlink($old_file);

                $value='';

            } else {

                $value = $model->getAttribute($field_varname);

            }

        }

        return $value;

    }



When I fill out the form this is the output:




Array ( [firstname] => Array ( [0] => First Name cannot be blank. ) [lastname] => Array ( [0] => Last Name cannot be blank. ) [gender] => Array ( [0] => Gender cannot be blank. ) [city] => Array ( [0] => City cannot be blank. ) [birthday] => Array ( [0] => Birthday cannot be blank. ) [phone] => Array ( [0] => Phone number cannot be blank. ) ) 



I don’t understand why the model is not validated, can anyone explain this to me? I have filled it out correctly of course.

If anyone ever is interested, here is my solution:




<?php


class UWfile {

    

    /**

     * @var array

     * @name widget parametrs

     */

    public $params = array('path'=>'assets');

    

    private $_file_instance = NULL;

    private $_old_file_path = '';

    private $_new_file_path = '';

    

    /**

     * Widget initialization

     * @return array

     */

    public function init() {

        return array(

            'name'=>__CLASS__,

            'label'=>UserModule::t('File field'),

            'fieldType'=>array('VARCHAR'),

            'params'=>$this->params,

            'paramsLabels' => array(

                'path'=>UserModule::t('Upload path'),

            ),

            'other_validator'=>array(

                'file'=>array(

                    'allowEmpty'=>array('','false','true'),

                    'maxFiles'=>'',

                    'maxSize'=>'',

                    'minSize'=>'',

                    'tooLarge'=>'',

                    'tooMany'=>'',

                    'tooSmall'=>'',

                    'types'=>'',

                    'wrongType'=>'',

                    'safe'=>array('true','false'),

                ),

            ),

        );

    }

    

    /**

     * @param $value

     * @param $model

     * @param $field_varname

     * @return string

     */

    public function setAttributes($value,$model,$field_varname) {

        $this->_new_file_path = $this->_old_file_path = $model->getAttribute($field_varname);

        

        if ($this->_file_instance = CUploadedFile::getInstance($model,$field_varname)){

            

            $model->getEventHandlers('onAfterSave')->insertAt(0,array($this, 'processFile'));

            $file_name = str_replace(' ', '-', $this->_file_instance->name);

            $this->_new_file_path = $this->params['path'].'/';

            

            if ($this->_old_file_path){

                $this->_new_file_path = pathinfo($this->_old_file_path, PATHINFO_DIRNAME).'/';

            } else {

                $this->_new_file_path .= $this->unique_dir($this->_new_file_path).'/';

            }

            

            $this->_new_file_path .= $file_name;

            

        } else {

            if (isset($_POST[get_class($model)]['uwfdel'][$field_varname])&&$_POST[get_class($model)]['uwfdel'][$field_varname]){

                $model->onAfterSave = array($this, 'processFile');

                $path = '';

            }

        }

        

        return $this->_new_file_path;

    }

        

    /**

     * @param $value

     * @return string

     */

    public function viewAttribute($model,$field) {

        $file = $model->getAttribute($field->varname);

        if ($file) {

            $file = Yii::app()->baseUrl.'/'.$file;

            return CHtml::link(pathinfo($file, PATHINFO_FILENAME),$file);

        } else

            return '';

    }

        

    /**

     * @param $value

     * @return string

     */

    public function editAttribute($model,$field,$params=array()) {

        if (!isset($params['options'])) $params['options'] = array();

        $options = $params['options'];

        unset($params['options']);

        

        return CHtml::activeFileField($model,$field->varname,$params)

        .(($model->getAttribute($field->varname))?'<br/>'.CHtml::activeCheckBox($model,'[uwfdel]'.$field->varname,$params)

        .' '.CHtml::activeLabelEx($model,'[uwfdel]'.$field->varname,array('label'=>UserModule::t('Delete file'),'style'=>'display:inline;')):'')

        ;

    }

    

    public function processFile($event){

            

        $model = $event->sender;

        

        if ($this->_old_file_path && file_exists($this->_old_file_path)){

            unlink($this->_old_file_path);

            $files = scandir(pathinfo($this->_old_file_path, PATHINFO_DIRNAME));

            if (empty($files[2])){

                //No files in directory left

                rmdir(pathinfo($this->_old_file_path, PATHINFO_DIRNAME));

            }

            

        }

        if ($this->_file_instance){

            if (!is_dir(pathinfo($this->_new_file_path, PATHINFO_DIRNAME))){

                mkdir(pathinfo($this->_new_file_path, PATHINFO_DIRNAME), 0777, TRUE);

            }

            $this->_file_instance->saveAs($this->_new_file_path);

        }

    }

    

    private function unique_dir($base_path='')

    {

        $unique_dir = $this->random_string();

        

        while (is_dir($base_path . $unique_dir)) {

            $unique_dir = $this->random_string();

        }

        

        return $unique_dir;

    }

    

    private function random_string($max = 20){

        $string = '';

        $chars = "abcdefghijklmnopqrstuvwxwz0123456789_-ABCDEGFHIJKLMNOPQRSTUVW";

        for($i = 0; $i < $max; $i++){

            $rand_key = mt_rand(0, strlen($chars));

            $string  .= substr($chars, $rand_key, 1);

        }

        return str_shuffle($string);

    }

    

}