Azima
Azima

Reputation: 4141

laravel response stream download returns empty file

I have a controller method that receives user's request for download, calls REST API endpoint with the requested body parameters.

API, in return, sends a file.

I am using Guzzle for making API requests and laravel version 5.4.

The content of the $response->getBody()->getContents(); is as :

"""
request_id\ts_sku\tr_product_url\thuman_verdict\n
199\tSG-948\thttps://www.amazon.com/gp/offer-listing/B076CP7J4P?condition=new\tMatch\n
199\tZIB-601\thttps://www.amazon.com/gp/offer-listing/B07D9PN39C?condition=new\tMatch\n
199\tRCM-LG526\thttps://www.amazon.com/gp/offer-listing/B07FDJ3W7P?condition=new\tMatch\n
199\tGSI-335\thttps://www.amazon.com/gp/offer-listing/B07GNX1VSG?condition=new\tMatch\n
199\tZIB-489\thttps://www.amazon.com/gp/offer-listing/B07D9RCGXM?condition=new\tMatch\n
"""

Also the received header response from API is:

Content-Type : ('text/tab-separated-values', none)
Content-Disposition : attachment; filename=/path/to/file1.tsv

I am trying to receive this file in my controller and return response as stream download to user's browser.

Here's controller method:

    $client = new Client(["base_uri" => $this->apiBaseUrl]);
    $url = 'download/filterdownload/';

    try {
        $response = $client->request('POST', $url, ['headers'=>['Content-Type' => 'application/json'], 'body'=>json_encode($filterArr)]);
        # $resArr = json_decode($response, true);
    } catch (\Exception $e) {
        return redirect()->back()->with('error', $e->getMessage());
    }

    if(!empty($resArr) && array_key_exists('response', $resArr))
        return redirect()->back()->with('error', $resArr['response']);

    # return response
    $file = $response->getBody()->getContents();

    $file_name = $filterArr['client_name'].'_'.Carbon::now()->toDateString().'.tsv';
    $headers = [
        'Content-Disposition' => 'attachment; filename='. $file_name. ';'
    ];
    return response()->stream(function () {
        $file;
    }, 200, $headers);

This downloads a file but the file is empty.

Upvotes: 3

Views: 29138

Answers (3)

Moritur
Moritur

Reputation: 1748

This is an optimized version that streams the contents of a remote url directly to the response:

use Illuminate\Support\Facades\Http;

$url = 'download/filterdownload/';

$responseStream = Http
    ::withOptions(['stream' => true])
    ->get($url)
    ->getBody()
    ->detach();

$headers = [
    'Content-Type' => 'application/pdf', // Ideally, replace this with your content type.
    'Content-Disposition' => 'attachment; filename="remote-file.pdf"', // Instead of "attachment" you can also set "inline" to render a pdf in the browser
];

return response()->stream(function() use ($responseStream) {
    // This actually just passes through the stream, instead of loading the file in PHP memory
    fpassthru($responseStream);
}, 200, $headers);

Upvotes: 1

Aslam Shekh
Aslam Shekh

Reputation: 706

Try This One

        $streamFileData = $response->getBody()->getContents();
        $fileName = "test.pdf";
        $headers = [
            'Content-Type'        => 'application/octet-stream',
            'Content-Disposition' => 'attachment; filename=' . $fileName,
        ];
        $response = response( $streamFileData, 200, $headers );
        return $response;

Upvotes: 4

Dmitry Leiko
Dmitry Leiko

Reputation: 4382

Maybe help:

 # return response
    $file = $response->getBody()->getContents();

    $file_name = $filterArr['client_name'].'_'.Carbon::now()->toDateString().'.tsv';
    $headers = [
        'Content-Disposition' => 'attachment; filename='. $file_name. ';'
    ];
    return response()->stream(function () use ($file)  { <-- edit
        $file;
    }, 200, $headers);

Upvotes: 4

Related Questions