Laravel - display a PDF file in storage without forcing download?

后端 未结 10 997
陌清茗
陌清茗 2020-12-02 10:31

I have a PDF file stored in app/storage/, and I want authenticated users to be able to view this file. I know that I can make them download it using

return          


        
相关标签:
10条回答
  • 2020-12-02 10:58

    In Laravel 5.5 you can just pass "inline" as the disposition parameter of the download function:

    return response()->download('/path/to/file.pdf', 'example.pdf', [], 'inline');
    
    0 讨论(0)
  • 2020-12-02 10:59

    As of laravel 5.5 if the file is stored on a remote storage

    return Storage::response($path_to_file);
    

    or if it's locally stored you can also use

    return response()->file($path_to_file);
    

    I would recommend using the Storage facade.

    0 讨论(0)
  • 2020-12-02 11:01

    Retrieving Files
    $contents = Storage::get('file.jpg');

    Downloading Files
    return Storage::download('file.jpg');

    File URLs
    $url = Storage::url('file.jpg');

    0 讨论(0)
  • 2020-12-02 11:02

    Update for 2017

    As of Laravel 5.2 documented under Other response types you can now use the file helper to display a file in the user's browser.

    return response()->file($pathToFile);
    
    return response()->file($pathToFile, $headers);
    

    Source/thanks to below answer

    Outdated answer from 2014

    You just need to send the contents of the file to the browser and tell it the content type rather than tell the browser to download it.

    $filename = 'test.pdf';
    $path = storage_path($filename);
    
    return Response::make(file_get_contents($path), 200, [
        'Content-Type' => 'application/pdf',
        'Content-Disposition' => 'inline; filename="'.$filename.'"'
    ]);
    

    If you use Response::download it automatically sets the Content-Disposition to attachment which causes the browser to download it. See this question for the differences between Content-Disposition inline and attachment.

    Edit: As per the request in the comments, I should point out that you'd need to use Response at the beginning of your file in order to use the Facade.

    use Response;
    

    Or the fully qualified namespace if Response isn't aliased to Illuminate's Response Facade.

    0 讨论(0)
  • 2020-12-02 11:05

    Ben Swinburne's answer is absolutely correct - he deserves the points! For me though the answer left be dangling a bit in Laravel 5.1 which made me research — and in 5.2 (which inspired this answer) there's a a new way to do it quickly.

    Note: This answer contains hints to support UTF-8 filenames, but it is recommended to take cross platform support into consideration !

    In Laravel 5.2 you can now do this:

    $pathToFile = '/documents/filename.pdf'; // or txt etc.
    
    // when the file name (display name) is decided by the name in storage,
    // remember to make sure your server can store your file name characters in the first place (!)
    // then encode to respect RFC 6266 on output through content-disposition
    $fileNameFromStorage = rawurlencode(basename($pathToFile));
    
    // otherwise, if the file in storage has a hashed file name (recommended)
    // and the display name comes from your DB and will tend to be UTF-8
    // encode to respect RFC 6266 on output through content-disposition
    $fileNameFromDatabase = rawurlencode('пожалуйста.pdf');
    
    // Storage facade path is relative to the root directory
    // Defined as "storage/app" in your configuration by default
    // Remember to import Illuminate\Support\Facades\Storage
    return response()->file(storage_path($pathToFile), [
        'Content-Disposition' => str_replace('%name', $fileNameFromDatabase, "inline; filename=\"%name\"; filename*=utf-8''%name"),
        'Content-Type'        => Storage::getMimeType($pathToFile), // e.g. 'application/pdf', 'text/plain' etc.
    ]);
    

    And in Laravel 5.1 you can add above method response()->file() as a fallback through a Service Provider with a Response Macro in the boot method (make sure to register it using its namespace in config/app.php if you make it a class). Boot method content:

    // Be aware that I excluded the Storage::exists() and / or try{}catch(){}
    $factory->macro('file', function ($pathToFile, array $userHeaders = []) use ($factory) {
    
        // Storage facade path is relative to the root directory
        // Defined as "storage/app" in your configuration by default
        // Remember to import Illuminate\Support\Facades\Storage
        $storagePath         = str_ireplace('app/', '', $pathToFile); // 'app/' may change if different in your configuration
        $fileContents        = Storage::get($storagePath);
        $fileMimeType        = Storage::getMimeType($storagePath); // e.g. 'application/pdf', 'text/plain' etc.
        $fileNameFromStorage = basename($pathToFile); // strips the path and returns filename with extension
    
        $headers = array_merge([
            'Content-Disposition' => str_replace('%name', $fileNameFromStorage, "inline; filename=\"%name\"; filename*=utf-8''%name"),
            'Content-Length'      => strlen($fileContents), // mb_strlen() in some cases?
            'Content-Type'        => $fileMimeType,
        ], $userHeaders);
    
        return $factory->make($fileContents, 200, $headers);
    });
    

    Some of you don't like Laravel Facades or Helper Methods but that choice is yours. This should give you pointers if Ben Swinburne's answer doesn't work for you.

    Opinionated note: You shouldn't store files in a DB. Nonetheless, this answer will only work if you remove the Storage facade parts, taking in the contents instead of the path as the first parameter as with the @BenSwinburne answer.

    0 讨论(0)
  • 2020-12-02 11:08

    Since Laravel 5.2 you can use File Responses
    Basically you can call it like this:

    return response()->file($pathToFile);
    

    and it will display files as PDF and images inline in the browser.

    0 讨论(0)
提交回复
热议问题