php curl and download file [duplicate] - php

This question already has answers here:
php - How to force download of a file?
(7 answers)
Closed 20 days ago.
The community reviewed whether to reopen this question 20 days ago and left it closed:
Original close reason(s) were not resolved
I would like to use the invoiz api to download an invoice:
https://app.invoiz.de/api/documentation/#/invoices/download%20InvoiceDocument
my code:
// DOWNLOAD INVOICES
$curl = curl_init('https://app.invoiz.de/api/invoice/ID_OF_INVOICE/download');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($curl, CURLOPT_USERPWD, $apiKey . ":" . $secretApiKey);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
'Authorization: Bearer '.$token->token,
'accept: application/pdf'
));
$content = curl_exec($curl);
curl_close($curl);
echo $content shows:
But I would like to download the pdf file.
How can I realize it?
CURL response:
access-control-allow-origin: *
connection: keep-alive
content-disposition: attachment; filename="MyFileName.pdf" content-type: application/pdf
date: Tue,31 Jan 2023 10:50:24 GMT
strict-transport-security: max-age=7776000; includeSubDomains; preload
transfer-encoding: chunked

You must put the header to pdf so that your browser understands that it is a pdf.
header('Content-Type: application/pdf');
Or to force download something like that :
header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"" . basename($file) . "\"");

Related

PHP - Download a file from a URL

In my project, I need to download a file, and I need to use PHP.
All the results from Google were eventually not very helpful.
After combining code from 2 results, I ended up attempting:
function downloadFile($url, $filename) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$data = curl_exec($ch);
curl_close($ch);
header('Content-Description: File Transfer');
header('Content-Type: audio/*');
header("Content-Disposition: attachment; filename=\"$filename\"");
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($data));
readfile($data);
}
The result is an audio file, weighs 10KB (should be 3.58MB).
This code isn't the same as the code in the question that was suggested as a duplicate - here there's a section of curl functions and headers, while the question's answer only has a bunch of headers.
When opened the file with VLC - the following error appears:
Also, I tried using:
file_put_contents($filename, file_get_contents($url));
This one results in downloading the file to the path in which the PHP file is located at - which is not what I want - I need the file to be downloaded to the Downloads folder.
So now I'm basically lost.
What's the appropriate way to download files?
Thanks!
I successfully did it, thanks to Google and a lot of experiments.
The final code:
function downloadFile($url, $filename) {
$cURL = curl_init($url);
curl_setopt_array($cURL, [
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_FILE => fopen("Downloads/$filename", "w+"),
CURLOPT_USERAGENT => $_SERVER["HTTP_USER_AGENT"]
]);
$data = curl_exec($cURL);
curl_close($cURL);
header("Content-Disposition: attachment; filename=\"$filename\"");
echo $data;
}

PHP - Download file from external server, filename has quotes " ' " : 'filename.zip'

I made a script where depending on the request the server will return a specific file for download from an external source, I use an external source because I have unlimited bandwidth on the other server:
$ch = curl_init();
$url="http://www.example.com/downloads/$fileName";
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_NOBODY, true); // make it a HEAD request
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$head = curl_exec($ch);
$mimeType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
$size = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Type: $mimeType");
header("Content-length: $size");
header("Content-Transfer-Encoding: binary");
header("Content-Disposition:attachment;filename='$fileName'");
readfile($url);
$filename comes from the request on the front end. It is a simple post from a form.
Everything works great, but some users, not all, have reported that they cant open the file because the file name has quotes: 'filename.zip', instead of filename.zip
I hit a wall, I have no idea even where to start looking, apparently this happens with some mac users. Any ideas?
The HTTP standard would have you putting double quotes around the filename parameter in the Content-Disposition header. That might look like this in your code:
header('Cache-Control: public');
header('Content-Description: File Transfer');
header('Content-Type: ' . $mimeType);
header('Content-Type:application/octet-stream');
header('Content-length: ' . $size);
header('Content-Transfer-Encoding: binary');
header('Content-Disposition:attachment;filename="' . $fileName . '"');
readfile($url);
Note here that I have changed all your PHP string definitions to use single quotes to present all string definitions consistently.

ZIP downloads are bigger in size than they actually are on external server using PHP headers

We are hosting some heavy files that are advertised as free downloads on one of our sites. These files are on another server so in order to generate the download we execute this code:
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Type:application/octet-stream");
header("Content-Transfer-Encoding: binary");
header("Content-Disposition:attachment;filename='$fileName'");
readfile("http://mysiste.com/downloads/$fileName");
Where $fileName is the name of the zip files. Example: myfile.zip
All works fine except that if myfile.zip is 8Mb on the server it will download as 16Mb! The craziest thing is that the file works fine and when unzipping the file all the files inside are complete and not corrupted.
I guess it has something to do with the headers and the transfer encoding as if the zip file looses the compression.
Any ideas?
I think you are missing out an important header
header("Content-length: $size") here. You can use int filesize (string $filename) to find the file size. Here is the API doc
<?php
$fileName = "downloaded.pdf"
$size = filesize($file);
header('Content-type: application/pdf');
header("Content-length: $size");
header("Content-Disposition: attachment; filename='$fileName'");
readfile($file);
?>
If the file is located in a remote server, you can GET the Content-length easily by setting up the Curl without actually downloading it.
These stackoverflow threads should help you:
Easiest way to grab filesize of remote file in PHP?
PHP: Remote file size without downloading file
Reference credit: Content-length and other HTTP headers?
This is the code that would combine curl and PHP headers:
$url="http://mysite/downloads/$fileName";
$ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_NOBODY, true); // make it a HEAD request
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$head = curl_exec($ch);
$mimeType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
$size = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
$path = parse_url($url, PHP_URL_PATH);
$filename = substr($url, strrpos($path, '/') + 1);
curl_close($ch);
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Type:$mimeType");
header("Content-Disposition:attachment;filename='$fileName'");
header('Content-Length: '.$size);
readfile($url);
I hope this helps!

Getting an 'html' type instead of 'image' from the browser

I'm using CURL to fetch an image file from our server. After checking the browser's developer tools, it says that the returned type is 'html' instead of 'image'.
Here's the response:
/f/gc.php?f=http://www.norbert.com/get/image/BTS-005-00.jpg
GET 200 text/html 484.42 KB 1.68 s <img>
Here's the CURL script:
$ch = curl_init();
$strUrl = $strFile;
curl_setopt($ch, CURLOPT_URL, $strUrl);
curl_setopt($ch, CURLOPT_USERAGENT, "MozillaXYZ/1.0");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
$output = curl_exec($ch);
curl_close($ch);
return $output;
Any additional specific code that I could add in my CURL script?
Thanks!
Your PHP script is doing a cURL and returning the output without specific header of image.
So, by default, the browser will retrieve the data as HTML content.
Try to add a more specific header before returning the output.
Try
header('Content-Type: image/jpg');
to specify to the browser the type of content your script is actually sending.
If you want the user to be able to download as file, you can also add the header:
header('Content-Disposition: attachment; filename="' . $fileName . '";');
If you are sending binary content, you could add:
header("Content-Transfer-Encoding: binary");

get remote file size (without using Content-Length field)

I need to get size of remote file without download. I use this code, but headers from some sites doesn't contain Content-Length: field. How can I get filesize in that cases?
$ch = curl_init("http://wordpress.org/latest.zip");
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$data = curl_exec($ch);
curl_close($ch);
$contentLength = 'unknown';
if (preg_match('/Content-Length: (\d+)/', $data, $matches)) {
$contentLength = (int)$matches[1];
}
echo $contentLength;
this is result of echo $data;
HTTP/1.1 200 OK
Server: nginx
Date: Tue, 10 Apr 2012 11:32:20 GMT
Content-Type: application/zip
Connection: close
Pragma: no-cache
Cache-control: private
Content-Description: File Transfer
Content-Disposition: attachment; filename=wordpress-3.3.1.zip
Content-MD5: d6332c76ec09fdc13db412ca0b024df9
X-nc: EXPIRED luv 139
If Content-Length header is not present, that means that file size is unknown. In your case you have Content-Disposition header, wich means that downloadable file is an attachment to server response (same as email attachment). So here if you have no Content-Length header you can't get the size.

Categories