Yii 1.1: How to upload a file using a model

67 followers

The Model

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

The Controller

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.

The View

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');
// ...
echo CHtml::submitButton('Submit');
$this->endWidget();

Another syntax is to use static calls in CHtml instead of CActiveForm. The result is the same as above.

<?php echo CHtml::form('','post',array('enctype'=>'multipart/form-data')); ?>
...
<?php echo CHtml::activeFileField($model, 'image'); ?>
...
<?php echo CHtml::submitButton('Submit'); ?>
<?php echo CHtml::endForm(); ?>

Links

Total 20 comments

#15918 report it
KonApaz at 2013/12/29 07:52am
Re: How to validate a local file (removed question)

File Validation cannot be used before file uploaded on the server.

Instead of that, you could make javascript validation.

See the relative wiki http://www.yiiframework.com/wiki/598/clientvalidation-for-files-modern-browsers/

#15745 report it
Gerhard Liebenberg at 2013/12/11 04:42pm
$model->image = null

Tip: My $model->image stayed null, until I changed my json submit (with ($form).serialize()) back to a normal submit.

#15573 report it
Nacesprin at 2013/11/22 11:13am
Add attribute 'safe'=>true to rules()

You need to add the 'safe'=>true property to array('image', 'file', 'types'=>'xxxx', 'safe'=>true), or you'll get "Failed to set unsafe attribute 'image' ":

http://www.yiiframework.com/forum/index.php/topic/26456-failed-to-set-unsafe-attribute-file/

#15386 report it
NewYiiFan at 2013/11/04 10:01am
CException: Item and its behaviors do not have a method or closure named "save".

That's the exception-message, which I get..

#13600 report it
gaurish at 2013/06/10 10:06am
include(CUploadedfile.php): failed to open stream: No such file or directory

Hi, I tried with give example. I am using Yii 1.1.13... I got the error as

include(CUploadedfile.php): failed to open stream: No such file or directory

all the files are at correct place...

#13031 report it
kiran sharma at 2013/04/29 01:23pm
@Trejder

This article was written by me..

#13021 report it
Trejder at 2013/04/29 02:51am
@outrage, @CedSha, @kiran sharma

@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()) calls if($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 replacing if($model->save()) with if($model->validate()) and your code started to work.

@kiran sharma: Your example is wrong. You most certainly have to use if($model->validate()) instead of if($model->save()). If you use if($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 after if($model->validate()), but before if($model->save()) to avoid situation, where database is updated even after error of different type, than validation error.

#11695 report it
CedSha at 2013/01/28 03:47am
Validation (Response at @outrage )

I had the same problem, after investigation I have solved that way :

...
$model->attributes=$_POST['MyForm'];
$model->filename=CUploadedFile::getInstance($model,'filename');
if ($model->validate()){
    $model->image->saveAs('path/to/localFile');

I think if your model is not an instance of CActiveRecord, then you wont be able to do the

if($model->save())

and I believe the validation step is made there. So you have to explicitly test the validation.

#10909 report it
GusDeCooL at 2012/12/02 01:23pm
File Handling Validation

Remember to check your CUploadFile, if null don't do saveAs or you will get an error

Here is sample of my code

public function actionCreate() {
        $this->layout = '//layouts/column1';
        $this->pageTitle = 'Create post for '.$this->pageTitle;
        $model = new Article;
 
        // Uncomment the following line if AJAX validation is needed
        // $this->performAjaxValidation($model);
 
        if (isset($_POST['Article'])) {
            $model->attributes = $_POST['Article'];
            $model->created = date('Y:m:d H:i:s');
            $model->group = $this->articleGroup;
            $model->fk_user_id = Yii::app()->user->id;
 
            // file handling
            $imageUploadFile = CUploadedFile::getInstance($model, 'image');
            if($imageUploadFile !== null){ // only do if file is really uploaded
                $imageFileName = mktime().$imageUploadFile->name;
                $model->image = $imageFileName;
            }           
 
            $voiceUploadFile = CUploadedFile::getInstance($model, 'voice_note');
            if($voiceUploadFile !== null) {
                $voiceFileName = mktime().$voiceUploadFile->name;
                $model->voice_note = $voiceFileName;
            }
 
 
            if ($model->save()){
                if($imageUploadFile !== null) // validate to save file
                    $imageUploadFile->saveAs(Article::FOLDER_IMAGE.$imageFileName);
 
                if($voiceUploadFile !== null)
                    $voiceUploadFile->saveAs(Article::FOLDER_VOICE.$voiceFileName);
 
                $this->redirect(array('view', 'id' => $model->id));
            }   
        }
 
        $this->render('//article/create', array(
            'model' => $model,
        ));
    }
#10200 report it
kiran sharma at 2012/10/10 02:40pm
@outrage

Sorry bro, but things work fine for me, (also tested with latest version v1.1.12) i use following rule in model,

..
array('image', 'file','types'=>'jpg, gif, png'),
..

and when i upload example.txt ( text file ) i got error like,

The file "example.txt" cannot be uploaded. Only files with these extensions are allowed: jpg, gif, png.

So, might be some mistake with your code...

#10199 report it
outrage at 2012/10/10 12:29pm
Bug?

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.

$model->image=CUploadedFile::getInstance($model,'image');
#8976 report it
François Gannaz at 2012/07/11 04:42am
Do not ask for help here

@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.

#8969 report it
Bman900 at 2012/07/10 07:34pm
Video Upload

Video files do not work, it just reloads a cleared form, is there a fix to this?

#7734 report it
devric at 2012/04/13 04:26am
Show the image in _form.php for actionUpdate

Now i got the file uploaded,

how do i show what image i currently uploaded, into the _form.php file

Only for actionUpdate

#7593 report it
Asgaroth at 2012/04/01 08:15pm
XUpload extension

You can also use XUpload extension which supports multiple file uploads

#7180 report it
AlDente at 2012/03/01 10:01am
response to #6885 / vidhi

make sure that the line $model->image=CUploadedFile::getInstance($model,'image'); is before of if($model->save()) {...}

bye

#6885 report it
vidhi at 2012/02/11 02:55am
How to solve the problem occurring with image file upload.

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.

#6012 report it
rrbot at 2011/12/05 06:34pm
"File cannot be blank"

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.

#5496 report it
devric at 2011/10/16 09:32pm
How to save in views for noob

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(); ?>
#5354 report it
cuongnc at 2011/10/06 11:00am
validation ajax

I can't validation ajax with field image. It error "Image cannot be blank".

Leave a comment

Please to leave your comment.

Write new article
  • Written by: qiang
  • Updated by: KonApaz
  • Category: Tutorials
  • Yii Version: 1.1
  • Votes: +80 / -6
  • Viewed: 272,119 times
  • Created on: Feb 4, 2009
  • Last updated: Dec 7, 2013
  • Tags: File upload