I have gotten a problem about downloading .jpg and .avi files from a server using PHP
I have the following code:
$fileName = "Koala.jpg";
$filePath = "./Koala.jpg";
if (!file_exists($filePath)){
echo "No file";
return;
}
$fp = fopen($filePath, "r");
$fileSize = filesize($filePath);
header("Content-type: application/octet-stream");
header("Accept-Ranges: bytes");
header("Content-Length: $fileSize");
header("Content-Disposition: attachment;filename=".$fileName);
$buffer = 1024;
while(!feof($fp)){
$data = fread($fp, $fileSize);
echo $data;
}
fclose($fp);
The code downloads .txt file successfully and the downloaded file can be read.
However, when it comes to .jpg, the downloaded .jpg file cannot be read.
Can anyone give a helping hand? Thanks
Have just tried another method and it works fine
$file = 'Koala.jpg';
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit;
}
But just wonder what reason causes the first method fail, even though using fopen("xxx", "rb") instead. Thank you
Try replacing application/octet-stream for image/jpeg .
Regards
I'm no php expert (sorry to say) but I remember having a similar problem when using php on a Windows server. It stemmed from opening the file without the binary-flag (should be fopen($filePath, "rb"); in your sample). If you don't set that flag your data might be altered when you read it from the stream which could break your files (and you wouldn't notice it on textfiles).
See http://www.php.net/manual/en/function.fopen.php for more info on the different modes available.
Try using this --
<?php
$filename = "MyImage.jpg";
$handle = fopen($filename, "rb");
$contents = fread($handle, filesize($filename));
fclose($handle);
?>
Instead of the following code that you are using,
$buffer = 1024;
while(!feof($fp)){
$data = fread($fp, $fileSize);
echo $data;
}
Just use readfile method
readfile($filePath);
Related
While writing a PHP-Script, im stuck at an issue i cant resolve.
The PHP-Script consist in letting a user download a .mp4 file. The download works without any issues but the file downloaded can not be played.
Heres the code:
<?php
$filepath = "/www/servermedia/technounion.mp4";
$filename = basename($filepath);
header("Content-type: video/mp4");
header("Content-Disposition: attachment; filename=.$filename");
readfile($filename);
exit;
?>
After the .mp4 file gets downloaded, it cannot be played.
It looks like this:
The error message means that Windows Media Player cannot play back the file because probably the player doesnt support the codec. I already tried with VLC but it does not work either.
EDIT:
Comparing both file sizes, the downloaded file is only a couple bytes large instead of the 3,73 MB of the file on the server
Your code is not well-formed, you miss to escape double-quotes by adding single-quotes as I done here, please test my answer.
<?php
$filepath = "/www/servermedia/technounion.mp4";
$filename = basename($filepath);
header('Content-Type: video/mp4');
header('Content-Disposition: attachment; filename="' . $filename . '"');
readfile($filename);
exit;
?>
But I suggest a more complex way:
<?php
$filepath = $_SERVER['DOCUMENT_ROOT'] . "/www/servermedia/technounion.mp4";
$filename = basename($filepath);
header('Content-Type: video/mp4');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Content-Transfer-Encoding: binary');
header('Connection: Keep-Alive');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . sprintf("%u", filesize($filepath)));
set_time_limit(0);
$fh = fopen($filepath, "rb");
while (!feof($fh)) {
echo fgets($fh);
ob_flush();
flush();
}
fclose($fh);
exit;
?>
$_SERVER['DOCUMENT_ROOT'] is useful to get the full path from the server
set_time_limit(0) is useful to avoid any timeout during download
fgets() is useful for reading large files
ob_flush() and flush() assure that there is not other output in the buffer
I hope this helps.
Is the downloaded file the exact same filesize?
Does the content type exist in your webserver?
header("Content-Type: video/mp4"); Note capital 'T' for type.
This maybe worth testing with to see you can serve the file content inline:
http://www.phpmind.com/blog/2016/10/how-to-use-php-to-output-an-mp4-video/
The task is to create a controller to count the number of file downloads. It also must be able to account for failed or cancelled downloads. I was wondering if anyone knew the best way to go about accomplishing this.
$file = $_GET['download'];
if (ob_get_level()) {
ob_end_clean();
}
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
return filesize($file);`
$size = filesize($file);
Then if the number of bytes given is approximately equal to the file size:
if ( $size < given bytes) {
$handle = fopen("counter.txt", "r");
while (!feof($handle)) {
$buffer = fgets($handle, 4096);
$buffer=$buffer+1;
}
fclose($handle);
$fp = fopen("counter.txt", "w");
$test = fwrite( $fp, $buffer);
fclose($fp);
}
How to know the number of bytes sent by server to the user after clicking on link?
I'll start with what should be comments:
You've tagged this as javascript, but your quesiotn appears to have nothing to do with javascript. Please don't do that.
I assume you are aware of the gaping security hole exposed by your script / that you are not concerned about it.
Your handling of output buffering is wrong.
return filesize($file);
What is this line of code supposed to do?
header('Expires: 0');
no.
header('Pragma: public');
again, no.
As to your question - its all covered in the manual:
<?php
ignore_user_abort(1);
$file = $_GET['download'];
if (!is_readable($file)) {
die "No such file";
}
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . basename($file));
header('Content-Transfer-Encoding: binary');
header('Cache-Control: max-age=0; must-revalidate');
header('Content-Length: ' . filesize($file));
$count=0;
$ih=fopen($file, 'r');
while (CONNECTION_NORMAL==connection_status() && !feof($ih)) {
print fgets($ih, 4096);
}
log_completion(feof($ih));
BTW: This does not give an accurate record if the file was downloaded - you can only tell if the content has left PHP land.
I have gone through all articles on Stack Overflow and can't fix my issue. I am using following code:
$file = $_GET['url'];
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
The above mention code is downloading the file from the directly above the root and Yes it is downloading a PDF file but the file is only of 1KB size and not the original size. The $_GET['url'] is receiving ../dir/dir/filename.pdf in it. the filename is space in it as well. For security reason I cannot share the file name.
Please let me know where am I going wrong.
Please make sure you are using the web server path to access the file - for instance your path could be: /home/yourusername/public/sitename/downloads/<filename>, you should check first - to help you can run this at the top of your PHP script to find out the full path for the current script:
echo '<pre>FILE PATH: '.print_r(__FILE__, true).'</pre>';
die();
Only send the filename with the url using urlencode() and on the receiving PHP script use urldecode() to handle any character encoding issues.
See here: http://php.net/manual/en/function.urlencode.php
and here: http://php.net/manual/en/function.urldecode.php
So where you create your url:
Download File
And in your php script:
$file_base_path = '/home/yourusername/public/sitename/downloads/';
$file = urldecode($_GET['url']);
$file = $file_base_path . $file;
$file = $_GET['url'];
if (file_exists($file))
{
if (FALSE!== ($handler = fopen($file, 'r')))
{
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: chunked'); //changed to chunked
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
//header('Content-Length: ' . filesize($file)); //Remove
//Send the content in chunks
while(false !== ($chunk = fread($handler,4096)))
{
echo $chunk;
}
}
exit;
}
echo "<h1>Content error</h1><p>The file does not exist!</p>";
I hope this helps you!
I have an issue while downloading an mp3 file in PHP. I need to download the file, also rename it. Below is the download.php file which contains the following code:
$file = $_GET['file'];
$flname = explode("/",$file);
$num = sizeof($flname);
$filenme = $flname[$num-1];
$name_of_file = $filenme;
header('Content-Description: File Transfer');
header('Content-type: application/mp3');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header('Content-Length: '.filesize($name_of_file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
readfile_chunked($file);
function readfile_chunked($file)
{
$chunksize = 1*(1024*1024); // how many bytes per chunk
$buffer = '';
$handle = fopen($filename, 'rb');
if ($handle === false)
{
return false;
}
while (!feof($handle))
{
$buffer = fread($handle, $chunksize);
print $buffer;
}
return fclose($handle);
}
I am getting the file path in $file:
$file = $_GET['file'];
where $file becomes:
$file = "localhost/project/mp3 file path";
Then I am exploding it to get the mp3 file name only (thus removing the path).
I don't know what the problem is, but it's always showing some 490 bytes in the download dialogue of Firefox even if file is of 1-2MB. Can someone explain what I'm doing wrong?
Thank you in advance.
Open the downloaded file in a text editor. It probably contains php errors that will tell you what exactly is going on. It might be an issue with the path or permissions of the file you are trying to download.
I have a script that creates a zip files from files in a certain directory. After Download, for a lot of users - the zip file is empty. However, for other users - the file isn't empty. Is it something I'm doing wrong?
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="'.$id.'.zip"');
header('Cache-Control: private');
ob_clean();
flush();
readfile("".$id.".zip");
exit;
Better add some error control:
$file = "{$id}.zip";
if (!is_readable($file))
{
die('Not accessible.');
}
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="'.$file.'"');
header('Cache-Control: private');
ob_clean();
flush();
readfile($file);
exit;
Additionally triple check your output buffering configuration vs. readfile.
I recommended this as a suggestion earlier, here is a skeleton of what I am talking about. It is untested as I don't have access to php at the moment.
$filename = $id . '.zip';
$handle = fopen($filename, 'r');
if ($handle === false)
{
die('Could not read file "' . $filename . '"');
}
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Cache-Control: private');
while (!feof($handle))
{
echo fread($handle, 8192);
}
fclose($handle);
exit;