I am making a call(PHP server) to an API and I can confirm that I am getting a response, my code at the point where I know I am getting a response is:
$binaryF = $rsObject->makeCall('get', "/JobData/{$_GET["jID"]}", "?format=bin");
//header("Pragma: public"); // required
//header("Content-Type: application/zip");
//header("Content-Disposition: attachment; filename=ss.zip");
//header("Content-Length: " . filesize($binaryF.length));
//header("Content-Transfer-Encoding: binary");
file_put_contents('C:\ss.zip', $binaryF);
If I keep the code as is and click on the link that takes me to the page with this code on it, ss.zip is created and I open it and confirm that it has the correct content. The data is coming from an API call on the first line and is basically a zip package. If I remove the comments and comment out the file_put_contents line then the browser opens a file save dialog box but if I save it the archive is 0 bytes?
How do I send the content to a browser after retrieving it from the api call? I do not want to save it to disk first, I want to send it to the browser making the request directly.
Thank you
Jack
Ok. I changed it to:
header("Pragma: public"); // required
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=ss.zip");
header("Content-Length: " . strlen($binaryF));
header("Content-Transfer-Encoding: binary");
and now it opens the file save. I save it and it is 8 K but when I try t oopen it I get a message of: "Windows cannot open the folder" It complains that the zip is invalid? At least I am getting somewhere, thanks for the help so far!
Try (untested):
header('Content-type: application/octet-stream');
header('Content-disposition: attachment; filename=ss.zip');
echo $binaryF;
$binaryF would need to be a string value for the filepath to the file you are trying to serve up in order for filesize() to work.
You can use strlen() to get the filesize for use in the ContentLength header.
You of course still need to actually output the file to the client browser.
I had some similar problems with PDF's, for me the Content-Length couldn't be calculated correctly with strlen() because it doesn't support multibyte-characters.
instead try this:
header("Content-Length: " . mb_strlen($binaryF));
See the documentation for more detailed information: http://www.php.net/manual/en/function.mb-strlen.php
Ok, #zerkms helped me by pointing out that I should use: strlen($binaryF) instead of filesize($binaryF.length) He helped me in a chat session by telling me to open the zip archive(with something simple like notepad) that I did get with file_put_contents('C:\ss.zip', $binaryF); This showed that what was produced was only partially correct, there was some HTML content that slipped into the response of the actual call. So all credit goes to #zerkms, thanks.
What worked? the following worked for me:
header("Pragma: public"); // required
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=ss.zip");
header("Content-Length: " . filesize($binaryF.length));
header("Content-Transfer-Encoding: binary");
echo $binaryF
Related
I'm stuck...
For some reason no matter what I try, I can't get the browser to prompt me to download a file. I've taken the code below down to the minimum to try and troubleshoot it. What am I missing? When I run this, no prompt is given. When I view the page, it looks like it read the file, its just a bunch of unreadable characters.
<?php
header("Content-type: application/pdf");
header("Content-Disposition: attachment; filename='downloaded.pdf'");
readfile("docs/contract.pdf");
?>
Try using the original filename in Content Disposition header.You could try code like this:
<?php
header("Content-type: application/pdf");
header("Content-Transfer-Encoding: Binary");
header("Content-Disposition: attachment; filename=contract.pdf");
readfile("docs/contract.pdf");
?>
Also, Ensure no output before sending headers. Sending/modifying HTTP headers must be invoked before any output is made. Otherwise the call fails.
I've created a function to issue a download once user click a link, the file is located in 3rd party storage service (Sugar Sync) and is accessed via their REST API. Now I've created the force download function and tested it runs fine on localhost (a download dialog is prompted), but when I run the function on the server it returns an error page of 'File not Found'. I figured this might be some PHP configuration that needs to be set on server side, but I've got no clue which, so any help or hint is greatly appreciated.
Here's a snippet of the code:
$sugarsync = new SugarSync($refreshtoken);
$response = $sugarsync->get($url);
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: no-cache, must-revalidate");
header("Content-Type: ".$response->mediaType);
header("Content-Type: application/force-download");
header("Content-Disposition: attachment; filename=".$response->displayName.";");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".$response->size);
//file is returned as binary data from the API
print($sugarsync->download(urldecode($url)));
exit();
As it turns out, after further troubleshooting, the problem is related to output buffering, so I just need to enable that on the server config.
Try adding ob_get_clean(); before your print function like so:
ob_get_clean();
//file is returned as binary data from the API
print($sugarsync->download(urldecode($url)));
exit();
I need to retrieve our reports from the jasperserver report engine as a PDF, then I want the PDF to be forced as a download, instead of being displayed inthe browser. The problem with displaying in the browser is we don't want the report parameters to be displayed to the end users in the url.
If I enter this URL path into the browser I get a PDF document that shows in the same browser window with all the report data:
https://mysite.com:8443/jasperserver/flow.html?_flowId=viewReportFlow&reportUnit=sample_report&output=pdf;
What I would prefer to have happen is for a download dialog box to be used and for the users to download the PDF to their computer, instead of it showing in the browser.
I've tried the following php code, but can't get it to work. I get a return value of false, but nothing in the server logs that shows an error.
ob_start();
header("Location: $src"); /* Redirect browser */
$report_contents = ob_get_contents();
ob_end_clean();
var_dump($report_contents);
I'm not really sure how to go about this...anyone got any ideas?
Thanks for the help.
You could buffer the file to the PHP server then output with force download:
header('Content-disposition: attachment; filename=huge_document.pdf');
header('Content-type: application/pdf');
readfile('https://mysite.com:8443/jasperserver/flow.html?_flowId=viewReportFlow&reportUnit=sample_report&output=pdf;');
See the notes about using readfile over an HTTP stream wrapper
http://php.net/manual/en/function.readfile.php
how about
$source=$url
header("Expires: 0");
header("Cache-Control: private");
header("Pragma: cache");
header("Content-length: $size");
header("Content-type: $type");
header("Content-Disposition: attachment; filename=$name");
readfile($source);
exit();
i have a tar archive on the server that must be downloadable through php. This is the code that i've used:
$content=file_get_contents($tar);
header("Content-Type: application/force-download");
header("Content-Disposition: attachment; filename=$tar");
header("Content-Length: ".strlen($content));
unlink($name);
die($content);
The file is downloaded but it's broken and it can't be open. I think that there's something wrong with headers because the file on the server can be open without problems. Do you know how can i solve this problem?
UPDATE
I've tried to print an iframe like this:
<iframe src="<?php echo $tar?>"></iframe>
And the download works, so i'm sure that there's something missing in headers.
I have used this code when I have had to do it:
function _Download($f_location, $f_name){
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Length: ' . filesize($f_location));
header('Content-Disposition: attachment; filename=' . basename($f_name));
readfile($f_location);
}
_Download("../directory/to/tar/raj.tar", "raj.tar");
//or
_Download("/var/www/vhost/domain.com/httpdocs/directory/to/tar/raj.tar", "raj.tar");
Try that.
Don't use file_get_contents() and then echo or print to output the file. That loads the full contents of the file into memory. A large file can/will exceed your script's memory_limit and kill the script.
For dumping a file's contents to the client, it's best to use readfile() - it will properly slurp up file chunks and spit them out at the client without exceeding available memory. Just remember to turn off output buffering before you do so, otherwise you're essentially just doing file_get_contents() again
So, you end up with this:
$tar = 'somefile.tar';
$tar_path = '/the/full/path/to/where/the/file/is' . $tar;
$size = filesize($tar_path);
header("Content-Type: application/x-tar");
header("Content-Disposition: attachment; filename='".$tar."'");
header("Content-Length: $size");
header("Content-Transfer-Encoding: binary");
readfile($tar_path);
If your tar file is actually gzipped, then use "application/x-gtar" instead.
If the file still comes out corrupted after download, do some checking on the client side:
Is the downloaded file 0 bytes, but the download process seemed to take much longer than it would take for 0 bytes to transfer, then it's something client-side preventing the download. Virus scanner? Trojan?
Is the downloaded file partially present, but smaller than the original? Something killed the transfer prematurely. Overeager firewall? Download manager having a bad day? Output buffering active on the server and the last buffer bucket not being flushed properly?
Is the downloaded file the same size as the original? Do an md5/sha1/crc checksum on both copies. If those are the same, then something's wrong with the app opening the file, not the file itself
Is the downloaded file bigger than the original? Open the file in notepad (or something better like notepad++ which doesn't take years to open big fils) and see if any PHP warnings messages, or some invisible whitespace you can't see in your script got inserted into the download at the start or end of the file.
Try something like the following:
$s_filePath = 'somefile.ext';
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'. s_filePath.'"');
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
header('Cache-control: private');
header('Pragma: private');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header("Content-Length: ".filesize($s_filePath));
$r_fh = fopen($s_filePath,'r');
while(feof($r_fh) === false) {
$s_part = fread($r_fh,10240);
echo $s_part;
}
fclose($r_fh);
exit();
Use Content-Type: application/octet-stream or Content-Type: application/x-gtar
Make sure you aren't echoing anything that isn't the file output. Call ob_clean() before the headers
Normally, when I want to allow a user to download a file without revealing the exact location, I just use something like this to let them download the file:
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"" . $filename) . "\";");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($filename));
readfile("$filename");
But if they are using a modern browser or other download client, and they pause the download and try to resume it, the script (assuming they are still authenticated or whatever) will resend the headers and the file contents from the beginning, thus breaking the download, and basically requiring the file to be redownloaded from the beginning.
How can I enable my script to compensate for paused (and consequentially, resumed) downloads?
Use php's built-in fopen to open the file and then fseek to the right place (based on the range in the request header) and then return the partial file using fpassthru instead of using readfile.
You can find some example code in php under the comments for fread
You need to read the request headers like Range, If-Range, etc then seek to the correct location in the file. Normally a web-server would do this for you on an ordinary file. It's a bit complex but here's something that might get you started:
http://forums.asp.net/t/1218116.aspx
http://www.notes411.com/dominosource/tips.nsf/0/480C4E3BE825F69D802571BC007D5AC9!opendocument
For the second link the code is in part 12