Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

File upload using foreach in Laravel [duplicate]

Tags:

laravel

Been working on this problem for 2 days and still cannot figure it out. I am trying to upload multiple files into storage in my Laravel project. I know my code works up to the foreach as I tested this with dd.

My controller:

$files = $request->file('current_plan_year_claims_data_file_1');
$folder = public_path(). "\storage\\$id";

if (!File::exists($folder)) {
    File::makeDirectory($folder, 0775, true, true);
}

if (!empty($files)) {
    foreach($files as $file) {
        Storage::disk(['driver' => 'local', 'root' => $folder])->put($file->getClientOriginalName(), file_get_contents($file));
    }
}
like image 651
Alexander Avatar asked Dec 13 '19 12:12

Alexander


2 Answers

I see that you are trying to store the files directly in public folder, but why not use the Storage API of Laravel and use the public disk? You can do something like this to upload the files to the public directory:

$id = 123;
$files = $request->file();
$folder = $id;
if (count($files) > 0) {
    foreach ($files as $file) {
        $file->store($folder, ['disk' => 'public']);
    }
}

And be sure that you have linked the storage path to public:

php artisan storage:link

Focus on $files = $request->file(); line. When you don't pass an argument to file() method, all uploaded file instances are returned. Now when you will loop over the $files array, you will get access to individual uploaded files.

And then you can store the file using your logic, i.e. you can use the original name or whatever else. Even you can use the Storage facade to process the file instance.

i.e. if you want to store the files with their original names, I find this a cleaner way rather than what you are doing:

$id = 123;
$files = $request->file();
$folder = $id;
if (count($files) > 0) {
    foreach ($files as $file) {
        Storage::disk('public')->putFileAs(
            $folder,
            $file,
            $file->getClientOriginalName()
        );
    }
}

And as suggested by @cbaconnier, you can use allFiles() method too that's more descriptive:

$files = $request->allFiles();

I hope this helps.

like image 64
Rehmat Avatar answered Oct 22 '22 14:10

Rehmat


You're trying to iterate over files, and file is just a reference to request->file(), which is a SINGLE UploadedFile object.

As indicated by your comment, you have multiple file inputs with different name attributes, so you can't easily loop over them with one statement, eg: if you had multiple files all uploaded as "attachments[]" as the input name attribute, you could get them all with $request->allFiles('attachments'), however, if you want to keep the input names as they are, this should be close to what you want.

public function foo(Request $request, $id){
    $folder = public_path(). "\storage\\$id";

    if (!File::exists($folder)) {
        File::makeDirectory($folder, 0775, true, true);
    }

    $files = array();
    $files[] = $request->file('current_plan_year_claims_data_file_1');
    $files[] = $request->file('prior_plan_year_claims_data_file_1');
    $files[] = $request->file('etc_file_whatever');

    foreach($files as $file) {
        Storage::disk(['driver' => 'local', 'root' => $folder])->put($file->getClientOriginalName(), file_get_contents($file));
    }
}

Side note, i'm not sure what you're doing with File and public_path, but if your goal is just to put something in your app storage, something like this should work fine

public function foo(Request $request, $id){
    if(!\Storage::exists($id)){
        \Storage::makeDirectory($id);
    }

    $files = array();
    $files[] = $request->file('current_plan_year_claims_data_file_1');
    $files[] = $request->file('prior_plan_year_claims_data_file_1');
    $files[] = $request->file('etc_file_whatever');

    foreach($files as $file) {
        \Storage::put("$id/" . $file->getClientOriginalFileName(), $file);
    }
}
like image 24
Zachary Craig Avatar answered Oct 22 '22 14:10

Zachary Craig