When a user runs this PHP script it is supposed to just download the specified image file but for some reason, it's only downloading it partially. It starts the download then stalls at 1,083 KB / 1,382 KB. The download stops after a few seconds and when I open the image, the bottom portion is grey/missing. This script worked fine on my old server but the new server it won't. I tried changing PHP settings and version but no luck.
<?php
if (file_exists("test-download-image.jpg")) {
header("Pragma: no-cache");
header('Expires: 0');
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="test-download-image.jpg"');
header('Content-Length: ' . filesize("test-download-image.jpg"));
readfile("test-download-image.jpg");
}
?>
Related
I want to "pipe" a file through PHP.
My PHP script calls a bash script through "shell_exec". The bash script downloads a file and prints its data. The PHP script then continues to send the file as response:
if (!file_exists("./$filename")) shell_exec("./get-file $file_id \"$filename\"");
if (file_exists($filename)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($filename) . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filename));
readfile($filename);
unlink($filename);
exit;
}
This works okay. But is there some way to "pipe" the file while it's being downloaded? Let's say the file is 500MB, instead of waiting for the file to download in the server, and then serve it to the client, is there some way to send the content as it's being downloaded? The reason is obvious; I want to minimize the total time it takes for the whole process to complete. If what I ask is possible, it could bring total time to half. Thank you.
Edit: I found this but the solution is based on curl. In my case, the file is being downloaded by external script. So I want to run a loop in which the PHP script checks if new bytes are written in the file, and proceed to sending them to the client, without closing the connection. Note that the file is not text-based, it's an audio file.
Edit: Now I'm closer: I modified the external script to output the file in stdout, effectively feeding its data to shell_exec. Now, how can I send data before shell_exec has finished? I guess I'll have to use something like ob_flush() but some help would be appreciated. Thanks again
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($filename) . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
// This sends the data AFTER the exec finishes. I want to send them as they arrive, real-time
echo shell_exec("get-file $file_id");
die();
OK I found the answer in other posts.
I just use passthru() instead of shell_exec() and it seems to be working great.
Thank everybody! <3
I'm using the following code to force download some mp3 files that are stored on my server. This works fine but it takes over 1 minute to download 1 mp3 file, even for a file that is 2.5MB. Something seems wrong for it take that long. Any ideas what I can do to make this download a lot faster?
$fullfilename=$_GET['file'];
$filename=basename($fullfilename);
header('Content-type: audio/mpeg');
header("Content-Disposition: attachment; filename=\"{$filename}\"");
header("Content-Length: " . filesize($filename));
header('Content-Transfer-Encoding: binary');
ob_clean();
flush();
readfile($fullfilename);
exit;
It depends on the internet connection between the server and your browser. PHP cannot do anything about it.
When I run the function below it locates and reads the file, displaying the results in the my Chrome Dev Tools preview tab correctly in the csv format. But it's not downloading it. If I link directly to the file in my browser it downloads it, so it doesn't appear to be an .htaccess issue. I've used the example in the documentation and many variations of it found here on Stack Overflow but the results are the same: the file displays in my preview tab in dev tools (and the same goes with Firefox as well) but no download. My code:
public function download()
{
$file = $this->dir;
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename='. $file);
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit;
}
}
I'm developing locally with latest Wamp server. When I push/pull to my remote, the result is the same.
From your question, it sounds like you might be trying to download your file via an AJAX request.
If so, I don't believe you can do this. Instead you could open the link to the file in a new window, which will successfully download the file.
I'm using this script:
http://www.webvamp.co.uk/blog/coding/creating-one-time-download-links/
to allow users download files (one time). Everything works fine with small files. Now i'm trying to do the same but with larger file 1.2 GB. Instead of forcing user to download file, script show off the relative patch to the file! Is there any way to modify the script or its a fault of the server configuration?
Thanks for help!
Looking for the code i think it fails on large files due to memory limitation. Script reads the whole file in memory via file_get_contents() before sending it. I suspect, >1Gb files will cause the problems with memory.
Try to replace following lines in download.php script:
//get the file content
$strFile = file_get_contents($strDownload);
//set the headers to force a download
header("Content-type: application/force-download");
header("Content-Disposition: attachment;
filename=\"".str_replace(" ", "_", $arrCheck['file'])."\"");
//echo the file to the user
echo $strFile;
to:
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($strDownload));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($strDownload));
ob_clean();
flush();
readfile($strDownload);
This may be help.
Note from manual: readfile() will not present any memory issues, even when sending large files, on its own
I have this code:
$file = $tempDir . "/download.zip";
// there's some omitted code here that creates the file that's to be downloaded
if(file_exists($file) && is_readable($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
}else{
return "Error: Failed to retrieve file.";
}
The code that generates the file works fine, and after hitting the button for downloading, I see it appear in its appropriate place, at 1 KB. The file is also usable. When I download, it even says it's "973 bytes". When the file actually downloads though, it's suddenly 9.1 KB, and completely corrupted. Why?
does the code omitted run a background program? If you run a command line program (exec etc) to create the zip file you may be serving an incomplete file.
upload a zip file that you know works, remove the code to create a zip and see if that is served correctly. if it isn't let me know and i'll take a look.
is this windows or linux?
also the size of the file may vary slightly. windows adds meta data, created,added,modified etc that can effect the file size