i am just wondering if there is a way of setting up different "content-type" when downloading through php? like .mp3 AND .pdf etc.. instead of having to specify just one file type. My problem is that i have 2 file types to be downloaded, one type is pdf and the other type is mp3, but if i change the "content-type" to audio/mpeg, then it doesn't show the extension for the .pdf... i hope you understand? please help!
If you mean your user is downloading some content that's sent from a PHP script, which is also sending the Content-type HTTP header, can you not set that header with a different value for each type of file ?
Something like this (pseudo-code) :
if (file is a PDF) {
header('Content-type: application/pdf');
} else if (file is a MP3) {
header('Content-type: audio/mpeg');
}
And a "default" case might be useful, if you also have some other files you have not thought about just yet.
This function works great for me:
function Download($path, $speed = null)
{
if (is_file($path) === true)
{
set_time_limit(0);
while (ob_get_level() > 0)
{
ob_end_clean();
}
$size = sprintf('%u', filesize($path));
$speed = (is_null($speed) === true) ? $size : intval($speed) * 1024;
header('Expires: 0');
header('Pragma: public');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Type: application/octet-stream');
header('Content-Length: ' . $size);
header('Content-Disposition: attachment; filename="' . basename($path) . '"');
header('Content-Transfer-Encoding: binary');
for ($i = 0; $i <= $size; $i = $i + $speed)
{
echo file_get_contents($path, false, null, $i, $speed);
while (ob_get_level() > 0)
{
ob_end_clean();
}
flush();
sleep(1);
}
exit();
}
return false;
}
You can also optionally specify the max speed at which the file is delivered.
Related
I want to paste one script in all my client machine which call php file which is on my server.
Let say my server path is www.google.com/support/lokesh.php
So that I want to put one file to all my client machine at location where it call php file(for example if it call from /home/lalu/myscript.sh) then my php code will put one file(additional.sh) to /home/lalu/additional.sh
below is my code to download file
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename('google.com/support/lokesh.txt'));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize('/home/lokesh/lalu.txt'));
readfile('/home/lokesh/lalu.txt');
//for sending mail fif only one user is available
exit;
I want to paste one file location at client machine from where it call server file.
One attempt, with a progress bar.
#!/usr/bin/php
<?php
if (#$argv[1] != null){
echo "Retrieving http header...";
$header = get_headers("$argv[1]");
$pp = "0";
echo json_encode($header, JSON_PRETTY_PRINT);
$key = key(preg_grep('/\bLength\b/i', $header));
$type = key(preg_grep('/\bType\b/i', $header));
$http = substr($header[0], 9, 3);
$tbytes = #explode(" ",$header[$key])[1];
$type = #explode("/",explode(" ",$header[$type])[1])[1];
echo " Target size: ".floor((($tbytes / 1000)/1000))." Mo || ".floor(($tbytes/1000))." Kb";
$t = explode("/",$argv[1]);
$remote = fopen($argv[1], 'r');
$nm = $t[count($t)-1].".$type";
$local = fopen($nm, 'w');
$read_bytes = 0;
echo PHP_EOL;
while(!feof($remote)) {
$buffer = fread($remote, intval($tbytes));
fwrite($local, $buffer);
$read_bytes += 2048;
$progress = min(100, 100 * $read_bytes / $tbytes);
$progress = substr($progress,0 , 6) *4;
$shell = 10; /* Progress bar width */
$rt = $shell * $progress / 100;
echo " \033[35;2m\e[0m Downloading: [".round($progress,3)."%] ".floor((($read_bytes/1000)*4))."Kb ";
if ($pp === $shell){$pp=0;};
if ($rt === $shell){$rt=0;};
echo str_repeat("█",$rt).str_repeat("=",($pp++)).">#\r";
usleep(1000);
}
echo " \033[35;2m\e[0mDone [100%] ".floor((($tbytes / 1000)/1000))." Mo || ".floor(($tbytes/1000))." Kb \r";
echo PHP_EOL;
fclose($remote);
fclose($local);
}
The file is build directly into the current folder, not in the temp directory.
This mean the file can be read while downloading.
If the file type is made to handle that, like most media format do.
To use, pass an url as first argument in the command line.
./pget https://site.download.mp4
You know you want to tweek it ;)
In my opinion, the easiest way is:
$fileContent = file_get_contents('/home/lokesh/lalu.txt');
If I correctly understood.
Try this code. In your download file :
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false);
header("Content-Type: application/".$extension); // you can put here MIME type of your file
header("Content-Disposition: attachment; filename=\"" . basename($filePath) . "\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($filePath));
set_time_limit(0);
readfile("$filePath");
the code I am using:
function DownLoading($Peter)
{
// if(ini_get('zlib.output_compression'))
// ini_set('zlib.output_compression', 'Off')
$File = "";
$Filename = "";
If ($Peter == "Farm") {
$File = "TestFile.txt";
$FileName = $File; //"TestFile.txt";
$len = filesize($File); // Calculate File Size
if (file_exists("TestFile.txt")) {
header('Content-Description: File Transfer');
header('Content-Type: text/plain');
header('Content-Disposition: attachment; filename="TestFile.txt"');
header('Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . $len);
ob_clean();
$wasdownloaded = readfile("TestFile.txt");
if ($wasdownloaded === false)
echo "error";
else {
echo "no error";
Flush();
exit;
}
}
}
}
The strange thing is that if I run this code on wamp server then it works fine (no echoeing, but downloading)
The following is echoed to the sdcreen: This is a test file!!! Nowno error
whereby "This is a test file!!! NOW" is the files's content
Can somebody help me?
I did something very stupid that was causing the same thing. Basically, as already said, you must ensure nothing has been sent already.
I had put a space before the <?php opening declaration - and that was the problem!
I'm doing file download with renaming it before. Everything works except size. I can't set file size with
header('Content-Length: ');
even I'm setting it to
header('Content-Length: 15444544545');
it's not working. I'm using PHP codeigniter framework, where is the problem?
EDIT: more code:
$file_data = array(
'originalName' => $post_info['file_info'][0]['original_name'],
'fakeName' => $post_info['file_info'][0]['file_name'],
'modificationId' => $post_info['file_info'][0]['modification_article_id'],
'extension' => end(explode('.', $post_info['file_info'][0]['original_name'])),
'name' => str_replace(".".end(explode('.', $post_info['file_info'][0]['original_name'])), "", $post_info['file_info'][0]['original_name']),
'filesize' => filesize($post_info['file_info'][0]['file_name'])
);
header('Cache-Control: public');
header('Content-Description: File Transfer');
header('Content-Disposition: attachment; filename=' . $file_data['name'] . '.' . $file_data['extension']);
header('Content-Length: ' . filesize(base_url().$file_data['fakeName']));
// Read file
readfile(base_url().$file_data['fakeName']);
//print_r($file_data);
echo "<script>window.close();</script>";
EDIT: Solution
there was a server problem
You can try like this:
$mm_type="application/octet-stream";
header("Cache-Control: public, must-revalidate");
header("Pragma: hack");
header("Content-Type: " . $mm_type);
header("Content-Length: " .(string)(filesize($fullpath)) );
header('Content-Disposition: attachment; filename="'.$filename.'"');
header("Content-Transfer-Encoding: binary\n");
readfile($fullpath);
wrong usage of base_url().
where is your file stored?
maybe you can try the constant FCPATH instead of call function base_url()
and you have the filesize stored in $file_data['filesize']
finally there should not be a line echo "<script>window.close();</script>"; in your php script when the file content was output.
You tried with download_helper?? Sintax: force_download($filename, $data).
Also in your code you're reading file through URL. Use file system path instead.
From controller action:
<?php
public function download()
{
//Your code here...
$filePath = realpath(FCPATH.DIRECTORY_SEPARATOR.'uploads/myfile.pdf'); //FakeName????
force_download($file_data['fakeName'], readfile($filePath));
}
If my solution don't works give me a touch to give you other way.
Note: FCPATH is the front controller path, a public folder of server e.g.(/var/www/CodeIgniter). Other path constants are already defined on index.php (front-controller).
A print of $file_data['fakeName'] will be useful.
If your CodeIgniter version don't have download_helper make your own... refer to CI docs for full explanation. There is the force_download function code:
function force_download($filename = '', $data = '')
{
if ($filename == '' OR $data == '')
{
return FALSE;
}
// Try to determine if the filename includes a file extension.
// We need it in order to set the MIME type
if (FALSE === strpos($filename, '.'))
{
return FALSE;
}
// Grab the file extension
$x = explode('.', $filename);
$extension = end($x);
// Load the mime types
if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
{
include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php');
}
elseif (is_file(APPPATH.'config/mimes.php'))
{
include(APPPATH.'config/mimes.php');
}
// Set a default mime if we can't find it
if ( ! isset($mimes[$extension]))
{
$mime = 'application/octet-stream';
}
else
{
$mime = (is_array($mimes[$extension])) ? $mimes[$extension][0] : $mimes[$extension];
}
// Generate the server headers
if (strpos($_SERVER['HTTP_USER_AGENT'], "MSIE") !== FALSE)
{
header('Content-Type: "'.$mime.'"');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Transfer-Encoding: binary");
header('Pragma: public');
header("Content-Length: ".strlen($data));
}
else
{
header('Content-Type: "'.$mime.'"');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header("Content-Transfer-Encoding: binary");
header('Expires: 0');
header('Pragma: no-cache');
header("Content-Length: ".strlen($data));
}
exit($data);
}
I have set up a page using php and mysql that requires user to log in to download various paid for programs. They can click on a link as here and the program downloads and runs correctly.
$c3 = mysql_result($result,$i,"exe");
echo "<a href='$c3'>... etc
However, RT-click properties lets them see the path to that file, so I changed the above to:
$c3="downloads3.php?link=".mysql_result($result,$i,"exe");
Where downloads3.php is as follows:
<?php
$file = $_GET['link'];
$size = filesize($file);
$type = filetype($file);
$path = "../downloads/";
header('Content-Type: $type');
header("Content-Transfer-Encoding: Binary");
header("Content-Disposition: attachment; filename=$path.$file");
header("Content-Length: ".filesize($file));
readfile($file_url);?>
?>
It finds the correct file and I get a security warning but on clicking run anyway it immediately gives a windows error message that the file is not compatible with this version of windows. Must be something in the above header but can't figure out what. Tried various permutations.
Any brill ideas, either of getting the above to work or other ways of hiding the source path? Thanks.
It's far more likely that the EXE is getting corrupted due to unexpected output. Your downloads3.php file has some extra output that will appear in the download:
readfile($file_url);?> //PHP stops parsing here
?> //output "\n?>"
The PE header itself tells Windows what versions it can run on, so if any errors get generated before the file gets sent, they'll appear in the place Windows is expecting the header.
To mitigate this you can remove the extra newline and ?> at the end of the file and turn error reporting off with error_reporting(0) at the top of the file.
The Best solution for here to get download file with any name what do you have want
function force_download($filename = '', $data = '')
{
if ($filename == '' OR $data == '')
{
return FALSE;
}
// Try to determine if the filename includes a file extension.
// We need it in order to set the MIME type
if (FALSE === strpos($filename, '.'))
{
return FALSE;
}
// Grab the file extension
$x = explode('.', $filename);
$extension = end($x);
// Load the mime types
if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes'.EXT))
{
include(APPPATH.'config/'.ENVIRONMENT.'/mimes'.EXT);
}
elseif (is_file(APPPATH.'config/mimes'.EXT))
{
include(APPPATH.'config/mimes'.EXT);
}
// Set a default mime if we can't find it
if ( ! isset($mimes[$extension]))
{
$mime = 'application/octet-stream';
}
else
{
$mime = (is_array($mimes[$extension])) ? $mimes[$extension][0] : $mimes[$extension];
}
// Generate the server headers
if (strpos($_SERVER['HTTP_USER_AGENT'], "MSIE") !== FALSE)
{
header('Content-Type: "'.$mime.'"');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Transfer-Encoding: binary");
header('Pragma: public');
header("Content-Length: ".strlen($data));
}
else
{
header('Content-Type: "'.$mime.'"');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header("Content-Transfer-Encoding: binary");
header('Expires: 0');
header('Pragma: no-cache');
header("Content-Length: ".strlen($data));
}
exit($data);
}
$data = 'Here is some text!';
$name = 'mytext.txt';
force_download($name, $data);
DOH!!!!!!!!!!!!!!!! Too much cutting and pasting, that code has a really stupid error readfile($file_url) should be readfile($file), no wonder my 36Mb file was only 1KB after download, it was empty!
Thanks for all the comments, apologies for wasting your time.
I use the following to download a file with PHP:
ob_start();
$browser = id_browser();
header('Content-Type: '.(($browser=='IE' || $browser=='OPERA')?
'application/octetstream':'application/octet-stream'));
header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize(realpath($fullpath)));
//header("Content-Encoding: none");
if($browser == 'IE')
{
header('Content-Disposition: attachment; filename="'.$file.'"');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
} else
{
header('Content-Disposition: attachment; filename="'.$file.'"');
header('Cache-Control: no-cache, must-revalidate');
header('Pragma: no-cache');
}
//#set_time_limit( 0 );
ReadFileChunked(utf8_decode($fullpath));
ob_end_flush();
The source code of ReadFileChunked is:
function ReadFileChunked($filename,$retbytes=true)
{
$chunksize = 1*(1024*1024);
$remainFileSize = filesize($filename);
if($remainFileSize < $chunksize)
$chunksize = $remainFileSize;
$buffer = '';
$cnt =0;
// $handle = fopen($filename, 'rb');
//echo $filename."<br>";
$handle = fopen($filename, 'rb');
if ($handle === false) {
//echo 1;
return false;
}
//echo 2;
while (!feof($handle))
{
//echo "current remain file size $remainFileSize<br>";
//echo "current chunksize $chunksize<br>";
$buffer = fread($handle, $chunksize);
echo $buffer;
sleep(1);
ob_flush();
flush();
if ($retbytes) {
$cnt += strlen($buffer);
}
$remainFileSize -= $chunksize;
if($remainFileSize == 0)
break;
if($remainFileSize < $chunksize)
{
$chunksize = $remainFileSize;
}
}
$status = fclose($handle);
if ($retbytes && $status) {
return $cnt; // return num. bytes delivered like readfile() does.
}
return $status;
}
The question is :
The file downloaded will contiain some html tags which are the content of the html code generated by the php.
The error will happened when downloading the txt file with the file size smaller than 4096 bytes.
Please help me to slove this problem , thank you very much!
Chu
Have you tried using fpassthru rather than your custom function.
There's no need to use the $chunksize stuff in there. fread() automatically stops reading once it reaches the end of the file, even if the $chunksize would normally tell it to read more. As well, you should probably put your ob_flush() and flush() calls BEFORE the sleep(1). That way the data you've just placed in the output buffer can get sent off to the webserver without having to wait the one second needlessly.
In fact, you could replace the whole function with the following:
function ReadFileChunk($filename, $retbytes = true) {
$fh = fopen($filename, 'rb');
if (!$fh) {
return(false);
}
while($buf = fread($fh, 4096)) {
echo $buf;
ob_flush();
flush();
sleep(1);
}
$status = fclose($fh);
return( $retbytes ? filesize($filename) : $status);
}
But why bother rolling your own when readfile() already exists? It will handle the whole business of opening the file, and sending it in normal-sized pieces that won't exceed memory_limit.