First declare an attribute to store the file name in the model class (either a form model or an active record model).
Also declare a file validation rule for this attribute to ensure a file is uploaded with specific extension name.
class Item extends CActiveRecord { public $image; // ... other attributes public function rules() { return array( array('image', 'file', 'types'=>'jpg, gif, png'), ); } }
You can add others validation parameters as described in CFileValidator. For instance, one can add a "maxSize" restriction (the PHP ini settings will of course prevail).
Then, in the controller class define an action method to render the form and collect user-submitted data.
class ItemController extends CController { public function actionCreate() { $model=new Item; if(isset($_POST['Item'])) { $model->attributes=$_POST['Item']; $model->image=CUploadedFile::getInstance($model,'image'); if($model->save()) { $model->image->saveAs('path/to/localFile'); // redirect to success page } } $this->render('create', array('model'=>$model)); } }
CUploadedFile::saveAs() in one of the methods of CUploadedFile. You can also access directly to the file through its "tempName" property.
Finally, create the action view and generate a file upload field.
$form = $this->beginWidget( 'CActiveForm', array( 'id' => 'upload-form', 'enableAjaxValidation' => false, 'htmlOptions' => array('enctype' => 'multipart/form-data'), ) ); // ... echo $form->labelEx($model, 'image'); echo $form->fileField($model, 'image'); echo $form->error($model, 'image'); // ... $this->endWidget();
Another syntax is to use static calls in CHtml instead of CActiveForm. The result is the same as above.
echo CHtml::form('','post',array('enctype'=>'multipart/form-data')); ... <?php echo CHtml::activeFileField($model, 'image'); ... <?php echo CHtml::endForm();
Total 20 comments
This article was written by me..
@outrage: If model's rules are correctly defined, then
if($model->save())preforms validation and does not allow to save model, if there are any validation errors. That's how ActiveRecord works ever since and this has to work in either current or in any other version of framework. So, if you're able to upload TXT files, then you most certainly made mistake in your validators definition. I copied code from this wiki line-by-line and also wasn't able to upload TXT files. The example is OK.@CedSha:
if($model->save())callsif($model->validate())internally, so changing one to another won't fix anything, if validators are incorrectly defined. The only difference between these two functions is that first validates model and saves it to database, while second one only validates and does not perform any DB query. I simply can't believe that you didn't change anything except replacingif($model->save())withif($model->validate())and your code started to work.@kiran sharma: Your example is wrong. You most certainly have to use
if($model->validate())instead ofif($model->save()). If you useif($model->save()), model will be written to database (if it passes validation, of course), even if$model->image->saveAs('path/to/localFile');or any other command following will fail. This way, you'll have empty (dead) entry in database, that does not reference any physical file, if for example moving file from temporary to permanent location fails.In this or any other contexts there should be only page redirection after
if($model->save()). All other operations, on database or related, must be performed before model is saved, that is afterif($model->validate()), but beforeif($model->save())to avoid situation, where database is updated even after error of different type, than validation error.I had the same problem, after investigation I have solved that way :
I think if your model is not an instance of CActiveRecord, then you wont be able to do the
and I believe the validation step is made there. So you have to explicitly test the validation.
Remember to check your CUploadFile, if null don't do saveAs or you will get an error
Here is sample of my code
Sorry bro, but things work fine for me, (also tested with latest version v1.1.12) i use following rule in model,
and when i upload example.txt ( text file ) i got error like,
So, might be some mistake with your code...
There may be an issue following this wiki with recent versions of Yii.
When I add the following line above $model-save(), the validation doesn't work as intended. In fact, it allows upload of any file type.
@Bman900 : Just above the comment form of this page, there's an alert box that warns: "Please only use comments to help explain the above article. If you have any questions, please ask in the forum, instead."
You should follow these rules. It will benefit to you (you can explain your problem in details and more people will read your post there) and to this wiki (a lighter page with useful comments). If you get insightful answers in the forum, then please update your comment or the wiki page.
Video files do not work, it just reloads a cleared form, is there a fix to this?
Now i got the file uploaded,
how do i show what image i currently uploaded, into the _form.php file
Only for actionUpdate
You can also use XUpload extension which supports multiple file uploads
make sure that the line $model->image=CUploadedFile::getInstance($model,'image'); is before of if($model->save()) {...}
bye
After performing the above given example, my form is submitted but the data is not stored in database... the DB table totally blank.. not a single entry in the form is been stored.
Please help me to solve my issue.
If you are having problems with Updating a model with a file, where you want the file to be empty but get "File cannot be blank", adjust your rule accordingly:
array('file', 'file', 'types'=>'jpg', 'allowEmpty' => true),
If you only want this to be empty on update, you could use a scenerio.
Hi i've followed the guide and add the submit button to the view, but it does not submit, how do i submit this?
<? echo CHtml::form('', 'post', array('enctype'=>'multipart/form-data')); ?><? echo CHtml::activeFileField($model, 'image'); ?> <?php echo CHtml::submitButton('Submit'); ?><? echo CHtml::endForm(); ?>I can't validation ajax with field image. It error "Image cannot be blank".
A Question/Suggestion:
If you put this line: $model->image=CUploadedFile::getInstance($model,'image');
in your model under beforeSave() and the file handling in afterSave() you can leave the controller untouched. for me this is usefull beause if you add more file uploads or change something you can just change everything in the model.
The example above is great, but if you are working with a CRUD interface, then there is a need for a "UPDATE" action. If you update fields but dont upload any files the previous files will be "reset" (made empty) in the model. To prevent this you need to extend the code above.
This approach is based on the explanation from tri, see forum topic >>
http://www.yiiframework.com/forum/index.php?/topic/5419-optional-upload-file-when-update-a-record/page__view__findpost__p__27940
My example:
MODEL:
By making the image unsafe the input values for the image field wont be set by $model->attributes=$_POST['Events'];
This allows us to use CUploadedFile data object to set the image data.
CONTROLLER:
The first "if" check if the upload object is being loaded and filled with the uploaded file. If this is the case then the model->image gets an update otherwise the previous uploaded file remains.
The second "if" in the save will actually save the file on the webserver.
Hope this helps for those who are struggling with the file upload
If like me you decide to use the included "/projectname/images" folder to store your applications' images, you can change this line from the tutorial:
To be this:
The Yii::app()->basePath includes "/protected" at the end, and as the folder "images" is a sibling to "protected" so the /../ is necessary.
I'll also add that an easy way to display an uploaded image, would then be to open your view file, and use CHtml::image to generate tags for your Images with the necessary attributes, as follows:
$data->description, and $data->title are from my Image.php model, and were perfect for the tags alt text and title, respectively.
To define the enctype using CActiveForm, use the htmlOptions property:
$form=$this->beginWidget('CActiveForm', array( 'id'=>'paper-form', 'enableAjaxValidation'=>false, 'htmlOptions'=>array('enctype'=>'multipart/form-data') ));
Leave a comment
Please login to leave your comment.