Yii – Uploading and saving images

  • Yii Articles

  • Blog Subjects

  • updated:  7-Feb-2013

    A simple example of a method to upload and save images.  In this example, I created a “Photo” model that saves caption & alt text info to be displayed with the images.  If you create a similar model using Gii and then apply these changes.

    Firstly, you will need to install the image extension (cImageComponent) available from the YiiFrameworks extension library and this extension requires either GD or ImageMagick libraries.

    Controller:

    Here, I’m just showing you the create action. obviously, you will also need to code the Update and Delete actions as well.

    When uploading photos, I prefer to rename the photo with a randomly generated name and this is included in the UpdatePhoto function below.

    Also, I crunch photos to a maximum size, this stops users trying to upload their 2500px 21Mb photo! The UpdatePhoto function will also create a thumbnail and store that in a “thumbs” sub-directory.

     PHP |  copy code |? 
    01
    02
     
    03
    public function actionCreate()
    04
    	{
    05
    		$model=new Photos;
    06
     
    07
    		if(isset($_POST['Photos']))
    08
    		{
    09
                        $model->attributes=$_POST['Photos'];
    10
                        $myfile = CUploadedFile::getInstance($model,'image');
    11
                        $model->image=$myfile;
    12
     
    13
                        if($model->save())
    14
                            $this->updatePhoto($model, $myfile);
    15
     
    16
    					$this->redirect('view'.'id'=>$model->id);
    17
    		}
    18
     
    19
            $this->render('create',array(
    20
    			'model'=>$model,
    21
    		));
    22
    	}
    23
     
    24
            /*--------------
    25
            * Upload and crunch an image
    26
            ----------------*/
    27
            public function updatePhoto($model, $myfile ) {
    28
               if (is_object($myfile) && get_class($myfile)==='CUploadedFile') {
    29
                    $ext = $model->image->getExtensionName();
    30
     
    31
    		//generate a filename for the uploaded image based on a random number
    32
    		// but check that the random number has not already been used
    33
                    if ($model->filename=='' or is_null($model->filename)) {
    34
                        $model->filename = uniqid(rand(), true) . \'.\' . $ext;
    35
                    $model->filename=$filename;
    36
                    }
    37
     
    38
                    $model->save();
    39
     
    40
                    $model->image->saveAs($model->getPath());  //model->getPath see below
    41
     
    42
                    $image = Yii::app()->image->load($model->getPath());
    43
    		//Crunch the photo to a size set in my System Options Table
    44
    		//I hold the max size as 800 meaning to fit in an 800px x 800px square
    45
                    $size=$this->getOption('PhotoLarge');
    46
                    $image->resize($size[0], $size[0])->quality(75)->sharpen(20);
    47
                    $image->save(); 
    48
     
    49
    		// Now create a thumb - again the thumb size is held in System Options Table
    50
    		$size=$this->getOption('PhotoThumb');
    51
                    $image->resize($size[0], $size[0])->quality(75)->sharpen(20);
    52
                    $image->save($model->getThumbnail()); // or $image->save('images/small.jpg');
    53
                    return true;
    54
                 } else return false;
    55
            }

    View:

    The view is pretty standard, note the enctype has been changed to multipart.

    Note also, the function getThumbnail from the photo model which returns the thumbnail image.  the code for this is given below.

     PHP |  copy code |? 
    01
    02
    <div class="form" >
    03
    <div id="success">
    04
        </div>
    05
     
    06
        <?php $form=$this->beginWidget('CActiveForm', array(
    07
                'enableAjaxValidation'=>true,
    08
                'id'=>'formPhoto',
    09
            'htmlOptions'=>array('enctype'=>'multipart/form-data',
    10
                ),
    11
        )); ?>
    12
     
    13
    Fields with <span class="required">*</span> are required.
    14
    <div class="row" >
    15
                    <?php echo $model->getThumbnail(); ?>
    16
     
    17
    		<?php echo $form->labelEx($model,'filename'); ?>
    18
                    <?php echo $form->hiddenField($model, 'id'); ?>
    19
            	<?php echo $form->hiddenField($model, 'property_id'); ?>
    20
                    <?php echo CHtml::activeFileField($model, 'image'); // see comments below ?>
    21
    </div>
    22
    <div class="row">
    23
    		<?php echo $form->labelEx($model,'caption'); ?>
    24
    		<?php echo $form->textArea($model,'caption',array('rows'=>6, 'cols'=>50)); ?>
    25
    </div>
    26
    <div class="row">
    27
    		<?php echo $form->labelEx($model,'alt_text'); ?>
    28
    		<?php echo $form->textField($model,'alt_text',array('rows'=>6, 'cols'=>50)); ?>
    29
    </div>
    30
    <div class="row">
    31
    		<?php echo $form->labelEx($model,'sort_order'); ?>
    32
    		<?php echo $form->textField($model,'sort_order'); ?>
    33
    	</div>
    34
    <div class="row buttons" id="dvPhotoSubmit">
    35
    		<?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); ?>
    36
                    <?php echo CHtml::button('Cancel',array('onclick'=>"window.parent.$('#cru-dialog').dialog('close');window.parent.$('#cru-frame').attr('src','');")); ?>
    37
    </div>
    38
     
    39
    <?php $this->endWidget(); ?>
    40
    </div>
    41
     
    42
    <!-- form -->

    Model
     PHP |  copy code |? 
    01
    public function getThumbnail(){
    02
             // here i return the image
    03
                if (!empty($this->filename) && $this->filename!='')
    04
                 return CHtml::image($this->getPath(),$this->alt_text,array('width'=>options::model()->getOption('PhotoThumb').'px','max-height'=>options::model()->getOption('PhotoThumb').'px'
    05
             ));
    06
            }
    07
    	public function getPath($all=true){
    08
                if (is_null($this->_PhotoPath)) {
    09
                     // I hold the image path and system directory separator in the config/main.php
    10
                     // this is because I develop on a windows server and normally deploy on Linux
    11
                     $this->_PhotoPath=Yii::app()->params['imagePATH'];
    12
                     $this->_PathSep=Yii::app()->params['pathSep'];
    13
                }
    14
                $path=$this->_PhotoPath.$this->_PathSep;
    15
                if ($all) $path.=$this->filename;
    16
                return $path;
    17
            }

    edit:  I should have mentioned before that the model has a dummy field to store the bitmap image.  Use a variable definition ‘Public $image’ and add a validation rule as safe.  This will enable the digital image to be saved in the model by the controller using the line
     PHP |  copy code |? 
    1
    $model->attributes=$_POST['Photos'];