Uploading files - problems

I’ve run through the cookbook tutorial How to upload a file using a model as well as read many forum posts, but I still cant get this to work with my own code.

  1. I thought the whole idea about CActiveRecord was to handle data to and from database. Therefore it’s very confusing when this tutorial uses a model of this type. Is there an easy explanation for this?

  2. OK, I try to integrate the example with my own models and code. I have a model class (for my db table) that extends CActiveRecord and it looks like this:




class quiz_3dqs_questions extends CActiveRecord {

	public static function model($className=__CLASS__) {

		return parent::model($className);

	}

	public function tableName() {

		return 'quiz_3dqs_questions';

	}

	public function rules() {

		return array(

			array('question, answer', 'required'),

		);

	}

	public function attributeLabels() {

		return array(

			'question_id' => 'Question Id',

			'gruop_id' => 'Group id',

			'question' => 'Question',

			'has_image' => 'Has image',

			'answer' => 'Answer',

			'created_date' => 'Created date',

		);

	}

}



I don’t want to store my uploaded images in the db itself, but on disk. There for I cant understand why I should mess with my file upload in this class, but I try to do it since thats what the tutorial says, so I add this to the class:

  • public $image; // put it on top

  • array(‘image’, ‘file’, ‘types’=>‘jpg’), // put it inside the rules function

My controller for this model looks like this: (I’m only pasting the relevant function)




public function actionEdit() {

  if(isset($_POST['quiz_3dqs_questions'])) {

    $tmp_model=quiz_3dqs_questions::model()->findbyPk($_POST['quiz_3dqs_questions']['question_id']);

    $tmp_model->attributes=$_POST['quiz_3dqs_questions'];

    $tmp_model->image=CUploadedFile::getInstance($tmp_model,'image');

    if ($tmp_model->validate()) { $tmp_model->save(); }

    $tmp_model->image->saveAs('/images/quiz_3dqs/test');

  }//if

...



My html input form has this:




<?php echo CHtml::activeFileField($question,"image"); ?>



Problem is that when uploading a file i get the error:


Fatal error: Call to a member function saveAs() on a non-object in /.../protected/controllers/Quiz_3dqsController.php on line 56

The $_FILES array do contain the file, I just cant get it working with the "Yii way"

A var_dump of $tmp_model->image right after it’s called the getInstance function returns NULL.

Any ideas where I might have gone wrong? …I’m 5 minuttes from starting to parse the $_FILES array… :confused:

i have done a action with file upload.

I will post my code




class LansController extends CController

.....

public function actionCreate()

    {

        $model=new lans;

        if(isset($_POST['lans']))

        {

            $model->attributes=$_POST['lans'];

            $model->lan_flag=CUploadedFile::getInstance($model,'lan_flag');


            if($model->save())

            {

                $model->lan_flag->saveAs('./file/flag/default/'.$model->lan_flag);

                $image = Yii::app()->image->load('./file/flag/default/'.$model->lan_flag);

                $image->resize(16, 11);

                $image->save('./file/flag/'.$model->lan_flag);

......

model




class lans extends CActiveRecord

...public function rules()

	{

		return array(

			array('lan_code','length','max'=>255),

		 array('lan_flag', 'file', 'types'=>'jpg, gif, png','allowEmpty'=>true),


		);

	}...

I used also kohana image library from extension

[Edit]

This is my update action, I thing it is not as yours


public function actionUpdate()

    {

        $model=$this->loadlans();

        if(isset($_POST['lans']))

        {

            $model->attributes=$_POST['lans'];

            $file=CUploadedFile::getInstance($model,'lan_flag');

            if (!empty($file))


            $model->lan_flag=CUploadedFile::getInstance($model,'lan_flag');

            else

            $model->lan_flag=lans::model()->findByPk($model->lan_id)->lan_flag;


            if($model->save())

            { if (!empty($file))


                {

                    $model->lan_flag->saveAs('./file/flag/default/'.$model->lan_flag);

                    $image = Yii::app()->image->load('./file/flag/default/'.$model->lan_flag);

                    $image->resize(16, 11);

                    $image->save('./file/flag/'.$model->lan_flag);

                }


                $this->redirect(array('show','id'=>$model->lan_id));


            }

        }

        $this->render('update',array('model'=>$model));

    }

public function loadlans($id=null)

    {

        if($this->_model===null)

        {

            if($id!==null || isset($_GET['id']))

            $this->_model=lans::model()->findbyPk($id!==null ? $id : $_GET['id']);

            if($this->_model===null)

            throw new CHttpException(404,'The requested page does not exist.');

        }

        return $this->_model;

    }






Hello dimis and thanks for your answer. Quote from your update action:

I found this a bit confusing…

Still, it looks simular to mine, but I cant say this made me any smarter, anyone else have suggestions?

I wish there was more examples to all the functionality of the wonderful yii classes…

At my code if user do not upload something I want not to change the field (As I thing will do if user do not upload a file).

Are you sure that $tmp_model is an object of your model and have the write values, this is that I understand from your error.

Thanks again man, yes I’m sure that my code:




$tmp_model=quiz_3dqs_questions::model()->findbyPk($_POST['quiz_3dqs_questions']['question_id']);



returns a model object.

Honestly, I’m pretty fed up with this upload thing now after sitting with it a whole day, so I just very easy managed to upload the files I wanted using the good’ol $_FILES array…

I would love for someone to explain my first question though… There are still so many things I find a little bit strange about how things are done, and the answer to some of the logic is not existant. When is the first book on Yii coming? I would buy it in an instant, eBook or paper!

Hi,

I also have same problem as alf.

For me also it is not possible to get it working with POST array.

I inspected post array and POST[‘uploadedFileName’] is empty. ‘uploadedFileName’ is the name of my file field.

Also noticed YII generates a hidden field when activeFileField is called.

Hidden field also has the same name as file field.




<input id="ytNewsMedia_uploadedFileName" type="hidden" value="" name="NewsMedia[uploadedFileName]" />

<input name="NewsMedia[uploadedFileName]" id="NewsMedia_uploadedFileName" type="file" />



I think POST array gives the value of this hidden field. I am still not sure why this hidden field is rendered by YII.

I am testing my application on firefox browser.

It will be great help if somebody helps me to figure out what is wrong.

Thanks,

Chamal.

I was able to solve my problem. My coding had a bug.

Alf,

Have u declared a property named as $image in ur quiz_3dqs_questions model ?

Hi people I have discovered the same problem on FireFox. CUploadedFile::getInstances($model,‘fileToLoad’); returns nothing!

The question is how and what to put in that additional hiddenField Yii renders.Should I use JavaScript? Or more wise parse $_FILES or $_POST depending on browser? Any ideas?

Hey!

I have just fixed it that way:




<?php $form=$this->beginWidget('CActiveForm', array(

	'id'=>'tasks-form',

	'enableAjaxValidation'=>false,

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

)); ?>



It’s very important to add ‘htmlOptions’ => array(‘enctype’=>‘multipart/form-data’). Check your code.

Hi, alf …

this is veera from chennai…you can try this …

add ur view file like this :(photo.php)


<?php echo CHtml::form('','post',array('enctype'=>'multipart/form-data')); ?>

<p>

Upload  Your Photo :


<?php echo CHtml::activeFileField($model, 'image'); ?>

 

<?php $flash=Yii::app()->user->getFlash('key');?>

<p>


  

    <?php

if($flash!=""){


?>


<div class="flash-errr" style="padding-left: 250px; ">

    <p>

  <?php echo $flash; ?>


</div>

<p>

   <?php


}

?>

       <br/>

<?php echo CHtml::SubmitButton('Upload'); ?>


<?php echo CHtml::endForm(); ?>.

</div>


 </div>


In your controller ::




public function actionPhoto()

	{


                 $id=$_GET['id'];

               $model=new Image;

              

            $model=Image::model()->findByAttributes(array('uid'=>$id));

               if ($model==""){

                  $model=new Image;

               $model->uid=$id;

            }else{

              $model->uid=$id;

            }

                       

                if($_POST['Image']!=""){

                      

                   

                    $photo=CUploadedFile::getInstance($model,'image');           

                        $model->image=$photo;

                        $model->uid=$id;

                         $model->name=Yii::app()->user->name;

                       

                         if($model->validate()&& $model->image!=""){


                   $model->save();

                 $model->image->saveAs('photo/'.$model->uid.$model->image);

                   

                 $this->render('myprofile',array('model'=>$model,));

                  return false;

                   }

                   else{

                        Yii::app()->user->setFlash( 'key','Please Upload Valid Image Format Like jpg , jpeg , gif , png .');

                       $model=Image::model()->findByAttributes(array('uid'=>$id));

                      $model->uid=$id;


                    }

                }

                $this->render('photo',array('model'=>$model,));

            }

same question: why this hidden field is rendered…

the error response from server will show two error msgs of file.

no idea how to remove the hidden field?

after form submit and get error, the file field will be removed too, how to keep it?

THANKS IN ADVANCE

I too do not understand, why this hidden field exists? i tried some different options to set this, but could not… so finally added my own hidden field for the file which works…


<div class="row">

		<?php echo $form->labelEx($model,'photo'); ?>

            <?php echo $form->fileField($model,'photo'); ?>


       >>>  <?php echo $form->hiddenField($model,'photo'); ?>


		<?php echo $form->error($model,'photo'); ?>

	</div>

How I solved this problem

CHtml::activeFileField change to:


	public static function activeFileField($model,$attribute,$htmlOptions=array())

	{

		self::resolveNameID($model,$attribute,$htmlOptions);

		// add a hidden field so that if a model only has a file field, we can

		// still use isset($_POST[$modelClass]) to detect if the input is submitted

		$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);

		

		if(array_key_exists('uncheckValue',$htmlOptions))

		{

			$uncheck=$htmlOptions['uncheckValue'];

			unset($htmlOptions['uncheckValue']);

		}

		else

			$uncheck='0';


		$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);

		$hidden=$uncheck!==null ? self::hiddenField($htmlOptions['name'],$uncheck,$hiddenOptions) : '';

		

		

		return $hidden

			. self::activeInputField('file',$model,$attribute,$htmlOptions);

	}



After that use in view:


<?php echo $form->fileField($model,'filename',array('uncheckValue'=>$needValue)); ?>

Hidden field takes the value $needValue

If ‘uncheckValue’ is null, the hidden field will not be created.

Sorry for the terrible english