PHP is reading file instead of downloading - php

I have script below for downloading files from a folder using PHP, it is working local but online it is reading and printing on the page instate of downloading.
if( $result && count($result) > 0){
$row = $result[0];
$book = true;
$Location = './files/';
$bookLocation = $Location . $row['file_name']; // exampe: report.zip
if( file_exists( $bookLocation ) ){
$fileLocation = $bookLocation;
$file_size = filesize($fileLocation);
echo 'Please wait downloading the file....';
header('Content-Description: File Transfer');
header('Content-Type: application/force-download');
header('Content-Disposition: attachment; filename=' . $row['file_name']);
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: ' . $file_size);
ob_clean();
flush();
readfile($fileLocation);
exit;
}else{
echo '<h3>Sorry!, file not found...</h3>';
}
}
.htaccess script
RewriteEngine on
RewriteRule ^$ index.html
RewriteRule ^index.html$ index.php
RewriteRule ^([0-9]{1,9})(/)([^/\.]+[^/\.]+)(_+[^/\.]+)(\.html|)/?$ index.php?id=$1&cat=$3
RewriteRule ^([^/\.]+[^/\.]+)(\.html|)/?$ index.php?page=$1
RewriteRule ^(.*)(/)([0-9]{1,9})(/)(.*)(\.html|)/?$ index.php?view_file=$3&file=$5
RewriteRule ^(.*)(/)([0-9]{1,9})(/)(.*)(\.htm)/?$ index.php?download=$3
RewriteRule ^(author)(/)(.*)(.html)/?$ index.php?user=$1
Thanks for the help.

It is possible that in certain browsers, you set it to automatically download and run that particular file type.
If that is the case, there is no way to "fix" this. The browser decides what to do with the file, even if you tell it to download it, the user might have told it to run directly.
Big Edit
While my earlier comment is correct, you have a major issue in your code:
$file_size = filesize($fileLocation);
echo 'Please wait downloading the file....';
header('Content-Description: File Transfer');
You must remove that echo statement. It is bound to cause issues, such as the headers not being sent. Considering your description, I'd say this is your problem.
See, once you send any content, you cannot send more headers.

As Christian suggested, you must remove the echo statement in your code. If it doesn't work for you even after that, try replacing the line
header('Content-Type: application/force-download');
with
header('Content-Type: application/octet-stream');

Related

PHP - Change file name from url when user downloads file

File links are all http://website.com/f/xxx.png/zip/txt and so on.
I need to set it up so that if a user downloads that file it would download with a different name.
I have seen how to do this on a normal page, but I have no clue how making it work when the image itself is linked to is done.
Appreciate any help :)
Edit: Using the rewrite Steven Jeffries posted,
header('Content-Disposition: inline; filename=' . $originalFileName . "'");
header("Content-Type:" . $mimeType);
$im = imagecreatefrompng($filePathOnServer);
imagepng($im);
to display images and
header('Content-Disposition: attachment; filename=' . $originalFileName . "'");
header("Content-Type:" . $mimeType);
to make other files download solved the issues I had.
I think an easy way to do this would be to redirect download links to another script that handles what to download, etc. Basically, I'd set up a download dir, add some rewrite rules, and then create a script to handle what gets output.
Something like this (untested):
/path-to-web-root/download/.htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^.* /downloads/handle-downloads.php
/path-to-web-root/download/handle-downloads.php
$url = trim($_SERVER['REQUEST_URI'], '/');
if (preg_match('^#downloads/(?<real_filename>.*?)/(?<options>.*)/(?<fake_filename>.*)$#', $url, $matches)) {
// Double check my regex, but basically pull the real filename from the url here
$actual_file = "/path-to-webroot/f/{$matches['real_filename']}";
$options = explode('/', $matches['options']);
if (in_array('zip', $options)) {
// Handle zip, etc.
}
$fake_filename = $matches['fake_filename'];
if (file_exists($actual_file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($fake_filename).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($actual_file));
readfile($file);
exit;
}
}
Then, instead of having the download link being website.com/f/xxx.png/zip/txt, you could instead do website.com/download/xxx.png/zip/txt/new-filename.png. This would allow you to set the filename to whatever you wanted since the browser will just take what's at the end of the url.
Edit: I've included the relevant code from readfile's manual page.
You can set the file response file name by setting header parameter.
For example:
<?php
header('Content-Type: image/png');
header('Content-Disposition: attachment; filename="xyz.png"');
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
...
More on PHP header function here: http://php.net/manual/en/function.header.php

PHP force download corrupt PDF file

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!

PHP Coding for downloading the image

In the website page contains many images with downloading options. If I click the download button it automatically downloaded on user system and it shows on browser downloadable page. I have PHP code like
$image = file_get_contents('http://website.com/images/logo.png');
file_put_contents('C:/Users/ASUS/Downloads/image.jpg', $image);
Above coding is working fine. But I need to provide the path name for image to save. In user side we don`t know the path.
I need the PHP code to use the browser download location and download images need to show the browser downloads.
not possible to store the image in particular user location due to security issues .you don't force user .you have to suggest him to store particular location .and also you don't know the what file system there in user system.and also downloading path can be setting up by user anywhere so your not able to get that.
$filename = '/images/'.basename($_POST['text']);
file_put_contents($filename, $content);
you have to save/download the image somewhere on your web serwer and next send the file to user using header function, for example:
$file = 'path_to_image';
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
else {
echo "file not exists";
}
manual
`<?php
$filename ='http://website.com/images/logo.png';
$size = #getimagesize($filename);
$fp = #fopen($filename, "rb");
if ($size && $fp)
{
header("Content-type: {$size['mime']}");
header("Content-Length: " . filesize($filename));
header("Content-Disposition: attachment; filename=$filename");
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
fpassthru($fp);
exit;
}
header("HTTP/1.0 404 Not Found");
?>`

download files for only php users htaccess

how could i do this with htaccess , please ?
if (url has not parameter ?down=true)
redirect back
else
do noting
end if
example
example.com/upload/file.pdf // it mustn't downlaod the file
example.com/upload/file.pdf?down=true // it must download the file
please help me :)
that's my htaccess file
RewriteEngine on
RewriteRule ^upload/file/(.*) http\:\/\/www\.example\.org\/down.php?file=$1 [L]
this is the down.php page
<?php
session_start();
if(isset($_SESSION["user_id"])){
if(isset($_GET["file"])) $file = mysql_escape_string($_GET["file"]);
$file = "http://www.example.org/upload/file/".$file;
$file = preg_replace("/ /", "%20", $file);
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
//header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}else{
header('Location:login.php');
}
exit();
You need %{QUERY_STRING} variable inside a RewriteCond for that checking for redirect like this.
RewriteEngine On
RewriteCond %{QUERY_STRING} !(^|&)down=true($|&)
RewriteRule example\.com\/upload\/file\.pdf /index.php [L]
if your RewiteCond has a down=true in the query string, then do not apply the following rule,else rewrites all request to /index.php

temp. download links (with codeigniter)

I was wondering how I could start generating temporarily download links based on files from a protected directory (e.g. /downloads/). These links need to be valid until someone used it 5 times or so or after a week or so, after that the link shouldn't be accessible anymore.
Any help would be appreciated.
One clever solution I've stumbled upon lately if you're using apache (or lighty) is to use mod_xsendfile (http://tn123.ath.cx/mod_xsendfile/), an apache module that uses a header to determine which file to deliver to the user.
It's very simple to install (see link above), and afterward, just include these lines in your .htaccess file:
XSendFile on
XSendFileAllowAbove on
Then in your php code, do something like this when you want the user to receive the file:
header('X-Sendfile: /var/notwebroot/files/secretfile.zip')
Apache will intercept any response with an X-Sendfile header, and instead of sending whatever content you output (you may as well return a blank page), apache will deliver the file.
This takes out all the pain of dealing with mimetypes, chunking, and miscellaneous headers.
Use a database. Every time a file is downloaded the database would be updated, as soon as a certain file has reached it's limit it can be either removed or it's access could be denied. For example:
$data = $this->some_model->get_file_info($id_of_current_file);
if ( $data->max_downloads <= 5 )
{
// Allow access to the file
}
I generally keep files outside of the website directory structure for security and request like so:
function retrive_file($file_hash)
{
$this->_redirect();
$this->db->where('file_hash', $file_hash);
$query = $this->db->get('file_uploads');
if($query->num_rows() > 0)
{
$file_info = $query->row();
if($file_info->protect == 1){
$this->_checklogin();
}
$filesize = filesize($file_info->file_path . $file_info->file_name);
$file = fopen($file_info->file_path . $file_info->file_name, "r");
// Generate the server headers
if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE"))
{
header('Content-Type: "application/octet-stream"');
header('Content-Disposition: attachment; filename="'.$file_info->file_name.'"');
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: ".$filesize);
}
else
{
header('Content-Type: "application/octet-stream"');
header('Content-Disposition: attachment; filename="'.$file_info->file_name.'"');
header("Content-Transfer-Encoding: binary");
header('Expires: 0');
header('Pragma: no-cache');
header("Content-Length: ".$filesize);
}
if($file)
{
while(!feof($file)){
set_time_limit(0);
echo fread($file, $filesize);
flush();
ob_flush();
}
}
fclose($file);
}
}
It would be pretty trivial to add byte/request counting to this.

Categories