Yii2 File Uploads

File uploads in Yii2 are handled using yii\web\UploadedFile. Yii2 provides built-in support for handling file uploads using ActiveForm, Model Validations, and Controller Actions.


1. Setting Up the Model for File Upload

To handle file uploads, we need to define a model and configure rules.

Example: Creating a File Upload Model (UploadForm.php)

namespace app\models;
use yii\base\Model;
use yii\web\UploadedFile;
class UploadForm extends Model
{
    public $image; // For a single file
    public $documents; // For multiple files
    public function rules()
    {
        return [
            [['image'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg, jpeg', 'maxSize' => 1024 * 1024],
            [['documents'], 'file', 'extensions' => 'pdf, doc, docx', 'maxSize' => 5 * 1024 * 1024, 'maxFiles' => 5],
        ];
    }
}
  • 'extensions' => 'png, jpg, jpeg' → Restricts file types.
  • 'maxSize' => 1024 * 1024 → Limits file size to 1MB.
  • 'maxFiles' => 5 → Allows multiple uploads.

2. Creating the Upload Form in View

Use ActiveForm to create an upload form.

use yii\widgets\ActiveForm;
use yii\helpers\Html;
/* @var $model app\models\UploadForm */
?>
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]); ?>
    <?= $form->field($model, 'image')->fileInput() ?>
    
    <?= $form->field($model, 'documents[]')->fileInput(['multiple' => true]) ?>
    <?= Html::submitButton('Upload', ['class' => 'btn btn-success']) ?>
<?php ActiveForm::end(); ?>
  • 'enctype' => 'multipart/form-data' → Required for file uploads.
  • fileInput(['multiple' => true]) → Allows multiple file uploads.

3. Handling File Upload in Controller

Define the action to process uploaded files.

Example: Upload Handling in Controller (UploadController.php)

namespace app\controllers;
use Yii;
use yii\web\Controller;
use yii\web\UploadedFile;
use app\models\UploadForm;
class UploadController extends Controller
{
    public function actionIndex()
    {
        $model = new UploadForm();
        if (Yii::$app->request->isPost) {
            $model->image = UploadedFile::getInstance($model, 'image');
            $model->documents = UploadedFile::getInstances($model, 'documents');
            if ($model->validate()) {
                if ($model->image) {
                    $imagePath = 'uploads/' . $model->image->baseName . '.' . $model->image->extension;
                    $model->image->saveAs($imagePath);
                }
                foreach ($model->documents as $document) {
                    $documentPath = 'uploads/' . $document->baseName . '.' . $document->extension;
                    $document->saveAs($documentPath);
                }
                Yii::$app->session->setFlash('success', 'Files uploaded successfully!');
                return $this->refresh();
            }
        }
        return $this->render('index', ['model' => $model]);
    }
}
  • UploadedFile::getInstance($model, 'image') → Retrieves single file.
  • UploadedFile::getInstances($model, 'documents') → Retrieves multiple files.
  • saveAs('uploads/...') → Saves files to the uploads folder.

4. Creating the Upload Directory

Ensure the uploads/ folder exists and is writable.

mkdir uploads
chmod 777 uploads

5. Displaying Uploaded Files in GridView

Once files are uploaded, you might want to display them in a GridView.

use yii\grid\GridView;
use yii\helpers\Html;
use yii\helpers\Url;
<?= GridView::widget([
    'dataProvider' => $dataProvider,
    'columns' => [
        'id',
        [
            'attribute' => 'image',
            'format' => 'raw',
            'value' => function ($model) {
                return Html::img(Url::to('@web/uploads/' . $model->image), ['width' => '80px']);
            },
        ],
        [
            'attribute' => 'document',
            'format' => 'raw',
            'value' => function ($model) {
                return Html::a('Download', Url::to('@web/uploads/' . $model->document), ['target' => '_blank']);
            },
        ],
    ],
]); ?>
  • Displays an image preview.
  • Creates a download link for documents.

6. Advanced: Storing Files in Database

Instead of saving files in a directory, you can store them as binary data in MySQL.

Migration for File Storage

$this->createTable('files', [
    'id' => $this->primaryKey(),
    'filename' => $this->string()->notNull(),
    'filetype' => $this->string()->notNull(),
    'filedata' => $this->binary()->notNull(),
]);

Updating Model (FileModel.php)

namespace app\models;
use yii\db\ActiveRecord;
class FileModel extends ActiveRecord
{
    public static function tableName()
    {
        return 'files';
    }
}

Saving File in Database

$file = new FileModel();
$file->filename = $model->image->baseName . '.' . $model->image->extension;
$file->filetype = $model->image->type;
$file->filedata = file_get_contents($model->image->tempName);
$file->save();

Retrieving and Serving File from Database

$file = FileModel::findOne($id);
header("Content-Type: " . $file->filetype);
echo $file->filedata;
exit;

7. Validating File Uploads with Custom Validator

Yii2 allows creating custom file validators.

Example: Restricting Image Dimensions (ImageSizeValidator.php)

namespace app\validators;
use yii\validators\Validator;
use Yii;
class ImageSizeValidator extends Validator
{
    public function validateAttribute($model, $attribute)
    {
        $imageInfo = getimagesize($model->$attribute->tempName);
        if ($imageInfo[0] > 1000 || $imageInfo[1] > 1000) {
            $this->addError($model, $attribute, 'Image size must not exceed 1000x1000 pixels.');
        }
    }
}

Using the Validator in Model

public function rules()
{
    return [
        [['image'], ImageSizeValidator::class],
    ];
}

8. Securing File Uploads

Security Best Practices for File Uploads in Yii2: 

  • Restrict file types using 'extensions' => 'png, jpg, pdf'.
  • Validate file size to prevent large uploads.
  • Store files outside the webroot (e.g., /protected/uploads/).
  • Rename files to prevent overwriting existing ones.
  • Use hash-based filenames to avoid conflicts:
$filename = Yii::$app->security->generateRandomString() . '.' . $model->image->extension;

Recommended File Upload Method in Yii2 (Dynamic Duniya Approach)

Why This Method is Recommended

  1. Avoids Storing Files in the Database: Storing files directly in the database can increase database size unnecessarily, impacting performance.
  2. Avoids Storing Files in the Web Directory: Keeping files in the web directory can be a security risk, as sensitive files might be accessible to unauthorized users.
  3. Works with Yii2 Advanced Template: In advanced template structures, direct file storage in the web directory is not feasible, and retrieving files can become difficult.
  4. Ensures Security & Organization: By storing files outside the web directory and using structured folder paths, we improve security and manageability.

Implementation

1. Model (PhotoGalleryForm)

This model handles file uploads and storage in a structured folder system.

<?php
namespace app\models\form;
use Yii;
use app\models\PhotoGallery;
use yii\base\Model;
use yii\web\UploadedFile;
class PhotoGalleryForm extends Model
{
    public $label;
    public $upload_image;
    public $photo_gallery_model;
    public function __construct(PhotoGallery $photo_gallery_model = null)
    {
        $this->photo_gallery_model = Yii::createObject([
            'class' => PhotoGallery::className()
        ]);
        if ($photo_gallery_model) {
            $this->photo_gallery_model = $photo_gallery_model;
            $this->label = $photo_gallery_model->label;
        }
    }
    public function rules()
    {
        return [
            [['label'], 'required'],
            ['label', 'string', 'max' => 255],
            [['upload_image'], 'file', 'extensions' => 'jpg, jpeg, png, gif, bmp, tiff, tif, webp'],
        ];
    }
    public function attributeLabels()
    {
        return [
            'label' => 'Photo Label',
            'upload_image' => 'Upload Photo',
        ];
    }
    public function initializeForm()
    {
        $this->photo_gallery_model->label = $this->label;
    }
    public function savePhoto()
    {
        if ($upload_image = $this->upload_image) {
            $path = Yii::$app->params['datapath'] . '/photo-gallery';
            if (!file_exists($path)) {
                mkdir($path, 0777, true);
            }
            $path .= '/' . $this->photo_gallery_model->id;
            if (!file_exists($path)) {
                mkdir($path, 0777, true);
            }
            $file_name = 'photo-gallery-' . time() . '.' . $upload_image->extension;
            if ($upload_image->saveAs($path . '/' . $file_name)) {
                $this->photo_gallery_model->path = $file_name;
                $this->photo_gallery_model->save(false);
            }
        }
    }
}

2. Controller (PhotoGalleryController)

This controller handles the file upload request and viewing stored images.

public function actionUpload()
{
    $model = new PhotoGalleryForm();
    if ($model->load(Yii::$app->request->post())) {
        $model->upload_image = UploadedFile::getInstance($model, 'upload_image');
        if ($model->validate()) {
            $model->initializeForm();
            if ($model->photo_gallery_model->save()) {
                $model->savePhoto();
                Yii::$app->session->setFlash('success', 'File Uploaded Successfully');
                return $this->redirect(["upload"]);
            }
        }
    }
    return $this->render('upload', [
        'model' => $model,
    ]);
}
public function actionViewimage($photo_id, $image)
{
    header("Content-type: image/jpeg");
    Yii::$app->response->sendFile(Yii::$app->params['datapath'] . '/photo-gallery/' . $photo_id . '/' . $image);
}

3. Configuring params.php

Define a secure storage path for uploaded files in the params-local.php file.

return [
    'datapath' => '/var/www/html/projects/data-dynamicduniya/',
];

How This Solves the Problems

ProblemSolution
Files in the database make it heavyFiles are stored on the server instead of the database.
Web folder storage is insecureFiles are stored outside the web folder.
Yii2 Advanced Template does not allow direct file storage in webUses a separate folder in datapath for secure storage.
Difficult to retrieve files from backend storageA dedicated actionViewimage method retrieves files securely.

This method ensures better security, maintainability, and compatibility with Yii2's advanced and basic templates structure.


Conclusion

  • Yii2 provides robust support for file uploads using UploadedFile.
  • We covered single & multiple file uploads, validation, storing in DB, serving files dynamically, and security best practices.
  • Recomandeed method for file upload.s in YII2.

With these techniques, you can handle file uploads efficiently in Yii2!