I have a file(mp3 speech files) download functionality in my website. When users are trying to download the file, for some users it is working fine. For others it just opened the browser download window and it remains without downloading any content. it is showing 0% even after half an hour. can anyone suggest a solution.
The site is developed in PHP. The users are from USA. Will this happen due to any firewall?
below is the code for downloading the file
header("Cache-Control: cache, must-revalidate");
header("Pragma: public");
header('Content-Type: application/force-download');
header('Content-Disposition: attachment; filename="' . $originalFileName . '"');
header('Content-Length: '.$fileSize);
//open the file
$fp = fopen($filePath, 'rb');
//seek to start of missing part
fseek($fp, $seek_start);
//start buffered download
while(!feof($fp))
{
//reset time limit for big files
set_time_limit(0);
print(fread($fp, 1024*8));
flush();
ob_flush();
session_write_close();
}
fclose($fp);
You can write session_write_close() outside of the while loop.
I think if you are closing session again and again then it will not work.
Related
I am having issues with downloading a file in php. I've got a folder with files outside my server root (for security reasons, but I dont think this might by the problem), and I am trying to download a file using the script below,
where $_POST['path'] or $filename (after check) is the absolute path of my folder, like
/home/username/storage/filename.extension
and my server root path is /home/username/www
when I try to download a .txt file, everything seems to work fine - I can download it and open it.
However, when I downloaded an image or video file, none of the applications on my computer could open the file.
For .png it says that my file is not a PNG file, for .jpg it says it does not start with 0x0a 0x0a, etc.
Everytime I've tried to download something, the size of the file in the folder from which I downloaded it was equal to the size of the file that I downloaded. But there is something wrong with the format/contents of the file.
I checked the files in the directory from which I am downloading, there is no problem with them. The problem is only with the downloaded ones, so for some reason my script does not download them correctly.
Maybe my headers are not correct? Or maybe there might be a problem with files above some size (my txt files are smaller than images.., but even a 300M video was downloaded in a couple of seconds)? (However, there is no error in apache error log.) Or what am I doing wrong, please?
if(isset($_POST['path'])) {
//Read the filename
//+there are some checks on the path, to make sure user does not download a file which I dont want him to be able to download, but I dont think that is important, because the .txt file is downloaded normally
$filename = $_POST['path'];
//Check the file exists or not
if(file_exists($filename)) {
//Define header information
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header("Cache-Control: no-cache, must-revalidate");
header("Expires: 0");
header('Content-Disposition: attachment; filename="'.basename($filename).'"');
header('Content-Length: ' . filesize($filename));
header('Pragma: public');
//Clear system output buffer
flush();
//Read the size of the file
readfile($filename);
//Terminate from the script
die();
}
else{
echo "File does not exist.";
}
}
else
echo "Filename is not defined."
Seems that calling the ob_clean() method before readfile() was helpful :),
for more information, see https://www.php.net/manual/en/function.ob-clean.php
this works for me:
if(isset($_POST['path']))
{
//Read the filename
$filename = $_POST['path'];
//Check the file exists or not
if(file_exists($filename)) {
//Define header information
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header("Cache-Control: must-revalidate");
header('Content-Transfer-Encoding: binary');
header("Expires: 0");
header('Content-Disposition: attachment; filename="'.basename($filename).'"');
header('Content-Length: ' . filesize($filename));
header('Pragma: public');
ob_clean(); //<----- I had to add THIS LINE
//Clear system output buffer
flush();
//Read the size of the file
readfile($filename);
//Terminate from the script
die();
}
else{
echo "File does not exist.";
}
}
else
echo "Filename is not defined."
I write some small script and it is working ok! however when i try download large file such a more than 1GB Download is stopping around ~880MB
Am i doing something wrong? or is there any better solution for download big file with PHP
This is my code
<?php
set_time_limit(0);
ini_set('memory_limit', '5000M');
//This File is 4GB size
$url = 'example.com/files/file_name.zip';
$headers = get_headers($url, TRUE); //collectind header information from file Url
$filesize = $headers['Content-Length']; //File size
while (ob_get_level()) ob_end_clean();
header('Content-Type: application/zip');
header('Content-Disposition: filename=' . basename($url));
header('Content-length: ' . $filesize);
header('Cache-Control: no-cache');
header("Content-Transfer-Encoding: chunked");
ob_flush();
flush();
readfile($url);
exit;
I suspect that you're hitting a memory limit error. Normally readfile avoids using much memory, but depending on your settings it can consume RAM in the process. Check your error logs to confirm that you're seeing a memory allocation error, and if you are seeing it, try getting rid of the while and ob_flush and flush and just add something like this after the headers:
if (ob_get_level()) {
ob_end_clean();
}
readfile($url);
Also, don't pump your memory limit up to 5GB... if this is working correctly you shouldn't require hardly any memory.
If that's not it, can you confirm that you're serving a remotely hosted ZIP file (i.e. you don't have direct access to the ZIP file on the current server)?
I want to serve a .APK file to users to download. I have a CDN and it works fine. When I request file download, It downloads from CDN. But I have a problem. My users request downloads from Android devices, in this case, Downloading pure APK file goes trouble because I want to users install that APK file and with pure APK it's not possible as I know. So I create a .php file like this and add 'Content-Type: application/vnd.android.package-archive':
<?php
$file = 'myfile.apk'; //File that we want to send to user.
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/vnd.android.package-archive');
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);
exit;
}
?>
When I request download.php, Its work and users can download and install the APK file. And now my question is, In this case, That file downloads from the CDN? I want both download.php and APK file served from CDN because I don't have enough traffic.
Or is this possible to add 'Content-Type: application/vnd.android.package-archive' to downloading file from CDN without php?
PS: When i request pure APK file, Because it's from CDN, It downloads instantly like it's caching, But with download.php, It takes time to download. it means in this case it's not from CDN?
Or is this possible to add 'Content-Type: application/vnd.android.package-archive' to downloading file from CDN without php?
Yes, downloading must work correct in this case.
But with download.php, It takes time to download. it means in this case it's not from CDN?
It takes time, because you use readfile and output buffering. In this case, download started only after php fully load content of target file into memory. This is potential problem, if you plan serve big apk files.
You can serve them, to example in this way:
// set headers here ...
$output = fopen('php://out', 'a');
$target = fopen($target, 'r');
if (!$target || !$output) {
// throw error, if cant read file or
}
// read target file, using buffer size 1024
while (!feof($target)) {
fwrite($output, fread($target, 1024), 1024);
}
fclose($target);
fclose($output);
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.
For some reason, our webserver is not responding while it's serving large files.
We use the windows platform, because we need to remotely call Win32 applications in order to generate the file that is to be served. This file is served through PHP's function: fpassthru, using this code:
if (file_exists($file)) {
$handle = #fopen($file, "rb");
header('Content-Description: File Transfer');
header('Content-Type: video/mp4');
if($stream==0){
header('Content-Disposition: attachment; filename='.basename($filename.".mp4"));
}
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_end_clean();
fpassthru($handle);
exit;
}
These files are often over 1GB in size and takes a while to transfer, but during this time, the webserver will not serve any pages. My firefox indicates it's 'connecting' but nothing else. Note that somebody else is transferring this file, not me, so different IP, different session.
Any clue where to look? Obviously, it's intolerable to have to wait 5 minutes for a website.
Thanks in advance!
This is commonly caused when you do not close the session before you begin sending the file data. This is because the session cache file can only be opened by one PHP process at a time, therefore the download is effectively blocking all other PHP processes at session_start().
The solution is to call session_write_close() to commit the session data to disk and close the file handle before you start outputting the file data.