Yii 1.1: How to upload a file using a model

65 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', 'safe' => false),
        );
    }
}

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 6 comments

#18074 report it
Larry Jr. at 2014/09/04 11:14am
My code is not uploading the file

Please Help! It's not working for me, after submitting the form nothing happened, here's my printscreen: printscreen

This is my action rule:

public function rules()
{
    return array(
        //...
                array('filename', 'file', 'types'=>'jpg, gif, png, pdf'),
        //...
    );
}

Here's my controller:

public function actionCreate()
{
    $model=new Image;
 
    if(isset($_POST['Image']))
    {
        $model->attributes=$_POST['Image'];
                $tempSave=CUploadedFile::getInstance($model, 'filename');
        if($model->save())
                           $tempSave->saveAs(Yii::app()->basePath .
                           '/../productimages/' . $model->id.'.jpg');
        $this->redirect(array('view','id'=>$model->id));
    }
 
    $this->render('create',array('model'=>$model));
}

And for the view (_form.php) I have this:

<?php $form = $this->beginWidget(
             'CActiveForm',
             array(
                 'id' => 'upload-form',
                 'enableAjaxValidation' => false,
                 'htmlOptions' => array('enctype' => 'multipart/form-data'),
             )
     ); ?>
 
  <div class="row">
    <?php echo $form->labelEx($model,'title'); ?>
    <?php echo $form->textField($model,'title',array(
                                                 'size'=>45,
                                                 'maxlength'=>45
    )); ?>
    <?php echo $form->error($model,'title'); ?>
  </div>
 
  <div class="row">
    <?php echo $form->labelEx($model,'filename'); ?>
    <?php echo $form->fileField($model,'filename',array(
                                                   'size'=>45,
                                                   'maxlength'=>45
    )); ?>
    <?php echo $form->error($model,'filename'); ?>
  </div>
 
  <div class="row buttons">
    <?php //echo CHtml::submitButton('Submit'); ?>
    <?php echo CHtml::submitButton($model->isNewRecord ? 'Upload' : 'Save'); ?>
  </div>
<?php $this->endWidget(); ?><!--CActiveForm widget-->
#15918 report it
Kostas Apazidis (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.

Also check that you have 'htmlOptions' => array('enctype' => 'multipart/form-data'), when you declare the active form - otherwise $image will stay null.

#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/

#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,
        ));
    }

Leave a comment

Please to leave your comment.

Write new article
  • Written by: qiang
  • Updated by: samdark
  • Category: Tutorials
  • Yii Version: 1.1
  • Votes: +85 / -6
  • Viewed: 358,384 times
  • Created on: Feb 4, 2009
  • Last updated: May 27, 2015
  • Tags: File upload