How to upload a file to directory in yii2? - php

i have an ActiveForm, and i want to add a field where the user can upload their photos.
the problem is that i don't have an attribute for the image in the users table and every
input field in 'yii' expects a model and an attribute as follows.
<?= $form->field($model, 'attribute')->input($platforms) ?>
i don't want to assign the image to any record nor i want to insert in in the database, i want it to be uploaded to a specific folder.
i have also checked the library kartik wrote, but also requires an attribute field.

Follow the official documentation
https://github.com/yiisoft/yii2/blob/master/docs/guide/input-file-upload.md
Form Model
namespace app\models;
use yii\base\Model;
use yii\web\UploadedFile;
/**
* UploadForm is the model behind the upload form.
*/
class UploadForm extends Model
{
/**
* #var UploadedFile|Null file attribute
*/
public $file;
/**
* #return array the validation rules.
*/
public function rules()
{
return [
[['file'], 'file'],
];
}
}
?>
Form View
<?php
use yii\widgets\ActiveForm;
$form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]); ?>
<?= $form->field($model, 'file')->fileInput() ?>
<button>Submit</button>
<?php ActiveForm::end(); ?>
Controller
Now create the controller that connects form and model together:
<?php
namespace app\controllers;
use Yii;
use yii\web\Controller;
use app\models\UploadForm;
use yii\web\UploadedFile;
class SiteController extends Controller
{
public function actionUpload()
{
$model = new UploadForm();
if (Yii::$app->request->isPost) {
$model->file = UploadedFile::getInstance($model, 'file');
if ($model->validate()) {
$model->file->saveAs('uploads/' . $model->file->baseName . '.' . $model->file->extension);
}
}
return $this->render('upload', ['model' => $model]);
}
}
?>
Instead of model->load(...) we are using UploadedFile::getInstance(...). [[\yii\web\UploadedFile|UploadedFile]] does not run the model validation. It only provides information about the uploaded file. Therefore, you need to run validation manually via $model->validate(). This triggers the [[yii\validators\FileValidator|FileValidator]] that expects a file:
$file instanceof UploadedFile || $file->error == UPLOAD_ERR_NO_FILE //in code framework
If validation is successful, then we're saving the file:
$model->file->saveAs('uploads/' . $model->file->baseName . '.' . $model->file->extension);
If you're using "basic" application template then folder uploads should be created under web.
That's it. Load the page and try uploading. Uplaods should end up in basic/web/uploads.

in your view
use kartik\widgets\ActiveForm;
use kartik\widgets\FileInput;
$form = ActiveForm::begin(['options' => ['enctype'=>'multipart/form-data']]); //important
echo FileInput::widget([
'name' => 'filename',
'showUpload' => false,
'buttonOptions' => ['label' => false],
'removeOptions' => ['label' => false],
'groupOptions' => ['class' => 'input-group-lg']
]);
echo Html::submitButton('Submit', ['class'=>'btn btn-primary']);
ActiveForm::end();
in your controller
$file = \yii\web\UploadedFile::getInstanceByName('filename');
$file->saveAs('/your/directory/'.$file->name);

Create a read only attribute for your model like public $imageand proceed like
<?= $form->field($model, 'image')->fileInput() ?>

I really like Yii2 Dropzone.
Installation:
composer require --prefer-dist perminder-klair/yii2-dropzone "dev-master"
Usage:
<?php
echo \kato\DropZone::widget([
'options' => [
'url'=> Url::to(['resource-manager/upload']),
'paramName'=>'image',
'maxFilesize' => '10',
],
'clientEvents' => [
'complete' => "function(file){console.log(file)}",
'removedfile' => "function(file){alert(file.name + ' is removed')}"
],
]);
?>
Controller:
public function actionUpload(){
$model = new ResourceManager();
$uploadPath = Yii::getAlias('#root') .'/uploads/';
if (isset($_FILES['image'])) {
$file = \yii\web\UploadedFile::getInstanceByName('image');
$original_name = $file->baseName;
$newFileName = \Yii::$app->security
->generateRandomString().'.'.$file->extension;
// you can write save code here before uploading.
if ($file->saveAs($uploadPath . '/' . $newFileName)) {
$model->image = $newFileName;
$model->original_name = $original_name;
if($model->save(false)){
echo \yii\helpers\Json::encode($file);
}
else{
echo \yii\helpers\Json::encode($model->getErrors());
}
}
}
else {
return $this->render('upload', [
'model' => $model,
]);
}
return false;
}

give this code after your uploaded code
//save the path in DB..
$model->file = 'uploads/'.$imageName.'.'.$model->file->extension;
$model->save();

If you have more than one file while uploading you must use foreach for that. And you should actual name of file in a column in table and a encrypted value of that name has to be stored to avoid duplicated in the directory.. Something like this..
$userdocs->document_name = UploadedFile::getInstances($userdocs, 'document_name');
foreach ($userdocs->document_name as $key => $file) {
$img_name = Yii::$app->security->generateRandomString();
$file->saveAs('user/business_files/' . $img_name . '.' . $file->extension);
$images = $img_name . '.' . $file->extension;
$userdocs->actual_name = $file->name;
$userdocs->user_id = $user->id;
$userdocs->document_name = $images;
$userdocs->save(false);
$userdocs = new UserDocs();
}
Here a random string is generated and it will be assign with the name of the document, and it will be stored in the table. The UserDocs is the model name.

Related

Yii Framework File Upload

I'm trying to learn how to upload an image file in Yii. I'm using this code
<?php
use yii\widgets\ActiveForm;
?>
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'imageFile')->fileInput() ?>
<button>Submit</button>
<?php ActiveForm::end() ?>
in ProjectFile/views/site/upload.php file.
The problem is in
<?= $form->field($model, 'imageFile')->fileInput() ?>
$model gives me a red underline. I have looked many examples and all of them wrote the like this.
What I need to do stop this problem?
Edit:
Is inside the controller/SiteController.php
// function for upload
public function actionUploadImage()
{
$model = new UploadImageForm();
if (Yii::$app->request->isPost) {
$model->imageFile = UploadedFile::getInstance($model, 'imageFile');
if ($model->upload()) {
// file is uploaded successfully
return;
}
}
return $this->render('upload', ['model' => $model]);
}
Is inside of models/UploadImageForm.php
<?php
namespace app\models;
use yii\base\Model;
use yii\web\UploadedFile;
class UploadImageForm extends \yii\base\Model
{
public $imageFile;
// gives rules of how to upload picture
public function rules(){
return [
[['imageFile'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg'],
];
}
// uploads picture
public function upload(){
if($this->validate()){
$this->imageFile->saveAs('uploads/' . $this->imageFile->baseName . '.' . $this->imageFile->extension);
}
}
}
Please make sure that model has attribute/field called "imageFile"
Check your editor do you get red line on your editor then its your editor related issue
The same happened to me, your view code is pretty fine. Mine was also the same, I made it work by using these lines in model function:
$imageFile= UploadedFile::getInstances($model, 'imageFile')[0];
$imageFile->saveAs('uploads/' . $imageFile->baseName . '.' . $imageFile->extension);
and in controller action:
$model->imageFile= UploadedFile::getInstances($model, 'imageFile')[0];
In views\upload.php the red underline is shown because the system can't find the $model. While running, program will connect $model to controller. So the red underline is not a problem for php files.

Yii 2 How add a custom validation check on file upload

I am building a CSV uploader and I want to add a custom validation function that will check the header row of the CSV file to ensure the correct columns are in place.
I am trying to put a custom validation rule in the model to do this but failing at the first hurdle.
I am getting
Setting unknown property: yii\validators\FileValidator::0
exception but as far as I can tell from the documentation this should work.
Model
/**
* UploadForm is the model behind the upload form.
*/
class UploadForm extends Model
{
/**
* #var UploadedFile file attribute
*/
public $file;
/**
* #return array the validation rules.
*/
public function rules()
{
return [
[['file'], 'file', 'extensions' => 'csv', 'checkExtensionByMimeType'=>false, 'headerCheck', 'skipOnEmpty' => false]
];
}
public function attributeLabels(){
return [
'file'=>'Select csv'
];
}
function headerCheck($attribute, $params, $validato){
$this->addError($attribute, "error");
}
}
Controller function:
public function actionUpload()
{
$model = new UploadForm();
if (Yii::$app->request->isPost) {
$model->file = UploadedFile::getInstance($model, 'file');
$filename = $model->file->baseName . '.' . $model->file->extension;
if ($model->file && $model->validate()) {
$upload = $model->file->saveAs('uploads/'.$filename );
if($upload){
define('CSV_PATH','uploads/');
$csv_file = CSV_PATH . $filename;
$filecsv = file($csv_file);
foreach($filecsv as $data){
$lines = explode(',',$data);
$t=1;
}
}
}
}
return $this->render('csvUpload', ['model' => $model]);
}
View
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'file')->fileInput() ?>
<button>Submit</button>
<?php ActiveForm::end() ?>
Why is headerCheck() not getting picked up as a custom validation function?
Short Answer
Your rules should be written like so:
return [
[['file'], 'file', 'extensions' => 'csv', 'checkExtensionByMimeType'=>false, 'skipOnEmpty' => false],
[["file"], "headerCheck"],
];
Note that your validation rule, "headerCheck", is a separate item in the array.
Long Answer
A rule's structure is like so:
[["attributes_to_validate"],"vaildatorCallback","param1"=>"value","param2"=>"value]
Note the first two items are the attributes and the callback respectively, and then after that you can specify params that should be assigned to the validator, or passed to your validator callback. These params are expected in a form where the key is the name of the property, and the value is the value to assign to the property.
In the example you provided, Yii sees that you want to utilize the "file" validator, so it creates an instance of yii\validators\FileValidator. It then sees that you want the parameter "extensions" set to "csv", so it does:yii\validators\FileValidator::$extensions = "csv"; But then, because you have included your custom validator in this part of the array, it thinks that "headerCheck" is actually a value of a property you want to assign to the validator. Because you have entered this "param" without a key, the key defaults to 0 and so Yii thinks the property you want to assign is called '0'. Thus, Yii attempts this: yii\validators\FileValidator::0 = "headerCheck";
Of course, there is no property '0' on FileValidator, and so that's where the error you're getting is coming from.

image is not uploading in YII ActiveForm

I am new to Yii. I am using this code
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]); ?>
<?= $form->field($model, 'description')->textarea(['rows' => 6]) ?>
<?= $form->field($model, 'image')->fileInput(['type' => 'file']) ?>
<?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
When i try to print post data in my controller then image field is going blank;
If i print through $_FILES then file data is showing.
Please let me know how to get image in post method.
Step 1 :
In your model file define one variable.
public $uploadedImage;
Step 2 :
In your controller,
$model->uploadedImage = UploadedFile::getInstance($model, 'image');
$model->image = $model->uploadedImage->name;
After save() method write this to store image
$model->uploadedImage->saveAs('YOUR_WEBDIR_IMAGES_FOLDER/' . $model->uploadedImage->baseName . '.' . $model->uploadedImage->extension);
[If the above solution doesn't work then try this. :
Define another variable.
public $tempVarforImage;
In your controller
$model->tempVarforImage = $model->uploadedImage->name;
$model->image = $model->tempVarforImage;
(Because once I faced the issue in confliction of 'image' field from database and yii2 based 'image' variable)]
Create UploadForm model
namespace app\models;
use yii\base\Model;
use yii\web\UploadedFile;
class UploadForm extends Model{
public $image;// Image name
public function rules()
{
return [
[['image'], 'file'/* , 'skipOnEmpty' => false *//* , 'extensions' => 'png, jpg' */],
];
}
public function upload($fileName)
{
if ($this->validate()) {
$this->image->saveAs($fileName);
return true;
} else {
return false;
}
}
}
Controller code
Add at top of your file
use app\models\UploadForm;
use yii\web\UploadedFile;
Add this in your function
$model = User();
if ($model->load(Yii::$app->request->post())) {
$model1 = new UploadForm();
$model1->image = UploadedFile::getInstance($model, 'image');
$fileName = $model1->image->baseName.'_'.time();
$extension = $model1->image->extension;
$fileName = $fileName.'.'.$extension;
$filePath = WEBSITE_SLIDER_ROOT_PATH.$fileName;
if ($model1->upload($filePath)) {
//Save in database
}
}

Yii2 FileInput - Trying to get property of non object

i am using Yii2 and Kartik's FileInput extension and I have successfully get the file uploads working(only single upload). My problem now is that, I get the error as in the title(with logs attached) if I did not choose any files(It should be optional).
After much searching over the internet, I think it has to be something to do with array, but I am not sure how to fix that, especially even with the logs pointing to the exact line!
Here is my log,
Here is my model,
namespace app\models;
use Yii;
class FormMovement extends \yii\db\ActiveRecord
{
public $file;
public static function tableName()
{
return 'form_movement';
}
public function rules()
{
return [
[['fm_date_received', 'fm_form_name', 'fm_from', 'fm_ptj'], 'required'],
[['form_id'], 'integer'],
[['fm_date_received', 'fm_date_action1', 'fm_date_action2','fm_upload'], 'safe'],
[['fm_form_name', 'fm_note'], 'string', 'max' => 500],
[['fm_from', 'fm_ptj', 'fm_action1', 'fm_action2'], 'string', 'max' => 100],
[['file'], 'file', 'skipOnEmpty' => true, 'extensions'=>'jpg,pdf,png,doc,docx,xls,xlsx, jpeg', 'maxFiles' => 3],
];
}
My controller function, the log shows that it is at the line 75, which is this one,
$model->fm_upload='uploads/'.$fileName.'.'.$model->file->extension;
Been tinkering with it, but no success.
public function actionCreate()
{
$model = new FormMovement();
if ($model->load(Yii::$app->request->post())) {
//set the file name
$fileName = $model -> fm_form_name;
//get instance
$model->file = UploadedFile :: getInstance($model, 'file');
//set the file path in the db
$model->fm_upload='uploads/'.$fileName.'.'.$model->file->extension;
//save the file to the server directory
$model->save();
$model->file->saveAs('uploads/'.$fileName.'.'.$model->file->extension);
return $this->redirect(['view', 'id' => $model->form_id]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
Finally my view,
<div class="form-group kv-fieldset-inline">
<?= Html::activeLabel($model, 'file[]', [
'label'=>'MUAT NAIK FAIL',
'class'=>'col-sm-1 control-label'
]) ?>
<div class="col-sm-8">
<?= $form->field($model, 'file',[
'showLabels'=>false
])->widget(FileInput::classname(), [
'options' => ['accept' => 'file/*', 'multiple' => 'true'],
'pluginOptions'=>[
'showUpload' => false,
]
]) ?>
</div>
</div>
This part should be refactored:
//set the file name
$fileName = $model -> fm_form_name;
//get instance
$model->file = UploadedFile :: getInstance($model, 'file');
//set the file path in the db
$model->fm_upload='uploads/'.$fileName.'.'.$model->file->extension;
//save the file to the server directory
$model->save();
$model->file->saveAs('uploads/'.$fileName.'.'.$model->file->extension);
like this:
$model->file = UploadedFile::getInstance($model, 'file');
$model->save();
if ($model->file) {
$model->fm_upload = "uploads/{$model->fm_form_name}.{$model->file->extension}";
$model->file->saveAs("uploads/{$model->fm_form_name}.{$model->file->extension}");
}
Also note that you don't handle failed validation in your controller at all.
For further refactoring, this line:
$model->file = UploadedFile::getInstance($model, 'file');
can be moved to beforeValidate() event handler.
This part:
if ($model->file) {
$model->fm_upload = "uploads/{$model->fm_form_name}.{$model->file->extension}";
$model->file->saveAs("uploads/{$model->fm_form_name}.{$model->file->extension}");
}
can be moved to afterSave() event handler to keep your controller slim.
In saveAs() it's better to use alias, I desribed it in this answer.

multiple file upload and save data in database in yii2

when i upload multiple files in Yii2, i am getting following error and cannot insert data into database:
finfo_file(C:\xampp\tmp\phpCACD.tmp): failed to open stream: No such
file or directory
controller file:
public function actionGallery($id)
{
$model = new Gallery();
if (Yii::$app->request->post()) {
$model->imageFiles = UploadedFile::getInstances($model,'imageFiles');
foreach ($model->imageFiles as $file) {
$imageName = Yii::$app->security->generateRandomString();
$model->added_date = date('Y-m-d');
$model->emp_id = $id;
$file->saveAs('uploads/emp/' . $imageName . '.' . $file->extension);
$originalFile = EMP_PROFILE_ORIGINAL.$imageName.'.'.$file->extension;
$thumbFile = EMP_PROFILE_THUMB.$imageName.'.'.$file->extension;
Image::thumbnail($originalFile, 200, 200)->save($thumbFile, ['quality' => 80]);
$model->save();
}
}
return $this->render('gallery', [
'gal' => $model
]);
}
view file:
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
use yii\grid\GridView;
?>
<div class="posts-form">
<div class="wrapper-md">
<div class="row">
<div class="col-sm-8">
<div class="panel panel-default">
<div class="panel-body">
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]); ?>
<?= $form->field($gal, 'imageFiles[]')->fileInput(['multiple' => true, 'accept' => 'image/*']) ?>
<div class="form-group">
<button class="btn btn-success">Submit</button>
<a class="btn btn-default" href="<?=\Yii::$app->urlManager->createUrl('post')?>">Cancel</a>
</div>
<?php ActiveForm::end(); ?>
</div>
</div>
</div>
</div>
</div>
</div>
but i am getting above error. I cannot find the solution for this.
first, in model you must have 2 variable that will save the images and the name of it.
`
* #property string $image_name
*/
class Gallery extends \yii\db\ActiveRecord
{
**public $fileImage=[];**
public static function tableName(){
`
in this case I use $image_name that is one of my model column, and $fileImage, $fileImage is an array that will be used to upload the image,
:)
then in controller
$model = new Gallery(); // this variable is only used to check if everything is valid
if ($model->load(Yii::$app->request->post())) {
$model->fileImage = UploadedFile::getInstances($model,'fileImage');
$a=0;
foreach ($model->fileImage as $file) {
$a++;
$model1 = new Gallery();
$file->saveAs("images/test".$a.".".$file->extension);
$model1->image_url="images/test.".$a.".".$file->extension;
$model1->image_name = "".$a;
$model1->save();
}
return $this->redirect(['index']);
} else {
return $this->render('create', [
'model' => $model,
]);
}
I think thats all. . .
You can use
$sql = 'INSERT INTO `table`(`id`, `col1`, `col2`, `path`) VALUES (Null,"'.($model2->col1).'","'.($model2->col2).'","'.($model2->path).'")';
$command = \Yii::$app->db->createCommand($sql);
$command->execute();
instead of $model->save();
I made an example,
so the whole code in controller would be:
public function actionCreate()
{
$model = new Planet();
if ($model->load(Yii::$app->request->post()) ) {
$model->file = UploadedFile::getInstances($model, 'file');
foreach ($model->file as $file) {
$model2 = new Planet();
$model2->load(Yii::$app->request->post());
$model2->path='uploads/' . $file;
$sql = 'INSERT INTO `planet`(`id`, `name`, `s_id`, `path`) VALUES (Null,"'.($model2->name).'","'.($model2->s_id).'","'.($model2->path).'")';
$command = \Yii::$app->db->createCommand($sql);
$command->execute();
$file->saveAs('uploads/' . $file->baseName . '.' . $file->extension);
}
return $this->render('view', [
'model' => $model,
]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
It works for me.
edit: also you can use $model2->save(false); It worked in my case.
Call $model->save()
before
$model->file->saveAs();
I was having the exact same problem
*I think you forget to create uploads and emp folder or maybe you use wrong folder name, please check your folder name...
*If you want to save the name of that file, you should use different variable (two variable) that will be used to save the images and the name of that images,

Categories