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/
Related
everybody, im running in some issue right now, see for internal situations with the server that i cant control or anything right now i cant use base64 encoded files directly over the website cause when the server delivers content to the browser it has a limit of characters for those tasks and it directly affects base64 encoded files cause of the lenght of those strings, so i made for one system a php script that delivers an already existing base64 pdf files to the client as a downloadable file, and it worked just like this:
$reg = File::find($args->string('id')); //querying the file from database
$filename = $reg->filename; //the original file name
$base64 = $reg->file; //the base64 encoded file
$meta_type = explode(',', $base64) [0]; //getting the meta type of the file
$meta_type = str_replace('data:', '', $meta_type);
$meta_type = str_replace(';base64', '', $meta_type);
$file = explode(',', $base64) [1];
$file = base64_decode($base64); //decoding the base64 string
header('Content-Description: File Transfer');
header('Content-Type: ' . $meta_type);
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . (strlen($file)));
echo $file;
this worked just fine when i use pdf files but when i try to use it on some 'xlsx' files it seem to work, it download the file, the filesize and all seem to match the original, but excel cant open the file, does anybody have an idea of what im i missing here?? :)
I am pretty sure, its happening, because you are not exiting your function and it continues to fill up buffers. You have to stop the script immediatelly after your stream is ready, clean the buffer and exit.
If its a valid Excel file, all you have to do is:
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Cache-Control: must-revalidate');
header('Expires: 0');
header('Pragma: public');
header('Content-Disposition: attachment; filename="' . $filename . '"');
if (ob_get_contents() || ob_get_length()) {
ob_end_clean(); //or ob_end_flush();
}
exit();
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 code to serve requested files in PHP. It's testing code, so input is not validated. (By the way, how to correctly sanitize this kind of input...)
$upload_dir = "/media/usb/dir";
$filename = $_GET['filename'];
$mimetype = $_GET['mime'];
$path = $upload_dir . $filename;
header('Content-Description: File Transfer');
header("Content-Type: ".$mimetype );
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($path));
header("X-Sendfile: \"$path\"");
echo readfile($path);
But size of file in bytes is appended to each file.
For example simple txt like this:
myfile
Will become this:
myfile6
How to get rid of this behaviour?
I'm getting textfile like this:
download.php?mime=text/plain&filename=my-file.txt
readfile() returns the size of the file. You can add # to the beginning of the function to remove the error reporting. echo #readfile($path); should display only the filename.
Hi I am trying to allow download a demo file which is related to a product. my code is like this
if(isset($_POST['submit'])){
$root = $_SERVER['DOCUMENT_ROOT'];
$path = "/download/";
$path = $root.$path;
$filename = $demo;
$file = $path.$filename;
header('Content-Type: application/force-download');
header("Content-Transfer-Encoding: Binary");
header("Content-Disposition: attachment; filename=\"".basename($file)."\";" );
header("Content-Length: ".filesize($file));
readfile($file);
}
I am able to get file name which is associated with the product by
$demo
After user submits his information, download will start automatically. Now this is downloading a non existing file or corrupted file with the proper file name. please help
<?php
$file = 'monkey.gif';
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, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit;
}
?>
As you can see Content type is application/octet-steam meaning file is byte by byte encoded. Also the cache headers are set. Then headers are forcefully sent by ob_clean();flush(); and then the file is read.
The file_exists is there to ensure that given file exists. You should also try not not thrust user input as they could easy write names for your php codes and download EACH file. And with ../ in names of the files, even your documents or system files and so on.
i though i found the answer here:
Serving .docx files through Php
But i am still getting the error that the file is corrupt when trying to download and open a docx server via php
Maybe you can see something wrong with my code. The .doc works fine it is the docx that fail.
$parts = pathinfo($doc);
$docFile = $userDocRoot.$doc;
if ( !file_exists($docFile) ){
throw new Exception("Can not find ".$parts ['basename']." on server");
}
if ( $parts['extension'] == 'docx' ){
header('Content-type: application/vnd.openxmlformats- officedocument.wordprocessingml.document');
header('Content-Disposition: attachment; filename="'.$parts['basename'].'"');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
ob_clean();
flush();
readfile($docFile);
}else{
header('Content-type: application/msword');
header('Content-Disposition: attachment; filename="'.$parts['basename'].'"');
readfile($docFile);
}
The solution for me was to add
$fsize = filesize($docFile);
header("Content-Length: ".$fsize);
Thanks for everyones help
There were a few extra spaces in your code which would cause it to fail.
Try using this code:
$parts = pathinfo($doc);
$docFile = $userDocRoot . $doc;
if(!file_exists($docFile)){
throw new Exception('Can not find ' . $parts['basename'] . ' on server');
}
if($parts['extension'] == 'docx') {
header('Content-type: application/vnd.openxmlformats-officedocument.wordprocessingml.document');
header('Content-Disposition: attachment; filename="' . $parts['basename'] . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
ob_clean();
flush();
readfile($docFile);
} else {
header('Content-type: application/msword');
header('Content-Disposition: attachment; filename="' . $parts['basename'] . '"');
readfile($docFile);
}
If it still doesn't work, try commenting out the header and the readfile lines, then you will see if there are any errors.
Also, I suggest that you check the filenames against a whitelist, so that people can't download PHP files with passwords in them, etc.
I have just spent a while looking at why my DOCX files are being corrupted and stumbled across this... but I have also found the answer elsewhere...
$fsize = filesize($docFile);
header("Content-Length: ".$fsize);
This gave me the tools to look for... and the key is that filesize() needs the basename of the file to get an accurate file size!
Adapting my code:
header("Content-Length: ".filesize(basename($file)));
This now offers DOCX (I have set the Content-type to "application/vnd.openxmlformats-officedocument.wordprocessingml.document") as intended and I do not have to "repair" the document like others have reported... (I also found that repairing worked)
Here is a code that's working for me (after about 5 hours of messing around):
// headers to send your file
header('Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document');
header("Content-Length: " . filesize($original_file));
header('Content-Disposition: attachment; filename="' . $new_filename . '"');
ob_clean();
flush();
readfile($original_file);
exit;
I hope it helps :)
I had the same issue.
The reason was, that somewhere in my php-file two spaces were hidden.
Removing them fixed the issue.
Add "//" in front of the header and readfile-statements
Write echo "test"; after the readfile-statement.
Then look in the HTML source-code, if there are spaces in front of
the "test".