Error "Please upload a file".

Hi All,

I have a form for user to upload CSV file. I want to make this upload compulsory but do not want to save this CSV file into my system, I just want to read CSV content and save the data into database table. When I run save(), it prompting I need to upload a file but in fact I had selected the file to upload but still prompt error. When I remove "csvfile" attribute from model, it will work fine and able to save without issue. Is there any way to resolve this issue?

Error when save:

Array ( [csvfile] => Array ( [0] => Please upload a file. ) )

Admin controller :

$model->form_id=$_POST[‘Accesscontrol’][‘form_id’];

$model->form_field=$_POST[‘Accesscontrol’][‘form_field’];

$model->rec_date=date("Y-m-d H:i:s");

$model->save();

The following rules in Model will prompt error need to upload file

public function rules()

{


   // file max 5 Mb


    return [


        [['form_id','form_field'], 'required'],


        [['form_id'], 'integer'],


        [['form_field'], 'string', 'max' => 20],


        [['csvfile'], 'file', 'skipOnEmpty' => false, 'extensions' => 'csv', 'maxSize'=>'5000000'],


        [['csvfile'], 'required']


    ];

}

The following rules in Model working fine after remove "csvfile"

public function rules()

{


   // file max 5 Mb


    return [


        [['form_id','form_field'], 'required'],


        [['form_id'], 'integer'],


        [['form_field'], 'string', 'max' => 20],


    ];

}

Just save it to a temporary file, read it, save the data into db, and remove it.

Thanks for your answer. In fact I’m able to save temporary file, read it but an error message prompted (

"Array ( [csvfile] => Array ( [0] => Please upload a file. ) )" ) when save. This is due to following Model Rules on "csvfile". If I remove "csvfile" attribute from the Rules, everything will go fine but I will not able to control upload file size, upload file type, required field etc.

Can I still want control my upload Form Rules but do not want to save uploaded file during save() ?

public function rules()

{


   // file max 5 Mb


    return [


        [['form_id','form_field'], 'required'],


        [['form_id'], 'integer'],


        [['form_field'], 'string', 'max' => 20],


        [['csvfile'], 'file', 'skipOnEmpty' => false, 'extensions' => 'csv', 'maxSize'=>'5000000'],


        [['csvfile'], 'required']


    ];

}

‘required’ validator is not necessary for file uploading. Setting ‘skipOnEmpty’ to false will do the job.




public function rules()

    {

       // file max 5 Mb

        return [

            [['form_id','form_field'], 'required'],

            [['form_id'], 'integer'],

            [['form_field'], 'string', 'max' => 20],

            [['csvfile'], 'file', 'skipOnEmpty' => false, 'extensions' => 'csv', 'maxSize'=>'5000000'],

            // [['csvfile'], 'required']

        ];

   }



Same issue with following rules … "Array ( [csvfile] => Array ( [0] => Please upload a file. ) )"

public function rules()

{


    return [


        [['form_id','form_field'], 'required'],


        [['form_id'], 'integer'],


        [['form_field'], 'string', 'max' => 20],


        [['csvfile'], 'file', 'skipOnEmpty' => false, 'extensions' => 'csv', 'maxSize'=>'5000000']


    ];


}

Please show us your controller code.

Probably the following section of the guide will be a great help.

http://www.yiiframework.com/doc-2.0/guide-input-file-upload.html

Here is my controller code…




public function actionCreate()

    {  

        $model = new Accesscontrol();

      

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

            {


            // read csv and import into table

                $file = UploadedFile::getInstance($model, 'csvfile');


                if ($model->upload() &&  $file->size > 0 && $model->validate())

                   {


                     $model->form_id=$_POST['Accesscontrol']['form_id'];

                     $model->form_field=$_POST['Accesscontrol']['form_field'];

                     $model->rec_date=date("Y-m-d H:i:s");

                     $model->save();


                     $file_content = fopen($file->tempName, "r");

                     while (($getData = fgetcsv($file_content, 10000, ",")) !== FALSE)

                            {

                                echo "<br>$count : ".$getData[0];

                                $count++;

                             }


                     fclose($file_content); 

		   }

             }

    }



Is the temp directory writable by the web server? I’ve seen some strange things when this was the cause, or php.ini on the server didn’t set up a file transfer directory

Also, you have a validate() if the if() condition, then a save() in the body of the if(). Could it be that you windup validating twice? I haven’t gotten into this too much in Yii2, but in Yii1 there was a ->save(false). This would save without revalidation.

And just a nit-pick: 50000000 is not 50Mb, it’s 50 million bytes. 50Mb = 52428800 bytes ;D

The php.ini file takes a string for maxFileSize. It defaults to ‘20MB’, but if you set the maxSize = 20000000, a file that shows as 20Mb in the directory browser may not be accepted as being too big. I’ve run into this problem before. I had set up to allow 29MB uploads, user tried to upload 19.3MB file, error “too big”. When I change the rule maxSize to 20,971,520 problems went away.

As you see in the sample code of the guide, you should set $model->csvfile with an instance of UploadedFile before you validate the model.




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

            {


            // read csv and import into table

                // $file = UploadedFile::getInstance($model, 'csvfile');

                $model->csvfile = $file = UploadedFile::getInstance($model, 'csvfile');


                if ($model->upload() &&  $file->size > 0 && $model->validate())

                   {



And please use code tags in your post. :)

Even I remove validate() from IF(), the result still same "Array ( [csvfile] => Array ( [0] => Please upload a file. ) )"

I believe this is nothing to do with the setting because if I remove "csvfile" attribute from the Rules, the program is able to save without any issue.

To clarify, from the Rules, I put ‘maxSize’=>‘5000000’ which is equivalent to 5Mb right?

Sorry I misread 5MB as 50MB.

5MB = 5,242,880 Bytes

I’m thinking that @softark may have it right. $model->csvfile may not actually have a file in it until the getInstance() call. I know that php uploads the file to the tmp directory. Yii gets somekind of reference to it in the field, but it is not an actual file that you can reference until the getInstance() thing.

Now prompting following error and even I select file with csv extension.

Array ( [csvfile] => Array ( [0] => Only files with these extensions are allowed: csv. ) )

Please note : In my table, I don’t have field to store CSV file but my purpose of this upload is to read the file content only.

Make sure you have


public $csvfile;

at the top of your model. This will allow $model->csvfile referencing.

Are you on a Windows machine? Is the extension actually ‘csv’ and not ‘CSV’? Linux is case sensitive, Windows is not, but php/Yii may be sensitive.

Try to allow extensions=>‘csv, CSV’.

Same error

Array ( [csvfile] => Array ( [0] => Only files with these extensions are allowed: csv, csv. ) )

Yes, this is Windows machine. I can upload and save without issue with following RULES


       


return [

            [['form_id','form_field'], 'required'],

            [['form_id'], 'integer'],

            [['form_id'], 'unique'],            

            [['form_field'], 'string', 'max' => 20],

        ];




It will NOT able to save with following RULES




        return [

            [['form_id','form_field'], 'required'],

            [['form_id'], 'integer'],

            [['form_field'], 'string', 'max' => 20],

            [['csvfile'], 'file', 'skipOnEmpty' => false, 'extensions' => 'csv,CSV', 'maxSize'=>'5000000']

        ];



I’m at a loss :huh:

Looking at the file validator source code

Is the php fileinfo extension enabled?

Comments in the validator also indicate that ‘extensions’=> is case insensitive, so the ‘CSV’ is not needed.

Following the validator code, it uses:


strtolower(pathinfo($this->name, PATHINFO_EXTENSION));

to get the extension. ‘$this->name’ is just a filename.

As a test, try to use pathinfo() in your code somewhere, like index.php.


<?= pathinfo('madeupfilename.csv', PATHINFO_EXTENSION) ?>

You could also run the ‘requirements.php’ file that comes with Yii. It has a check for FileInfo extension.

I agree with @jkofsky. You should check fileinfo extension.

And try the following for testing:




        return [

            [['form_id','form_field'], 'required'],

            [['form_id'], 'integer'],

            [['form_field'], 'string', 'max' => 20],

            [['csvfile'], 'file', 'skipOnEmpty' => false, 'extensions' => 'csv',

                 'checkExtensionByMimeType' => false, 'maxSize' => 5000000]

        ];



http://www.yiiframework.com/doc-2.0/yii-validators-filevalidator.html#$checkExtensionByMimeType-detail

Great job!! This is functioning after change the proposed Rules. Thanks so much for your help and effort.

Was it fileInfo or mimeType?

IIRC, by setting checkExtensionByMimeType to false you could perform the file validator without fileInfo extension, since the mimeType is determined using fileInfo reading the file contents (not by simple checking of the extension).

Of course, we should enable fileInfo anyway.