Laravel multiple file upload - laravel

I am trying to upload files (they can be any type), and I have a problem uploading file with certain way.
I am able to upload a file correctly using $request->file('file_name') and Storage::disk($disk)->put($path, $file);. However, $file parameter can only be through $request->file('file_name').
However, because of the way I want to upload multiple orders with multiple files like below:
Controller
foreach ( $filesArray as $key => $files ) {
$path = 'order/'.$order->id;
if ( isset($files[$i]) && !empty($files[$i]) ) {
for ( $j = 0; $j < count($files[$i]); $j++ ) {
$uploadedFile = FileHelper::upload($files[$i][$j], $path);
$orderFile = [];
$orderFile['order_id'] = $order->id;
$orderFile['file_id'] = $uploadedFile->id;
OrderFileModel::create($orderFile);
}
}
}
FileHelper
static public function upload($file, $path, $disk = 's3')
{
$fileOrm = new FileModel;
$fileOrm->size = $file->getSize();
$fileOrm->extension = $file->getExtension();
$fileOrm->bucket_name = self::$BUCKET_NAME;
$fileOrm->type = self::getFileType($file->getExtension());
$fileOrm->key = Storage::disk($disk)->put($path, $file);
$fileOrm->created_time = now();
$fileOrm->save();
return $fileOrm;
}
I've also attached images where I see the difference.
One with $request->file('file_name') and the other with just $request->file_name which is blob type.
The image below would return error saying fstat() expects parameter 1 to be resource, object given
How could I solve this problem?
Any advice or suggestion would be appreciated. Thank you.

Do you get your file list to use $request->files? If you do, change to $request->allFiles(). This method will convert File object to UploadedFile object.

Actually just put an array in your input file like this
<input type="file" name="files[]">
<input type="file" name="files[]">
<input type="file" name="files[]">
<input type="file" name="files[]">
NOTE: you need to enctype="multipart/form-data" enabled in your form.
Then in your controller, you can loop the input file by doing such
foreach($request->file('files') as $index => $file){
// do uploading like what you are doing in your single file.
}

Try:
$this->validate($request, [
'files.*' => 'file|mimes:...'
]);
foreach ($request->files as $file) {
$fileName = (string)Str::uuid() . '.' . $file->getClientOriginalExtension();
try {
if (\Storage::disk('s3')->put($fileName, file_get_contents($file))) {
FileModel::create([
'size' => '...',
'extension' => '...',
'bucket_name' => '...',
'type' => '...',
'key' => '...',
'created_time' => '...'
]);
}
} catch (\Exception $e) {
// ...
}
}

You might have been lucky before that some type casting on your $image object made a string out of it, I guess a simple chnage of your last line to
$disk->put($path, $file->__toString());
will fix the problem and is safer anyway as the "put" method officially only accepts strings (and looking at the implmentation also php resources). That should keep you compatible to changes in the long run.

Related

Make request (pass data) from Command File to Controller in Lumen/Laravel

i get data (query) in command file and want to pass to controller via API (route)
here my request code in command file :
$request = Request::create('/create_data_account', 'post', ['data'=>$data]);
$create = $app->dispatch($request);
this is the route :
$router->post('/create_data_account', 'APIController#create_account_data_api');
and my controller :
public function create_account_data_api(Request $request)
{
$count = 0;
foreach ($data as $key => $value) {
$insert = Account::create([
'account_name' => $value->account_name,
'type' => $value->type,
'role_id' => $value->role_id
]);
if($insert){
$count++;
}else{
return $response = ['result'=>false, 'count'=>$count, 'message'=>'Internal error. Failed to save data.'];
}
}
return $response = ['result'=>true, 'count'=>$count, 'message'=>'Account data saved Successfully'];
}
i'm confused why passing data to controller not working with that code. anyone can give me solution ? Thanks
As you are making the request with ['data'=>$data]. That means all the data is contained on the key data of your array. So before the foreach loop, you need to add a declaration statement $data = $request->input('data'); to get data in $data variable.

How to upload multiple images with base64 in laravel & vue-js

I have been trying to upload multiple images with base64 but it uploads only the second one.
and Is there any easy way to upload images in larvel-vueJS instead of base 64.
this is the Vue-js method:
updateIMG(e){
// console.log('uploaded');
let file = e.target.files[0]
let reader = new FileReader();
if(file['size'] < 9111775){
reader.onloadend = (file) => {
this.landingform.logo = reader.result;
this.landingform.landingBg = reader.result;
}
reader.readAsDataURL(file)
}else {
swal.fire({
icon: 'error',
title: 'Oops...',
text: 'You are uploading a large fiel!',
footer: 'You are authorized to upload files less than 10MB.'
})
}
the method called like this:
<input type="file" #change="updateIMG" name="logo" class="form-input">
and this is my controller:
public function updateLanding(Request $request)
{
$landnginIMG = LandingImage::whereIn('id', [1]);
if ($request->logo){
$name = time().'.' . explode('/', explode(':', substr($request->logo, 0,
strpos($request->logo, ';')))[1])[1];
\Image::make($request->logo)->save(public_path('img/landing/').$name);
$request->merge(['logo' => $name]);
};
if ($request->landingBg){
$bgname = time().'.' . explode('/', explode(':', substr($request->landingBg, 0,
strpos($request->landingBg, ';')))[1])[1];
\Image::make($request->landingBg)->save(public_path('img/landing/').$bgname);
$request->merge(['landingBg' => $bgname]);
};
$landnginIMG->update([
'logo'=> $request ['logo'],
'landingBg'=> $request ['landingBg'],
]);
return ['message' => 'all is done'];
}
There are a few factors your must follow.
First
Your form should let you select multiple files
Second
Your JavaScript must handle all of those files when selected. Check this line of your code.
// console.log('uploaded');
let file = e.target.files[0]
let reader = new FileReader();
e.target.files[0] is taking the first file. You should loop and go through all files.
let files = e.target.files;
Now, use JavaScript foreach loop and convert each file to base64 and store them on array. Then, send that array to sever.
On the server, do the same. You will receive an array so you should loop through each and convert it back to image and save it.
Thanks.
Pls check if this helps:
Vuejs example of multiple image upload https://picupload.netlify.app/
VueJS code repo https://github.com/manojkmishra/dw_take5
Concerned File- https://github.com/manojkmishra/dw_take5/blob/master/src/components/ImageUploader.vue
PHP[Laravel] part is behind firewall so upload submission will not work outside intranet. Here is the controller function code
public function imagesupload(Request $request){
if (count($request->images)) {
foreach ($request->images as $image) {
$image->store('images');
}
}
return response()->json(["message" => "Done"]);
}

how to validate that image uploaded must be multiple while submitting form in laravel?

how to validate that image uploaded must be multiple while submitting form in laravel?I mean when user upload only single image,then return back.
try this. its hardcoded. hope it gives you insight on what to do:
'filename.*' => 'mimes:pdf,doc,docx,jpeg,jpg,gif,png,bmp|max:8300',
if($request->hasfile('filename'))
{
$i=count($request->file('filename'));
if($i<=1){
dd('must be multiple');
}
else
{
//dd('multiple: '.count($request->file('filename')));
//loop and insert into db
foreach($request->file('filename') as $file)
{
$name=$file->getClientOriginalName();
$file->move(public_path().'/attachments', $name);
DB::table('tblimg')->insert([
'filename' => $name,
]);
}
}
}

Laravel 5.3 - Attach Multiple Files To Mailables

How does one go about attaching multiple files to laravel 5.3 mailable?
I can attach a single file easily enough using ->attach($form->filePath) on my mailable build method. However, soon as I change the form field to array I get the following error:
basename() expects parameter 1 to be string, array given
I've searched the docs and also various search terms here on stack to no avail. Any help would be greatly appreciated.
Build Method:
public function build()
{
return $this->subject('Employment Application')
->attach($this->employment['portfolio_samples'])
->view('emails.employment_mailview');
}
Mail Call From Controller:
Mail::to(config('mail.from.address'))->send(new Employment($employment));
You should store your generated email as a variable, then you can just add multiple attachments like this:
public function build()
{
$email = $this->view('emails.employment_mailview')->subject('Employment Application');
// $attachments is an array with file paths of attachments
foreach ($attachments as $filePath) {
$email->attach($filePath);
}
return $email;
}
In this case your $attachments variable should be an array with paths to files:
$attachments = [
// first attachment
'/path/to/file1',
// second attachment
'/path/to/file2',
...
];
Also you can attach files not only by file paths, but with MIME type and desired filename, see documentation about second case of use for the `attachment` method: https://laravel.com/docs/master/mail#attachments
For example, your $attachments array can be something like this:
$attachments = [
// first attachment
'path/to/file1' => [
'as' => 'file1.pdf',
'mime' => 'application/pdf',
],
// second attachment
'path/to/file12' => [
'as' => 'file2.pdf',
'mime' => 'application/pdf',
],
...
];
After you can attach files from this array:
// $attachments is an array with file paths of attachments
foreach ($attachments as $filePath => $fileParameters) {
$email->attach($filePath, $fileParameters);
}
Best solution work for me
$email = $this->from($from)->subject("Employment Application")
->view('emails.employment_mailview');
foreach ($files as $file) {
$path = '/path/to/'.$file->file;
$attachments->push($path);
}
$attachments = collect([]);
foreach ($attachments as $filePath) {
$email->attach($filePath);
}
return $email;
This worked for me, maybe it will work for more people.
As I am getting the files via $request this was the solution works for me.
obs: sorry I'm using translate. From Portuguese(Brazil) to English.
thanks #AlexanderReznikov, it helped me a lot.
class SendMailextends Mailable
{
protected $inputs;
protected $files;
public function __construct(array $inputs, array $files)
{
$this->inputs = $inputs;
$this->files = $files;
}
public function build()
{
if (isset($this->files)){
$email = $this->from('you#mail')->view('email.email-contact')->subject('Email teste mulptiple files');
for ($indice = 0; $indice < count($this->files['files']); $indice++) {
$files = $this->files[$indice];
$pathName = $files->getPathname();
$attachments = $pathName;
$fileName = $files->getClientOriginalName();
$email->attach($attachments,['as' => "$fileName"]);
}
return $email;
}else{
// file empty, send email
return $this->from('you#mail','name')->subject('Email teste mulptiple files')
->view('email.email-contact');
}
}
}

Yii validation with file upload failing

I'm having what looks to me some strange behaviour within Yii.
I have a simple file upload, that takes a name and the file itself.
If I just submit the form with no name or file I can bypass the validation (i.e - My controller action is called and is trying to process the uploaded file) I think my rules() are setup accordingly to stop this. These are my relevant rules:
public function rules() {
return array(
array('name file', 'required', 'message' => 'This field is required'),
array('file', 'file', 'on' => 'insert', 'allowEmpty' => false, 'safe'=>true,
'maxSize'=> 512000,
'maxFiles'=> 1,
'mimeTypes' => 'application/msword, text/plain',
'tooLarge'=> 'file cannot be larger than 500KB.',
'wrongMimeType'=> 'Format must be: .doc .txt'
),
I specified that the file is required and also within the file array that allowEmpty should be false. So what am I doing wrong here?
Thanks in advance for any help
Controller
public function actionCreate() {
$model = new File;
if (isset($_POST['File'])) {
$model->setAttributes($_POST['File']);
// Set file
$model->file = CUploadedFile::getInstance($model,'file');
// Set directory
$dest = Yii::getPathOfAlias('application.uploads');
$model->tmp_name = time();
$model->date_added = new CDbExpression('NOW()');
$model->file_type = $model->file->type;
$model->file_size = $model->file->size;
$model->extension = $model->file->extensionName;
if ($model->save()) {
$model->file->saveAs(($dest . '/' . $model->tmp_name . '.' . $model->file->extensionName));
Yii::app()->user->setFlash('success','<strong>Success!</strong> Your file has been uploaded');
}
}
$this->render('create', array( 'model' => $model));
}
For one you're missing a , in your first rule between name and file. Then you say:
I can bypass the validation (i.e - My controller action is called ...
From that i assume you use AJAX validation and expect the upload to fail. But you can't do AJAX validation on file uploads with CActiveForm.
So if you fix the typo above, you'll at least get AJAX validation for the name attribute.
You should maybe also remove the 'on'=>'insert' scenario. And you don't need the 'safe'=>true because you don't do massive assignment with the $model->file attribute.
For me I found that if I validate before I process the uploaded file it worked. Wasn't quite sure why I had to do that as I thought the save() method automatically called the validate() method
Validation will be performed before saving the record. If the validation fails, the record will not be saved. You can call getErrors() to retrieve the validation errors.
Updated code
public function actionCreate() {
$model = new File;
if (isset($_POST['File'])) {
$model->setAttributes($_POST['File']);
if($model->validate()){ // add in validation call
// Set file
$model->file = CUploadedFile::getInstance($model,'file');
// Set directory
$dest = Yii::getPathOfAlias('application.uploads');
$model->tmp_name = time();
$model->date_added = new CDbExpression('NOW()');
$model->file_type = $model->file->type;
$model->file_size = $model->file->size;
$model->extension = $model->file->extensionName;
if ($model->save()) {
$model->file->saveAs(($dest . '/' . $model->tmp_name . '.' . $model->file->extensionName));
Yii::app()->user->setFlash('success','<strong>Success!</strong> Your file has been uploaded');
}
}
}
$this->render('create', array( 'model' => $model));
}
Hope that helps anyone, thanks to #Michael Härtl too

Resources