Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

anatomic's avatar

Save generated PDF to public Laravel directory from API response?

Hi

I'm feeling quite frustrated and properly out of my depth with this and wonder if anyone can help please.

As part of an API response I receive a pdf. I want to save this pdf to a directory.

I've been trying file_get_contents and streaming the download using the http guzzle client, but all I get is the file downloading in my browser, or a null response.

I won't provide any "working" code, because I'm not sure it'll help, I just can't find anything on line (possibly my search skills)!

Any pointers please, I'm happy to work it out with the right resources, I just can't find theose resources and I'm about 6 hours in!

Thanks!

0 likes
7 replies
Sinnbeck's avatar

Not sure there are any resources but let's see if we can figure it out anyways. Is it a public api so I can try it out?

1 like
anatomic's avatar

Thanks, I appreciate it. And obviously I'm an idiot for not supplying code and at least showing that I'm trying!

These are the docs, I'm just working with the PDF Merge API, which is incredibly simple and simply returns as below.

https://www.stannp.com/uk/direct-mail-api/tools

{
    "success": true,
    "data": "https://merged-file.pdf"
}

The URL opens as any pdf would, so I'm just working with a local pdf much like below, which at the moment downloads the pdf, just can't get it saved into storage.

$client = new \GuzzleHttp\Client();
$response = $client->get('http://local.test/file.pdf');
$file = $response->getBody()->getContents();
$fileName = 'file-name.pdf';
$headers = ["content-type" => "application/octet-stream"];

return response()->streamDownload(function () use ($file) {
            Storage::putFile('public/uploads/', $file);
//	    echo $file;
}, $fileName, $headers);

If I echo out $file instead of using Storage as the return, the file downloads in the browser, just can't get it to go into the storage itself.

Appreciate you helping, thanks.

anatomic's avatar

Ok, I've got something working. It doesn't feel very Laravel like and to me feels a bit off, but it works.

$file = file_get_contents('http://website.test/pdf-file.pdf');
file_put_contents("../storage/app/public/uploads/pdf-file.pdf", $file);

I'm puzzled why I can't achieve the same thing with the storage Facade to be honest.

anatomic's avatar

The above failed on a live server, "Failed to open stream: No such file or directory" , so I've spent a few days trying to fix and ended up starting again...

I worked it out using Guzzle and lots of Google searches about downloading a file from a remote path to store on my server.

It works perfectly, I think, but I've not a clue about this, I'm worried it's fragile and going to break in production.

Can anyone shed any light on the below code and let me know if it's ok to use in production please, as it's taken me days of work (searching and trying over and over again - failed jobs is over 1000) and I'm outside of my knowledge!

Thanks

use GuzzleHttp\Client;

$fileToWrite = 'storage/app/public/new-file.pdf';

$client = new Client();
$fileToSave = 'http://website.com/download.pdf';

$resource = \GuzzleHttp\Psr7\Utils::tryFopen($fileToWrite, 'w');
$client->request('GET', $fileToSave, ['sink' => $resource]);
anatomic's avatar

Scrub that, it doesn't work. I'm at my whits end. (I won't give up, I just don't seem ot have the Google skills at the moment!)

I have a feeling it's permissions on the directories. I create them as 775, but no matter what they seem to only be 755. Perhaps it's a security setting on Forge?

\File::makeDirectory('app/public/downloaded/', 0775, true, true);
sikander.choudhry's avatar

Have you checked your browser settings. By default Chrome is configured to open pdf files in the browser irrespective of what you ask it to do. Go to Settings->Privacy and Security->Site Settings->PDF documents.

sikander.choudhry's avatar

Alternatively try downloading a file with different extension (like .doc or .xls) to ensure it is not a browser issue.

Please or to participate in this conversation.