Form fileField - hidden field empty

I have a CActiveForm with a fileField:




	<div class="row">

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

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

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

	</div>	



In edit mode for my model, while all other fields are populated correctly, the hidden field for the image remains empty:




  <div class="row">

    <label for="Labels_label_logo">Label Logo</label>

    <input id="ytLabels_label_logo" type="hidden" name="Labels[label_logo]" value="">

    <input id="Labels_label_logo" type="file" name="Labels[label_logo]">

    <div id="Labels_label_logo_em_" class="errorMessage" style="display:none"></div>

  </div>



Thus, when I save, I lose the current image in the database.

Is this a bug, or have I missed something?

do u want to show or change in edit mode?

Like most forms of this type that I work with, changing the image is an option. If no new image is selected, the existing image remains in the database.

As far as I am concerned, its a bug. Looking at CHtml.php we have:




	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);

		return self::hiddenField($htmlOptions['name'],'',$hiddenOptions)

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

	}



As you can see, the hidden field is guaranteed to wipe out any existing image in the database, since it has no value. I do not see the point of having the hidden field there at all (unless you think its a good thing to wipe out the existing image, even if no new image is uploaded!). I have changed the offending line to:




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



So now in my controller I just need:




			$logo=CUploadedFile::getInstance($model,'label_logo');

			

			if(!empty($logo)) $model->label_logo = $logo;

			

			if($model->save())

			{

				

				if(!empty($logo)) {

					$model->label_logo->saveAs(Yii::getPathOfAlias('webroot') . '/uploads/labels/' . $logo);

					Labels::model()->processLabelImage($logo, $model->id);

				}

				

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

			}



you neither miss something nor its a bug.

you got all your answer in This Post

and specially refer This Thread

I do not see anything there whatsoever that explains the purpose of a hidden field with no possible value accompanying the file input.

That field remains blank by default for new file upload.

you can get value by print_r($_FILES), it will give,


[Labels] => Array  (  [name] => Array  ([label_logo] => {Your uploaded logo image name}

as you say on edit page the field remains empty which is usual,

but you can get value using


 $model->label_logo

You can change rule function in controller as shown below.




<?

public function rules()

{

	

	return array(

		....

		array('label_logo', 'unsafe'),

		....

	);

}

?>



If you won’t take it unsafe each time form is submitted it will assign it’s value to label_logo and hence in become empty in case of edit if you don’t select file.

Also you need to assign label_logo value mannyally if image is uploaded as shown below.




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

$fileInstance = CUploadedFile::getInstance($model,'label_logo');		

if($fileInstance != "")

{

	$model->label_logo = $fileInstance;

}

if($model->save())



That makes no sense whatsoever. The hidden field with no value is NOT required at all for a new file upload. It serves no purpose whatsoever in that case. Its value (null) is in $_POST, not $_FILES.

I have worked on numerous PHP applications with file upload and a hidden field has ALWAYS been used to hold the value of the current file in database, so that if no new file is uploaded we retain the current file.

An empty hidden field serves no purpose whatsoever other than to DELETE the current file. That’s very backward IMO.

Perhaps if I file a bug report I may get an answer that makes sense… but I doubt it very much.

The standard Yii CRUD is:




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

		{

			

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

                } 



Thus, with the empty hidden field, $_POST[‘Labels’][‘label_logo’] will be null and the current image will be deleted. That’s just dumb.

How about you read above posts before replying?

There is no useful need to preserve value in that hidden field.

when you upload fill input field filled something as , C:\Users\kiran.sharma\Desktop\photo.png

and on update/edit page you can get value as in my above post and there are various ways to remain field blank on update/edit (one posted by vibhaJadwani) page and no reflection on particular file field in db and folder.

so i thing it makes no sense to preserve value.

can i ask for which purpose you require that?

Perhaps then you can enlighten the World as to what useful purpose the hidden field serves? There is no useful need for a hidden field that is always blank. It is nothing other than a nuisance.

Sure! This is the CRUD generated by Gii:




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

		{

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



Now, on update, since we are posting a hidden field that has no value for “Labels[label_logo]”, that attribute will be blank and we will lose the value in our database. If on the other hand the hidden field (which by default serves NO useful purpose) does in fact hold the value we have in our database, then we don’t need to worry about a workaround for this stupidity. The hidden field will serve a useful purpose in the same way it does in thousands of PHP applications that have file upload, that is, if no new file is uploaded the existing filename is preserved in our database without the need for silly workarounds.

@Backslider please moderate your posts, there is really no need to use such tone.

You are constantly asking why is there a hidden field… but the reason is explained just above it in the comments… you even did copy/paste that code above in the 3rd post. Do that comment answer your question?


On update:

My thinking is that I want to know if the user had uploaded a picture or not. So for that I can check the value of the model attribute. If there would be a previous value that would not be the case. That is the main reason why we should not change this as you suggested because it would possibly break current code and would not be BC. (BC == backward compatibility)

I cannot comprehend why you cannot see the flaw in your own thinking.

"I want to know if the user had uploaded a picture or not. So for that I can check the value of the model attribute"

The attribute will always be blank, it will not tell you anything about a file upload. The only way to tell if there is a file upload is to check $_FILES:




    $logo=CUploadedFile::getInstance($model,'label_logo');

    

    if(!empty($logo)) $model->label_logo = $logo;



I have no idea what post you are referring to. Please explain yourself the useful purpose of the hidden field that always remains blank.

The post I’m referring is the 3rd post in this thread.

The comment is:

Problem is that if there is no hidden INPUT, when the user does not choose a file

to be uploaded in POST you don’t get the model attribute at all, i.e. There is no $_POST[‘yourmodel’][‘fileattribute’]

That’s the reason why the hidden field is there…

Edit:

Ops… actually the field is never there even if the user selects a file. So the usual check if the form was submited as mentioned in the comments would fail.

So you are telling me that the only useful purpose this hidden field serves is a fudge for the rare possibility that a form only has a single file input?

If that is the case, then the input will still serve exactly the same purpose, while serving the more useful and logical purpose of preserving the existing filename in case there is no new upload, if it is in fact populated with the existing value for an update. This will not break BC at all.

I just did a dump of my $_POST and it contains:




 [yt0] => Save



So, you do not need the hidden field at all to check if the form has been posted, since $_POST will not be empty even if you have a single file input and no hidden field.

You cannot relay on if(isset($_POST))… you need to check for the model so it should be if(isset($_POST[‘yourmodel’]))

What you are essentially telling me is that rather than have the logical thing and populate the hidden field, we should have something like this:




	public function actionUpdate($id)

	{

		$model=$this->loadModel($id);

                $myfile = $model->myfile; // need this because silly hidden field is always empty




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

		{

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

			$model->myfile = $myfile;  // need this because silly hidden field is always empty

			

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

			

			if(!empty($file)) $model->myfile = $file; 	               




Thats just ugly… :-X

With a populated hidden field:




	public function actionUpdate($id)

	{

		$model=$this->loadModel($id);


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

		{

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

			

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

			

			if(!empty($file)) $model->myfile = $file; 



That makes sense…

I understand your point of view and your passion for this issue… but there is really no need to make a post on every few minutes…

What happens if some user has a required file upload even on update like forced picture change (can’t think of better need, but I think you can agree on that, that someone needs to have a required file upload on update too)

In that case if a user did not select a file the old filename would be in the file attribute.