4

I need help understanding Laravel's file storage system. I'm creating an app where I need to upload a users drivers license photo. This is obviously sensitive information. I would like to keep this image off of the internet unless an admin is viewing it. My understanding is that i have to save things to the public directory in the storage>app>public and create a symlink to the public>storage folder. I have this done and it's working fine. I save the path to the database and the program can display it, but I don't want things to be in the public folder if I can avoid it.

Is there any way to save an image/file to a private folder in the storage system then access it through the view? If I do this, does it keep that image "private" so that it's not stored in a cache somewhere beings that it's not in a "public" folder? Does the symlink protect files in the storage folder in the way I'm wanting or does it truly make all files available to the public?

Any help in understanding this would be appreciated.

mare96
  • 3,749
  • 1
  • 16
  • 28
maximus1127
  • 936
  • 11
  • 30

1 Answers1

11

What you've said is correct the files in storage/app/public is public. This is why you have to create a private directory, lets say storage/app/private, then upload your sensitive files here.

You may want to add a disks in your config/filesystems.php:

'private' => [
    'driver' => 'local',
    'root' => storage_path('app/private'),
],

If you want to access your private files. Create a route for this:

Route::get('/private-files/{file?}','FileController@get')->where('file', '(.*)');

Then in the FileController.php, you will have something like this (this is just an example, edit the code here to check if the user is admin):

<?php
namespace App\Http\Controllers;

use Auth;
use Storage;
use App\Http\Controllers\Controller;

class FileController extends Controller {

    public function __construct()
    {
        $this->middleware('auth');
    }

    public function get($file)
    {
        return Storage::disk('private')->get($file);
    }

 }
aceraven777
  • 4,358
  • 3
  • 31
  • 55
  • 1
    This is a very thorough answer. Thank you very much. My only other question is how would I access this in a view? For instance, the traditional way is to just put an img tag with src = path/to/file. How would I do this same thing and assign the source to that image by using a controller function like this? My view is being returned by a separate controller and a separate function. – maximus1127 Aug 12 '19 at 14:19
  • 2
    This is why I created the route in my answer. So if you want to put it in an image tag, this is the code: `` – aceraven777 Aug 12 '19 at 14:22
  • Aha, i understand. thank you. Another SO answer that I looked at said I can use the Storage facade...src = "{{Storage::($object->path)}}", is this also a good option that you suggest? – maximus1127 Aug 12 '19 at 14:24
  • That will not work because the `src` is expecting a URL path. The `Storage::disk('private')->get($file)` will return the CONTENT of the file NOT the URL. – aceraven777 Aug 12 '19 at 14:26
  • Can you explain one more thing to me? what does the "->where('file', '(.*)')" mean? I have checked the docs but I can't understand why I need that in the route. Also, in my previous question in the comments, I was not talking about using the Storage::disk line in the controller, but rather storing the path to the file in the database as "/app/private/filename.png" then in the src do "{{Storage::url($object->path)}}". will that approach not work? It should return the path to the storage private folder, right? – maximus1127 Aug 12 '19 at 15:00
  • I just use that as an example. I used `->where('file', '(.*)')` because i'm assuming that you will use files have a long path (multiple levels of directory), e.g. `storage/app/private/this/is/a/long/path/image.png`. if you don't use `->where('file', '(.*)')` the file you're accessing must only in one level, e.g. `storage/app/private/image.png` – aceraven777 Aug 13 '19 at 01:55
  • About using `{{ Storage::url($object->path) }}`, I don't know if that will work, you should try testing it out. But since your using the private storage, you should use `{{ Storage::disk('private')->url($object->path) }}`. – aceraven777 Aug 13 '19 at 01:57
  • 1
    Thank you so much. This is a lot of good information that will help me understand my code a lot better. Great job and many thanks. I appreciate you taking the time to actually type out code snippets to help me see your solutions – maximus1127 Aug 13 '19 at 01:59