File Upload Problem

Hi, I don’t know if this is a bug on Yii, or just a bug in my code.

But everytime I upload any file, even the one that satisfies the rules defined in my Model,

The ajax validation is insisting that the file is blank.

918

upload1.jpg

Here is the code in my view file send.php


<div class="form">

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

	'id'=>'send-form',

	'enableAjaxValidation'=>true,

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

	)); 

?>

 

    <?php echo $form->errorSummary($model); ?>

 

    <div class="row">

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

		<?php echo $form->label($model,'picture'); ?>

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

    </div>

 

    <div class="row submit">

        <?php echo CHtml::submitButton('Submit'); ?>

    </div>

 

<?php $this->endWidget(); ?>

</div><!-- form -->

Here is the code in my model file PictureSendForm.php


<?php

class PictureSendForm extends CFormModel

{

	public $picture;

	

	//Declares the validation rules.

	public function rules()

	{

		return array(

			array('picture','safe'),

			array('picture','file','types'=>'jpg','allowEmpty'=>false),

		);

	}

	

	public function attributeLabels()

	{

		return array(

			'picture'=>'Picture',

		);

	}

	

	public function process()

	{

		$file = 'files/pics/original/t'.Yii::app()->user->id.'.jpg';

		$w_max = 600;

		

		list($w, $h) = getimagesize($file);


		$ratio = $w/$h;

		

		$h_max = $w_max/$ratio;


		$image_input = imagecreatefromjpeg($file);

		$image_output = imagecreatetruecolor($w_max,$h_max);

	

		imagecopyresampled(

		$image_output,

		$image_input,

		0,0,0,0,

		$w_max,$h_max,

		$w,$h);

		

		imagejpeg($image_output,$file,100);

	}

}

?>

And the code in my controller file DefaultController.php




	public function actionSend()

	{

		$this->layout = '//layouts/column1';

		

        $model = new PictureSendForm;

		$this->performAjaxValidation($model);

		

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

        {

            //$model->attributes = $_POST['PictureSendForm'];

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

			if($model->validate()){

		        $model->picture->saveAs('files/pics/original/t'.Yii::app()->user->id.'.jpg');

				$model->process(); //Resizes the image

				$this->redirect('edit');	

			}

        }

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

	}


	protected function performAjaxValidation($model)

	{

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

		{

			if($_POST['ajax']==='send-form'){

				echo CActiveForm::validate($model);

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

			}

		}

	}




But if I clicked the Submit button, it is able to redirect to the Edit action.

Hope someone can help me, thank you in advance.

Same problem here, did you find any solution?

Thanks for the advice!

because you can NOT set the value of <input type="file" /> directly via javascript or insert the value by yourself.

Elaborate, I have the same troubles. The model returns error that the file is blank.

My model:




class DocFile extends CFormModel {

    public $doc;


	public function rules() {

		return array(

            array('doc', 'file', 'types'=>'jpg'),

		);

	}


	public function attributeLabels() {

		return array(

            'doc' => 'Document',

		);

	}


}



View part:




<?php echo CHtml::activeFileField($file, 'doc');?>



Controller part:




$file->attributes = $_POST['DocFile'];

                $file->doc = CUploadedFile::getInstance($file,'doc');

                if ($file->validate()) {

                    $file->doc->saveAs(Yii::app()->basePath . '/../../shareddocs/'.Yii::app()->user->getId().'.jpg');

                    echo 'all is well';

                } else {

                    pr($file->getErrors());

                    exit;

                }



Found the answer - forgot to add the enctype="multipart/form-data" to the <form> tag.

I forgot to add it too!!

…but found the answer right here in the forum

Thanks for this post!

hi, im having the same problem to, eventhough the forms enctype is multipart/form-data, it only happens with the ajax call, but when i submit the form this bug doesnt happen, any solutions?

I guess this one has the solution/tutorial you need: http://www.ajaxf1.com/tutorial/ajax-file-upload-tutorial.html

I believe your problem is related to the AJAX VALIDATION. You cannot send a file via AJAX and therefore validation always fails. Try to use it without AJAX VALIDATION and test it again. If it works, there you go.

Cheers

edit: I just saw that you actually tested this. What I recommend you is that you make use (it is what I do) jquery.validate plugin on your client or another way to do so, and once validated on client submit the form and validate again on server.

If you wish to AJAX submit a form with multipart/form-data (Yes I know we cannot do it) you can mimic that (as I do) by creating an IFRAME tag on the fly, set its TARGET attribute to the name of the IFRAME and then when coming back get its contents (response from server) to update whatever you do.

Here is a fragment of my own library that I plug onto all my CMS and that works in conjunction with other plugins I wrote.

** This code is an example, it doesn’t work by itself!




iframeSubmit: function ( ){

				

    var command = this.methods.getCommand( arguments );

    if( !command ) return false;


   var self = this;

   self.parser.createIFrame()


   var frm = $( command.form );

		       

    var c = frm.attr('target');

     frm.attr('target','iframe-redirect-target');

	            

	            frm.submit();

	            typeof command.onsubmit == "function" && command.onsubmit();

	            window.iframeHandler = function () {

	                var e = $("#iframe-redirect-target").get(0);

	                frm.attr('target',c);

	                try {

	                    response = (e.contentWindow || e.contentDocument || e).document.body.innerHTML;

	                    response = response.replace(/[\f\n\r\t]/g, " ");

	                    if (window.opera) response = response.replace(/&quot;/g, '"');

	                } catch (f) {

	                    response = null;

	                }

	                

	                command.oncomplete(response);

	            };

	            return true;

		        

}



i have the same problem …is it not possible through ajax validation

You can remove the message with the this workaround.

Inside the ajax check of your action in the controller replace:




CActiveForm::validate($model)



With:




echo preg_replace('/,"MyModel_file":\[".*?"\]/' , '' , CActiveForm::validate($model));



where MyModel_file is the id of your file input field.

+1 to you!

This seems like clever cheating, but it solves “filefield-ajax-validation” problem perfectly :)))))))

LATER UPDATE: IT SEEMS eventually it’s a bit buggy “hack” - i.e. when I fill form dtep-by-step from top to the bottom (file field in the bottom of my form) it works ok, but when I skip some field that needs validation (some text field) and fill in file field - it still show error that “file field is blank”…

Anyway,I used this approach:




     //echo CActiveForm::validate($model);

     echo CActiveForm::validate($model,array('news_date','order_date','header','intro','alias','body'));  // validate all except "file_field"