laravel 如何处理laravel 5中的私人图像?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28562908/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 10:57:54  来源:igfitidea点击:

How to deal with private images in laravel 5?

laravellaravel-5

提问by Hassan Saqib

I am new to Laravel and trying to store private images so that only authenticated users can access them. Firstly I stored images in Public/UserImages folder. But here all the pictures are accessible to unauthenticated users as well by going to Inspect Element of chrome and then changing the user IDs. Kindly help out me...

我是 Laravel 的新手并试图存储私人图像,以便只有经过身份验证的用户才能访问它们。首先,我将图像存储在 Public/UserImages 文件夹中。但在这里,未经身份验证的用户也可以访问所有图片,方法是转到 Inspect Element of chrome 然后更改用户 ID。请帮帮我...

采纳答案by ceejayoz

It's really up to you. It'll need to be outside the publicdirectory - I'd personally pick resources/uploadsor storage/uploads, or store them off-server entirely using the cloud filesystem support.

这真的取决于你。它需要在public目录之外- 我会亲自选择resources/uploadsstorage/uploads,或者完全使用云文件系统支持将它们存储在服务器外。

Whatever you pick, you'll need a route that fetches the file and passes it along to the user after first checking that they have access.

无论您选择什么,您都需要一个路径来获取文件并在首先检查他们是否具有访问权限后将其传递给用户。

回答by ken koehler

Following is how I solved the problem of storing images in Laravel 5 such that only authenticated users can view the images. People who are not authenticated will be directed to a login page. My server is a Ubuntu/Apache2 server.

以下是我如何解决在 Laravel 5 中存储图像的问题,以便只有经过身份验证的用户才能查看图像。未通过身份验证的人员将被定向到登录页面。我的服务器是 Ubuntu/Apache2 服务器。

  1. Create the directory /var/www/YOURWEBSITE/app/Assets/Images

  2. Add route to app/Http/routes.php.

    Route::get('/images/{file}','ImageController@getImage');

  3. Create a controller app/Http/Controllers/ImageController.php

    <?php
    namespace App\Http\Controllers;
    
    use App\Http\Requests;
    
    use App\Http\Controllers\Controller;
    
    use Illuminate\Http\Request;
    
    use Auth;
    
    class ImageController extends Controller {
    
        public function __construct()
       {
            $this->middleware('auth');
       } 
        public function getImage($filename) {
           $path = '/var/www/YOURWEBSITE/app/Assets/Images/'.$filename;
           $type = "image/jpeg";
           header('Content-Type:'.$type);
           header('Content-Length: ' . filesize($path));
           readfile($path);
    
        }
    
     }
    
  4. In your view you have img tags which have:

    src="{{ url('/images/test.jpg') }}"
    
  1. 创建目录 /var/www/YOURWEBSITE/app/Assets/Images

  2. 将路由添加到 app/Http/routes.php。

    Route::get('/images/{file}','ImageController@getImage');

  3. 创建一个控制器 app/Http/Controllers/ImageController.php

    <?php
    namespace App\Http\Controllers;
    
    use App\Http\Requests;
    
    use App\Http\Controllers\Controller;
    
    use Illuminate\Http\Request;
    
    use Auth;
    
    class ImageController extends Controller {
    
        public function __construct()
       {
            $this->middleware('auth');
       } 
        public function getImage($filename) {
           $path = '/var/www/YOURWEBSITE/app/Assets/Images/'.$filename;
           $type = "image/jpeg";
           header('Content-Type:'.$type);
           header('Content-Length: ' . filesize($path));
           readfile($path);
    
        }
    
     }
    
  4. 在您看来,您的 img 标签具有:

    src="{{ url('/images/test.jpg') }}"
    

This of course assumes test.jpg is a file in /var/www/YOURWEBSITE/app/Assets/Images/

这当然假设 test.jpg 是 /var/www/YOURWEBSITE/app/Assets/Images/ 中的文件

You can of course add more logic such as not hardcoding the path of the images, etc. This is just a simple example to enforce authentication. Note the use of middleware('auth') in the controller constructor.

您当然可以添加更多逻辑,例如不对图像的路径进行硬编码等。这只是一个强制执行身份验证的简单示例。请注意在控制器构造函数中使用 middleware('auth')。

回答by Franco Sarachu

I got the same issue some days ago and came up with this solution:

几天前我遇到了同样的问题,并提出了以下解决方案:

  1. First thing you have to do is upload the file to a non-public directory. My app is storing scanned invoices, so I'm going to place them inside storage/app/invoices. The code for uploading the file and generating the url would be:

    // This goes inside your controller method handling the POST request.
    
    $path = $request->file('invoice')->store('invoices');
    $url = env('APP_URL') . Illuminate\Support\Facades\Storage::url($path);
    

    The url returned should result in something like http://yourdomain.com/storage/invoices/uniquefilename.jpg

  2. Now you have to create a controller that uses the auth middlewareto ensure the user is authenticated. Then, define a method that grabs the file from the private directory and returns it as a file response. That would be:

    <?php
    
    namespace App\Http\Controllers;
    
    use Illuminate\Support\Facades\Storage;
    
    class FileController extends Controller
    {
    
        public function __construct()
        {
            $this->middleware('auth');
        }
    
        public function __invoke($file_path)
        {
            if (!Storage::disk('local')->exists($file_path)) {
                abort(404);
            }
    
            $local_path = config('filesystems.disks.local.root') . DIRECTORY_SEPARATOR . $file_path;
    
            return response()->file($local_path);
        }
    }
    
  3. The last thing is register the route inside your routes/web.phpfile:

    Route::get('/storage/{file_name}', 'FileController')->where(['file_name' => '.*'])
    
  1. 您必须做的第一件事是将文件上传到非公共目录。我的应用程序正在存储扫描的发票,所以我要把它们放在storage/app/invoices. 上传文件和生成 url 的代码是:

    // This goes inside your controller method handling the POST request.
    
    $path = $request->file('invoice')->store('invoices');
    $url = env('APP_URL') . Illuminate\Support\Facades\Storage::url($path);
    

    返回的 url 应该类似于http://yourdomain.com/storage/invoices/uniquefilename.jpg

  2. 现在您必须创建一个使用 的控制器auth middleware来确保用户通过身份验证。然后,定义一个从私有目录中获取文件并将其作为文件响应返回的方法。那将是:

    <?php
    
    namespace App\Http\Controllers;
    
    use Illuminate\Support\Facades\Storage;
    
    class FileController extends Controller
    {
    
        public function __construct()
        {
            $this->middleware('auth');
        }
    
        public function __invoke($file_path)
        {
            if (!Storage::disk('local')->exists($file_path)) {
                abort(404);
            }
    
            $local_path = config('filesystems.disks.local.root') . DIRECTORY_SEPARATOR . $file_path;
    
            return response()->file($local_path);
        }
    }
    
  3. 最后一件事是在您的routes/web.php文件中注册路由:

    Route::get('/storage/{file_name}', 'FileController')->where(['file_name' => '.*'])
    

So there you have it, a pretty reusable snippet for all your projects that deals with private files :)

所以你有它,一个非常可重用的片段,适用于所有处理私有文件的项目:)

回答by Mohamed Allal

Here how to do it in Laravel 5.7

这里如何在 Laravel 5.7 中做到这一点

To have private files (images), you need to serve the files through a route => controllerflow. And your auth middleware will handle authentication, and permission. If further authorization are needed you handle it in the controller.

要拥有私有文件(图像),您需要通过路由 => 控制器流来提供文件。您的身份验证中间件将处理身份验证和权限。如果需要进一步授权,您可以在控制器中进行处理。

So first we set a route:

所以首先我们设置一个路由:

Here we can have one route that handle allour files [i personally don't prefer that]. We can do that using such a route (it's like a wildcard).

在这里,我们可以有一个路由来处理我们所有的文件 [我个人不喜欢那样]。我们可以使用这样的路由(它就像一个通配符)来做到这一点。

Route::get('/storage/{filePath}', 'FileController@fileStorageServe')
->where(['filePath' => '.*'])

You can name it too like that:

你也可以这样命名:

Route::get('/storage/{fileName}', 'FileController@fileStorageServe')
->where(['fileName' => '.*'])->name('storage.gallery.file');

Otherwisewe create a route for each type/category of files: (advantage: you will be able to control better the accessibility. (Each route and type of resources and it's rules. If you want to achieve that with the wild card route (let me call it that) you need to have conditional blocks (if else, handling all different situations. It's unnecessary operations [going directly to the right block, when the routes are separate is better, plus out of that, it allow you to organize better the permissions handling]).

否则,我们为每种类型/类别的文件创建一个路由:(优点:您将能够更好地控制可访问性。(每个路由和类型的资源及其规则。如果您想使用通配符路由(让我称之为)你需要有条件块(如果否则,处理所有不同的情况。这是不必要的操作[直接进入正确的块,当路由分开时更好,另外,它可以让你更好地组织权限处理])。

Route::get('/storage/gallery/{file}', 'System\FileController@getGalleryImage')
->name('storage.gallery.image');

?We had our routes set NOW Controller/Controllers

?我们的路线设置现在控制器/控制器

The wild card one

外卡之一

  <?php
     public function fileStorageServe($file) {
                // know you can have a mapping so you dont keep the sme names as in local (you can not precsise the same structor as the storage, you can do anything)

                // any permission handling or anything else

                // we check for the existing of the file 
                if (!Storage::disk('local')->exists($filePath)){ // note that disk()->exists() expect a relative path, from your disk root path. so in our example we pass directly the path (/.../laravelProject/storage/app) is the default one (referenced with the helper storage_path('app')
                    abort('404'); // we redirect to 404 page if it doesn't exist
                } 
            //file exist let serve it 

// if there is parameters [you can change the files, depending on them. ex serving different content to different regions, or to mobile and desktop ...etc] // repetitive things can be handled through helpers [make helpers]

                return response()->file(storage_path('app'.DIRECTORY_SEPARATOR.($filePath))); // the response()->file() will add the necessary headers in our place (no headers are needed to be provided for images (it's done automatically) expected hearder is of form => ['Content-Type' => 'image/png'];

// big note here don't use Storage::url() // it's not working correctly.  
            }

The per route one

每条路线一

(big difference, is the parameter, now it reference just the file name, and not the relative path to storage disk root)

(区别很大,是参数,现在只引用文件名,而不是存储磁盘根的相对路径)

<?php
public function getCompaniesLogo($file) {
    // know you can have a mapping so you dont keep the sme names as in local (you can not precsise the same structor as the storage, you can do anything)

    // any permission handling or anything else

    $filePath =  config('fs.gallery').DIRECTORY_SEPARATOR.$file; // here in place of just using 'gallery', i'm setting it in a config file

    // here i'm getting only the path from the root  (this way we can change the root later) / also we can change the structor on the store itself, change in one place config.fs.

    // $filePath = Storage::url($file); <== this doesn't work don't use

     // check for existance
    if (!Storage::disk('local')->exists($file)){ // as mentionned precise relatively to storage disk root (this one work well not like Storage:url()
          abort('404');
    } 

    // if there is parameters [you can change the files, depending on them. ex serving different content to different regions, or to mobile and desktop ...etc] // repetitive things can be handled through helpers [make helpers]

    return response()->file(storage_path('app'.DIRECTORY_SEPARATOR.($file))); // the response()->file() will add the necessary headers in our place
}

Now you can check by forming the correct url (go to storage copy past the file name, and form your route. it should show you the image)

现在您可以通过形成正确的 url 来检查(转到文件名后的存储副本,并形成您的路线。它应该向您显示图像)

One last thing left:

剩下最后一件事:

How to show that in view

如何在视图中显示

the wild card one

外卡之一

<img src="{{route('routeName', ['fileParam' => $storageRelativePath])}}" />

Note that routeNamehere in the example above will be storage.file, and fileParamwould be filePath. $storageRelativePathfor example you get from the db (generally that's what it will be).

请注意,routeName在上面的示例中,此处将是storage.file,并且fileParam将是filePath$storageRelativePath例如你从数据库中得到的(通常就是这样)。

The per route

每条路线

<img src="{{route('routeName', ['fileName' => basename($storageRelativePath)])}}" />

Same but we provide only the filename.

相同,但我们只提供文件名。

Notes:The best way to send such a response, is using response()->file();. That what you will find in the 5.7 doc. That performance wise against Image::make($storagePath)->response();. Unless you need to modify it in the fly.

注意:发送此类响应的最佳方式是使用response()->file(); . 这就是您将在 5.7 文档中找到的内容。该性能对Image::make($storagePath)->response(); . 除非您需要即时修改它。

You can check my article in medium: https://medium.com/@allalmohamedlamine/how-to-serve-images-and-files-privatly-in-laravel-5-7-a4b469f0f706

您可以在媒体中查看我的文章:https: //medium.com/@allalmohamedlamine/how-to-serve-images-and-files-privatly-in-laravel-5-7-a4b469f0f706