How to upload a file using a model

46 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');
// ...
$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::endForm(); ?>

Links

Total 13 comments

#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
khobaucuatui at 2011/10/06 11:00am
validation ajax

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

#3970 report it
Kabinenkoffer at 2011/05/24 07:07am
Controller / Model

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.

#3217 report it
ghadad at 2011/03/25 05:38pm
and dont forgot adding multipart/form-data option to update form !
<?php $form=$this->beginWidget('CActiveForm', array(
    'id'=>'company-form',
    'enableAjaxValidation'=>true,
        'htmlOptions'=>array('enctype'=>'multipart/form-data'),
));
#3137 report it
thim at 2011/03/20 10:20am
File upload and update / error actions

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:

public function rules()
    {
        // NOTE: you should only define rules for those attributes that
        // will receive user inputs.
        return array(
...
            array('image', 'unsafe'),
...
}

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:

/**
     * Updates a particular model.
     * If update is successful, the browser will be redirected to the 'view' page.
     * @param integer $id the ID of the model to be updated
     */
    public function actionUpdate($id)
    {
        $model=$this->loadModel($id);
 
        // Uncomment the following line if AJAX validation is needed
        // $this->performAjaxValidation($model);
 
        if(isset($_POST['Events']))
        {
            $model->attributes=$_POST['Events'];
 
            $file_image = CUploadedFile::getInstance($model,'image');
 
            if ( (is_object($file_flyer) && get_class($file_flyer)==='CUploadedFile'))
                $model->flyer = $file_flyer;
 
            if($model->save())
            {
                if (is_object($file_flyer))
                    $model->flyer->saveAs(Yii::app()->basePath.'/../files/flyers/'.$model->flyer);
 
 
                //$this->redirect(array('update','id'=>$model->id));
 
            }
        }
 
        $this->render('update',array(
            'model'=>$model,
        ));
    }

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

#2242 report it
beninblack at 2010/11/30 07:09pm
FYI

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:

$model->image->saveAs('path/to/localFile');

To be this:

$model->image->saveAs(Yii::app()->basePath . '/../images/' . $model->image);
// As others have noted: $model->image at the end of the path is required,    // and is the filename of your image

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:

<?php echo CHtml::image(Yii::app()->baseUrl . '/images/' . $data->image, 
$data->description,
   array("class" => "clickme", "title" => $data->title, "width"=>"300", "height"=>"220")); ?>

$data->description, and $data->title are from my Image.php model, and were perfect for the tags alt text and title, respectively.

#559 report it
skyer2000 at 2010/04/26 04:33pm
Defining enctype using CActiveForm

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

#1460 report it
killermonk at 2009/07/28 01:25pm
More config Items

If you are interested in more config items, take a look at the code for the file (framework/validators/CFileValidator.php)

It gives you some small examples in the comments of how things can be used.

All of the public variables in the validator are options that can be set in the array.

Eg:

    public function rules()
    {
        return array(
            array('image', 'file',
                'types'=>'jpg, gif, png',
                'maxSize'=>1024 * 1024 * 50, // 50MB
                'tooLarge'=>'The file was larger than 50MB. Please upload a smaller file.',
            ),
        );
    }

Leave a comment

Please to leave your comment.

Write new article