Upload file in Yii 2 using FileInput widget

Are you planning to upload files in your webapp using the enhanced \kartik\widgets\FileInput widget, and not sure how to proceed further? Then read on.

Note

For advanced usage of using the FileInput widget for upload preview, update, and delete, read this follow-up web tip.

About FileInput

The FileInput widget is based on the bootstrap-fileinput plugin by Krajee. Let’s begin, but before we do that, do understand that the FileInput widget will only work with Yii Framework 2.0. This article extends and enhances a similar wiki for Yii 1.x for Yii 2.0 with usage of the FileInput widget. Here are the simple steps for you to configure the widget for upload:

Model

You must have an attribute declared to store the file name in the model class. The model class can extend either yii\base\Model or yii\db\ActiveRecord). Usually, it is good to declare a file validation rule for this attribute to ensure a file is uploaded with specific extension name. You can store the model class in any of these places for the Yii2 advanced app: app\models, backend\models, frontend\models, or common\models. Let’s say you have a model call Person as shown below, and you wish to upload an image file in an attribute named avatar and you have another field filename to store the source file name. Create a temporary attribute named image to get the uploaded file.

namespace common\models;

use yii\db\ActiveRecord;

/**
* Class Person
* @package common\models
* @package common\models
* @property int $id unique person identifier
* @property string $name person / user name
* @property array $avatar generated filename on server
* @property string $filename source filename from client
*/
class Person extends ActiveRecord
{
    /**
    * @var mixed image the attribute for rendering the file input
    * widget for upload on the form
    */
    public $image;

    public function rules()
    {
        return [
            [['image'], 'safe'],
            [['image'], 'file', 'extensions'=>'jpg, gif, png'],
        ];
    }
}

You can add others validation parameters as described in FileValidator. For instance, one can add a maxSize restriction (the PHP ini settings will of course prevail).

Controller

The upload path for your files is important. Its recommended you save it in a global parameter like Yii::$app->params['uploadPath']. For example:

Yii::$app->params['uploadPath'] = Yii::$app->basePath . '/uploads/';

Next setup your controller action for upload.

use Yii;
use common\models\Person;
use yii\web\UploadedFile;

class PersonController extends \yii\web\Controller
{
    public function actionCreate()
    {
        $model = new Person;
        if ($model->load(Yii::$app->request->post())) {
            // get the uploaded file instance. for multiple file uploads
            // the following data will return an array
            $image = UploadedFile::getInstance($model, 'image');

            // store the source file name
            $model->filename = $image->name;
            $ext = end((explode(".", $image->name)));

            // generate a unique file name
            $model->avatar = Yii::$app->security->generateRandomString().".{$ext}";

            // the path to save file, you can set an uploadPath
            // in Yii::$app->params (as used in example below)
            $path = Yii::$app->params['uploadPath'] . $model->avatar;

            if($model->save()){
                $image->saveAs($path);
                return $this->redirect(['view', 'id'=>$model->_id]);
            } else {
                // error in saving model
            }
        }
        return $this->render('create', [
            'model'=>$model,
        ]);
    }
}

View

Edit your _form.php or your other view file where you are rendering the create and image upload form.

use kartik\widgets\ActiveForm; // or yii\widgets\ActiveForm
use kartik\widgets\FileInput;
// or 'use kartik\file\FileInput' if you have only installed 
// yii2-widget-fileinput in isolation

$form = ActiveForm::begin([
    'options'=>['enctype'=>'multipart/form-data'] // important
]);
echo $form->field($model, 'filename');

// your fileinput widget for single file upload
echo $form->field($model, 'image')->widget(FileInput::classname(), [
    'options'=>['accept'=>'image/*'],
    'pluginOptions'=>['allowedFileExtensions'=>['jpg','gif','png']
]);

/**
* uncomment for multiple file upload
*
echo $form->field($model, 'image[]')->widget(FileInput::classname(), [
    'options'=>['accept'=>'image/*', 'multiple'=>true],
    'pluginOptions'=>['allowedFileExtensions'=>['jpg','gif','png']
]);
*
*/
echo Html::submitButton($model->isNewRecord ? 'Upload' : 'Update', [
    'class'=>$model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']
);
ActiveForm::end();

And thus, you should now be able to check your uploaded files in the path as set in Yii::$app->params['uploadPath']. In case you are using multiple file input, the $image variable in controller will return an array of files, which you must loop through. Its important for multiple file uploads to follow an array naming convention as mentioned in this web tip.

53 thoughts on “Upload file in Yii 2 using FileInput widget

  1. Pingback: 九州娛樂城
    1. Aleksey – not really. If you look at the example – avatar is the base db table field which stores the name of the uploaded file, while image is the file input field (not database attribute) for capturing the file input on your form.

    1. You can read the comment above. In this particular example, the avatar must be the database field (yes typically a VARCHAR in MYSQL)… that stores the filename uploaded on the server. The attribute image is a non-database field defined in the model.

  2. Nice that you included the controller actionCreate, which is the simplest action. The actionUpdate, where you need to preserve the existing uploaded file and filename db entry if no new file is uploaded but make the necessary changes if a new file is uploaded is far more difficult, yet equally necessary. How about an example on how to do that. (Preferably without the intricacies of generating some random filename which just complicates the whole thing.)

  3. i want to upload file and m puting all code avilable here….

    but error occur..

    Class ‘backend\controllers\Security’ not found….

    and i have include use yii\helpers\Security; in controller..

    so why this occur error?

    how to solved this error??

    1. This is not linked to the HTML multiple file input. You may need to read about using PHP namespaces and how to use it. The namespaces use statements need to be declared before your class declaration statement.

      1. public function actionCreate()
        {
            $model = new Authors();
            Yii::$app->params['uploadPath'] = Yii::$app->basePath . '/uploads/';
            if ($model->load(Yii::$app->request->post())) {
                $image = UploadedFile::getInstance($model, 'photo');
                $model->filename = $image->name;
                $ext = end((explode(".", $image->name)));
                $model->filename = Yii::$app->security->generateRandomString().".{$ext}"; 
                $path = Yii::$app->params['uploadPath'] . $model->photo;
                if($model->save()){
                    $image->saveAs($path);
                    return $this->redirect(['view', 'id' => $model->id]);
                }
            } else {
                return $this->render('create', [
                    'model' => $model,
                ]);
            }
        }
        

        this code is not perfect??? please check one time..
        which statement missing ??

  4. i have use this code for file upload but some error occur and not upload file ??

    this error display on controller page

    Trying to get property of non-object

    so how to solved it??

    i have use blow this code

    Yii::$app->params['uploadPath'] = Yii::$app->basePath . '/uploads/';
    if ($model->load(Yii::$app->request->post())) {
        $image = UploadedFile::getInstance($model, 'photo');
        $model->filename = $image->name;
        $ext = end((explode(".", $image->name)));
        $model->filename = Security::generateRandomKey().".{$ext}"; 
        $path = Yii::$app->params['uploadPath'] . $model->photo;
        if($model->save()){
            $image->saveAs($path);
            return $this->redirect(['view', 'id' => $model->id]);
        }
    }
    
    1. Unfortunately, I would not be able to help you debug your code. You would need to read about usage of various yii framework methods in Yii Guides/Docs. If you face further issues specific to the File Input extension – you may report it on Github.

  5. Sorry for bother you again but I am following your guide and I keep finding issues. This is happening by the continuous changes in the Yii 2 core. The Yii::$app->security->generateRandomKey() return non ASCII characters you should change it to Yii::$app->security->generateRandomString() which is safe for filename generation.

  6. Can we customize the file upload class to upload a image with the dimensions we want . I need to upload image with a specific width and height. And also the size should not exceed a certain limit say for example 1 Mb and dimension 100 by 100

  7. Hi, I’m sorry to bother you. I’m trying to use your extension to manage a single file upload but I always have the error: Class ‘kartik\widgets\FileInput’ not found

    In my _form.php I have:
    use yii\widgets\ActiveForm;
    use kartik\widgets\FileInput;
    [‘enctype’=>’multipart/form-data’]]); ?>
    field($model, ‘filename’);?>
    field($model, ‘imagefront’)-> widget(FileInput::classname(), [
    ‘options’ => [‘accept’ => ‘image/*’],
    ]);
    ?>

    I’ve installed your plugin via composer so in vendor there’s kartik-v with yii2-widget-fileinput .

    Have I to do something else? Controller is ok.
    Thank you so much

      • You need to use kartik\widgets\FileInput namespace if you have installed the yii2-widgets extension.
      • You need to use kartik\file\FileInput namespace if you have ONLY installed the yii2-widget-fileinput extension.
  8. Hi,
    I’m trying to use maxFileSize setting, so in _form.php I have:

    $form->field($model, ‘imagefront’)-> widget(FileInput::classname(), [
    ‘options’ => [‘accept’ => ‘image/*’],
    ‘pluginOptions’=>[
    ‘allowedFileExtensions’=>[‘jpg’,’jpeg’,’gif’,’png’],
    ‘maxFileSize’=> ‘2048’,
    ],

    But I always get this red prompt:

    File “filename.jpg” (74.85 KB) exceeds maximum allowed upload size of 2048 KB. Please retry your upload!

    I’ve tried with different files.

    thank you very much

  9. can you help me about error mentioned below

    Exception (Invalid Configuration) ‘yii\base\InvalidConfigException’ with message ‘The table does not exist: {{%person}}’

    in D:\xampp\htdocs\basic\vendor\yiisoft\yii2\db\ActiveRecord.php:301

  10. How to use the uploadExtraData callback function with Yii2?

    js:
    uploadExtraData: function() { // callback example
    var out = {}, key, i = 0;
    $(‘.kv-input:visible’).each(function() {
    $el = $(this);
    key = $el.hasClass(‘kv-new’) ? ‘new_’ + i : ‘init_’ + i;
    out[key] = $el.val();
    i++;
    });
    return out;
    }

    How to do it with Yii2?

    $form->field($model, ‘img’)->widget(\kartik\file\FileInput::classname(), [
    ‘options’ => [‘multiple’ => true, ‘accept’ => ‘image/*’],
    ‘pluginOptions’ => [
    ……
    ‘uploadExtraData’ => ‘function() {return {id: “222”};}’,

    ],
    ]

    I get the javascript error:
    Uncaught TypeError: Cannot use ‘in’ operator to search for ’36’ in function() {return {id: “222”};}

Leave a Reply