Image/file Upload In Yii2

I am using the widget extension by kartik-v.

I am getting the upload widget in the form, the image upload is also shown in the display box, but it is not getting saved as when I reopen the form it is blank again.

Can someone help me in getting the image upload working.

I am using this with Active Form with model.

Thanks.

Hi Pawan, I have the same problem but I tried with a simple HTML input "file" and the with the kartik-v plugin and both method returns empty in $_FILES.

I thinks it is a configuration problem but I am trying to solve it.

If i have knews i will tell you.

I fixed it.

You have to set the parameter option ‘enctype’ to the Active form


 <?php $form = ActiveForm::begin([

                'type' => ActiveForm::TYPE_HORIZONTAL,

                'options' => ['enctype'=>'multipart/form-data']

            ]); ?>

Regards

Nothing specific to my FileInput widget that focuses on capturing the file input and displaying on the client… but yes - for file uploads - set your form’s [font=“Courier New”]enctype[/font] to [font=“Courier New”]multipart/form-data[/font] as pointed out by sciolini. Check also if the attribute is set to safe in your model validation. FYI… your browser needs to support HTML5 file input (in case you are using multiple file uploads).

When I get time I may put in a wiki or something for the file uploads. You may get some information from this Yii 1.x wiki and try to use a similar approach for Yii 2.x. The key class to use in Yii2 is [font="Courier New"]\yii\web\UploadedFile[/font] instead of [font="Courier New"]CUploadedFile[/font].

You may want to check updates or discuss about the extension in the yii2-widgets forum. Had a similar query answered there.

Hi @Kartik V,

I solve the problem setting in my form enctype to multipart/form-data and when I do a var_dump($_FILES) I see all the file information. In my model i set the attribute with "safe" too, but when i do:


$physicalInvoice = new PhysicalInvoice();

$physicalInvoice->physical_number = $_POST['Bill']["physical_number"];

$file = UploadedFile::getInstance($physicalInvoice, 'image');

var_dump($file);

var_dump($_FILE);

$file is NULL, and $_FILE has values.

My form has has values of differents models, so i can not use "$model->load($_POST)" and i have to set attribute by attribute.

Do you know why UploadedFile::getInstance($physicalInvoice, ‘image’) return NULL;

‘image’ is the attribute of physicalInvoice model.

Thanks for your answer.

Regards,

1 Like

I am not sure where you are having the problem. I can test and find the UploadedFile works with the FileInput widget simply this way:

Your Model




public function rules() {

    return [

        [['image'], 'safe'],

        [['image'], 'file', 'types' => 'jpg'],

    ];

}



Your View




    use kartik\widgets\ActiveForm;

    use kartik\widgets\FileInput;


    $form = ActiveForm::begin(['options' => ['enctype'=>'multipart/form-data']]);

    echo $form->field($model, 'image')->widget(FileInput::classname(), [

        'options' => ['accept' => 'image/*'],

    ]);

    echo Html::submitButton('Submit', ['class'=>'btn btn-primary']);

    ActiveForm::end();



Your Controller




// Your controller action

public function actionUpload()

{

    $model = new Demo;

    if (!empty($_POST)) {

        $model->image = $_POST['Demo']['image'];

        $file = \yii\web\UploadedFile::getInstance($model, 'image');

        var_dump($file);


        // You can then do the following

        if ($model->save()) {

            $file->saveAs('path/to/file');

        }

        // its better if you relegate such a code to your model class

    }

    return $this->render('upload', ['model'=>$model]);

}



You get the output as below


object(yii\web\UploadedFile)#33 (5) { ["name"]=> string(6) "demo.jpg" ["tempName"]=> string(28) "X:\UniServer\tmp\phpA719.tmp" ["type"]=> string(10) "image/jpeg" ["size"]=> int(173885) ["error"]=> int(0) }

Excelent answer Kartik V. Thanks a lot.

My problem was that I not using a specific model in the form

MY VIEW


use kartik\widgets\ActiveForm;

use kartik\widgets\FileInput;


$form = ActiveForm::begin(['options' => ['enctype'=>'multipart/form-data']]);

echo FileInput::widget([

                    'name' => 'attachment',

                    'showUpload' => false,

                    'buttonOptions' => ['label' => false],

                    'removeOptions' => ['label' => false],

                    'groupOptions' => ['class' => 'input-group-lg']

                ]);

echo Html::submitButton('Submit', ['class'=>'btn btn-primary']);

ActiveForm::end();

Therefore, I had to use UploadedFile::getInstanceByName(‘attachment’) in the controller Because UploadedFile::getInstance($model, ‘attachment’) return null;

MY CONTROLLER


// Your controller action

public function actionUpload()

{

    $model = new Demo;

    if (!empty($_POST)) {

        $model->attachment = $_POST['Demo']['attachment'];

        $file = \yii\web\UploadedFile::getInstanceByName($model, 'attachment');

        var_dump($file);


        // You can then do the following

        if ($model->save()) {

            $file->saveAs('path/to/file');

        }

        // its better if you relegate such a code to your model class

    }

    return $this->render('upload', ['model'=>$model]);

}

In conclusion: if you have a form with model you should use getInstance and if you have a form without a model you should use getInstanceByName

1 Like

I have the exact same setup but my [font=“Courier New”]$_POST[‘Demo’][‘image’][/font] is an empty string.

[font="Courier New"]$_FILES[/font] is populated correctly though.

When I remove [font=“Courier New”]‘enctype’=>‘multipart/form-data’ $_POST[/font] is as expected.

I don’t really get what’s going on.

Anyway I made it work using this approach: http://www.yiiframework.com/wiki/622/upload-files-in-yii2-with-mongodb-and-gridfs/

The result is really satisfying.

I circumvented the problem with the following code, but I rewrite the filename in the model after


\yii\web\UploadedFile::getInstance($model, 'image');

Remains the problem of $__POST[‘Demo’][‘image’] = NULL

MyModel


public function rules() {

    return [

        [['image'], 'safe'],

        [['image'], 'file', 'types' => Yii::$app->controller->module->imagetype], // is 'jpg,jpeg,gif,png' from configuration

    ];

}

MyView


use kartik\widgets\ActiveForm;

use kartik\widgets\FileInput;


$form = ActiveForm::begin([

	'options' => ['enctype'=>'multipart/form-data'],

]);


echo $form->field($model, 'image')->widget(FileInput::classname(), [

        'options' => ['accept' => 'image/'.Yii::$app->controller->module->imagetype], // is 'jpg,jpeg,gif,png' from configuration

        'pluginOptions' => [

	    'previewFileType' => 'image',

	],

]);


echo Html::submitButton('Submit', ['class'=>'btn btn-primary']);

ActiveForm::end();



MyController


public function actionCreate()

    {

        $model = new Demo;


        if ($model->load(Yii::$app->request->post()) && $model->save()) 

		{		

			$imagepath = Yii::$app->controller->module->imagepath; // is dirname(dirname(__DIR__)) . '/frontend/web/img/' from configuration

			$this->uploadImage($model,$imagepath);

				

			Yii::$app->session->setFlash('success', \Yii::t('articles.message', 'Demo has been saved!'));

            return $this->redirect([

				'view', 'id' => $model->id,

			]);

        } else {

            return $this->render('create', [

                'model' => $model,

            ]);

        }

    }


// Upload Image in a select Folder

	protected function uploadImage($model,$imagepath)

	{

		$file = \yii\web\UploadedFile::getInstance($model, 'image');

		$file->saveAs($imagepath.$file->name);

		$model->image = $file->name;

		$model->save();

	}




Not related directly to the problem above - but in case you are using the widget to upload multiple files you should use the array input syntax for PHP to recognize the files as an array of files:




echo $form->field($model, 'filename[]') // note the brackets

    ->widget(FileInput::classname(), [

        'options'=>['multiple'=>true]

    ]);



Hi Kartik,

I’m trying to make this: when i go to an update form, automatically loading the name of the file (loaded from the database) and the preview.

How do I populate these fields? I have to run a js function? which one?

Did not get the question completely?

Loading a file from server and displaying in view would need to be done through PHP only. If I have time - I can post a wiki later telling how to do that and how you trigger update of this uploaded file.

If you are hinting, that the server file should be read by the FileInput widget… its not possible. Its one way behavior only (create new upload - not update). The FileInput widget can only select files from client for uploading to server (its based on the HTML file input only and is limited by the HTML File Input features).

The answer to my question was the second: the widget input file is one way. To bypass the problem, in the update view if the image is present in the database i will show it in the form with a button to remove it, else i show the widget to upload the file.

Thanks

That’s correct… its as simple as the following. You can just style the following img tags using additional div container and css to mimic it like the FileInput widget preview.




$imageUrl = self::getUploadedFile(); // get file if available from the db/server


$image = ($imageUrl == null) ? 

    Html::img('/images/default.png', ['alt' => 'No image yet']) :

    Html::img($imageUrl, ['alt' => 'User avatar']);


echo $image;


if ($imageUrl == null) { // to show FileInput only for new upload

    echo FileInput::widget($options);

}

else {

    echo Html::a('Remove Image', $deleteAction, ['class'=>'btn btn-danger']);

}



Just posted a wiki on using fileinput for reference.

Hello everyone.

Great widget but I have a problem with multiload.

The form`s input field:


echo '<label class="control-label">Add Attachments</label>';

        echo FileInput::widget([

            'model' => $model,

            'attribute' => 'image',

            'options' => ['multiple' => true]

        ]);

But the UploadedFile::getInstances($model, ‘image’) in the controller returns the array with only one file`s data.

It looks like:


Array

(

    [0] => yii\web\UploadedFile Object

        (

            [name] => LF4IchVSjy4.jpg

            [tempName] => /tmp/phpXsrkB0

            [type] => image/jpeg

            [size] => 58092

            [error] => 0

        )


)

What`s the problem? Does anyone know?

Thanks a lot!

Thanks read below.

In order for PHP to recognize MULTIPLE FILE INPUT, you must name the attribute in array format.




echo FileInput::widget([

    'model' => $model,

    'attribute' => 'image[]',

    'options' => ['multiple' => true]

]);



Refer this wiki I created for the same.

have anybody of you ever encountered this sort of issue on Yii 2.0 before? The validator for extensions of file doesn’t work because the function: FileHelper::getMimeType($file->tempName, null, false) return this: “inode/x-empty”, so that the validator always return false.

hi everyone

i am new yii2 frame work

my error is

Exception (Unknown Property) ‘yii\base\UnknownPropertyException’ with message ‘Setting unknown property: yii\validators\FileValidator::types’

in my model

============

<?php

namespace app\models;

use Yii;

/**

  • This is the model class for table "upload".

  • @property integer $file_id

  • @property string $image

*/

class Upload extends \yii\db\ActiveRecord

{

/**


 * @inheritdoc


 */


public static function tableName()


{


    return 'upload';


}





/**


 * @inheritdoc


 */

public function rules() {

return [


    [['image'], 'safe'],


    [['image'], 'file', 'types' =&gt; 'jpg'],


];


 }


/**


 * @inheritdoc


 */


public function attributeLabels()


{


    return [


        'file_id' =&gt; 'File ID',


        'image' =&gt; 'Image',


    ];


}

}

my view

=======

<?php

use yii\helpers\Html;

use kartik&#092;form&#092;ActiveForm;


use kartik&#092;widgets&#092;FileInput;


?&gt;

<?php $form = ActiveForm::begin([‘options’ => [‘enctype’=>‘multipart/form-data’]]);?>

<?php echo $form->field($model, ‘image’)->widget(FileInput::classname(), [

    'options' =&gt; ['accept' =&gt; 'image/*'],


]); ?&gt;

<?php echo Html::submitButton(‘Submit’, [‘class’=>‘btn btn-primary’]);?>

<?php ActiveForm::end(); ?>

my controler

==============

<?php

namespace app\controllers;

use Yii;

use app\models\Upload;

use yii\data\ActiveDataProvider;

use yii\web\Controller;

use yii\web\NotFoundHttpException;

use yii\filters\VerbFilter;

/**

  • UploadController implements the CRUD actions for Upload model.

*/

class UploadController extends Controller

{

public function behaviors()


{


    return [


        'verbs' =&gt; [


            'class' =&gt; VerbFilter::className(),


            'actions' =&gt; [


                'delete' =&gt; ['post'],


            ],


        ],


    ];


}





/**


 * Lists all Upload models.


 * @return mixed


 */


public function actionIndex()


{


    &#036;dataProvider = new ActiveDataProvider([


        'query' =&gt; Upload::find(),


    ]);





    return &#036;this-&gt;render('index', [


        'dataProvider' =&gt; &#036;dataProvider,


    ]);


}





/**


 * Displays a single Upload model.


 * @param integer &#036;id


 * @return mixed


 */


public function actionView(&#036;id)


{


    return &#036;this-&gt;render('view', [


        'model' =&gt; &#036;this-&gt;findModel(&#036;id),


    ]);


}





/**


 * Creates a new Upload model.


 * If creation is successful, the browser will be redirected to the 'view' page.


 * @return mixed


 */


public function actionCreate()


{


    &#036;model = new Upload();





    if (&#036;model-&gt;load(Yii::&#036;app-&gt;request-&gt;post()) &amp;&amp; &#036;model-&gt;save()) {


        return &#036;this-&gt;redirect(['view', 'id' =&gt; &#036;model-&gt;file_id]);


    } else {


        return &#036;this-&gt;render('create', [


            'model' =&gt; &#036;model,


        ]);


    }


}








public function actionUpload()

{

&#036;model = new Upload;


if (&#33;empty(&#036;_POST)) {


    &#036;model-&gt;image = &#036;_POST['Upload']['image'];


    &#036;file = &#092;yii&#092;web&#092;UploadedFile::getInstance(&#036;model, 'image');


    var_dump(&#036;file);





    // You can then do the following


    if (&#036;model-&gt;save()) {


        &#036;file-&gt;saveAs('path/to/file');


    }


    // its better if you relegate such a code to your model class


}


return &#036;this-&gt;render('upload', ['model'=&gt;&#036;model]);

}

/**


 * Updates an existing Upload model.


 * If update is successful, the browser will be redirected to the 'view' page.


 * @param integer &#036;id


 * @return mixed


 */


public function actionUpdate(&#036;id)


{


    &#036;model = &#036;this-&gt;findModel(&#036;id);





    if (&#036;model-&gt;load(Yii::&#036;app-&gt;request-&gt;post()) &amp;&amp; &#036;model-&gt;save()) {


        return &#036;this-&gt;redirect(['view', 'id' =&gt; &#036;model-&gt;file_id]);


    } else {


        return &#036;this-&gt;render('update', [


            'model' =&gt; &#036;model,


        ]);


    }


}





/**


 * Deletes an existing Upload model.


 * If deletion is successful, the browser will be redirected to the 'index' page.


 * @param integer &#036;id


 * @return mixed


 */


public function actionDelete(&#036;id)


{


    &#036;this-&gt;findModel(&#036;id)-&gt;delete();





    return &#036;this-&gt;redirect(['index']);


}





/**


 * Finds the Upload model based on its primary key value.


 * If the model is not found, a 404 HTTP exception will be thrown.


 * @param integer &#036;id


 * @return Upload the loaded model


 * @throws NotFoundHttpException if the model cannot be found


 */


protected function findModel(&#036;id)


{


    if ((&#036;model = Upload::findOne(&#036;id)) &#33;== null) {


        return &#036;model;


    } else {


        throw new NotFoundHttpException('The requested page does not exist.');


    }


}

}

what can i do for upload and save the file

please help me thanks in advance