I have a PHP file protector script:
.htaccess
RewriteEngine on
RewriteRule ^(.*).(zip|tgz)$ ../wp-file-protector.php?file=$1.$2 [QSA]
wp-file-protector.php
<?php
global $wpdb;
/** Make sure that the WordPress bootstrap has run before continuing. */
require( dirname(__FILE__) . '/wp-load.php' );
$current_user = wp_get_current_user();
if ($current_user->ID > 0){
$order = $_GET['order'];
$items = new_get_order_by_id_and_user($order, $current_user->ID);
if($items != false){
$file_enabled = true;
//Some authentication
$filepath = dirname(__FILE__).'/../downloads/'.$_GET['file'];
if($file_enabled && file_exists($filepath)){
$filename = basename($filepath);
$extension = end(explode('.', $filename));
ob_clean();
// http headers for zip downloads
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
if($extension == 'tgz'){
header("Content-Type: application/gzip");
}else{
header("Content-type: application/octet-stream");
}
header("Content-Disposition: attachment; filename=\"".$filename."\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($filepath));
ob_end_flush();
#readfile($filepath);
}
}
}
I works fine with zipped and other files. The problem appears with gzipped files. I got unexpected results (also different results for Firefox download and open action).
I think I need some good header for the gzipped files. What should I use?
Also good to know that the request is running through the Cloudflare service, so maybe I should send out some header, which tells cloudflare server to not to gzip it.
I'm stuck :(
Update #1
header("Content-type: application/x-gzip");
This also doesn't work. When I choose save in firefox, it tells when opening that corrupted. When I choose open, I got a file without extension, but it seems tar as I can go deeper into the dir.
Related
I have some zip files in my laravel project and they were downloaded by simple method
return response()->download($path);
now I added forcing https to the website with this:
if (!(isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' ||
$_SERVER['HTTPS'] == 1) ||
isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
$_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'))
{
$redirect = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
header('HTTP/1.1 301 Moved Permanently');
header('Location: ' . $redirect);
exit();
}
and now I can't read the zip files, they seem corrupted.
I opened one of them in hex editor, and I see that there is an additional 0a0a character at the beginning.
I have no idea why this happens and what that means. And especially how to fix it, without editing the downloaded files.
It might be your headers try looking at this blog post and see if that is the fix to your issues.
https://perishablepress.com/http-headers-file-downloads/
<?php // HTTP Headers for ZIP File Downloads
// https://perishablepress.com/press/2010/11/17/http-headers-file-downloads/
// set example variables
$filename = "Inferno.zip";
$filepath = "/var/www/domain/httpdocs/download/path/";
// http headers for zip downloads
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"".$filename."\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($filepath.$filename));
ob_end_flush();
#readfile($filepath.$filename);
?>
I am trying to make a file download dependent inside a session. Here is the code:
<?php>
session_name("My-Download");
session_start();
$_SESSION['Download-Authorized'] = 1;
echo "<a class='invlink' rel='nofollow' download target='_blank' href='download.php?download_file=file.to.download.pdf'>Name of File</a><br /><br />";
?>
The download script ('download.php') comes next:
<?php
session_start();
if(!isset($_SESSION['Download-Authorized'])) {
exit;
}
$path = $_SERVER['DOCUMENT_ROOT']."/downdir/";
$fullPath = $path.$_GET['download_file'];
if ($fd = fopen ($fullPath, "r")) {
$fsize = filesize($fullPath);
$path_parts = pathinfo($fullPath);
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Type: application/pdf");
header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . $fsize);
while(!feof($fd)) {
$buffer = fread($fd, 2048);
print($buffer);
flush();
}
fclose ($fd);
} else {
die("File does not exist. Make sure you specified correct file name.");
}
exit;
?>
All works fine as long as the verification of '$_SESSION['Download-Authorized'] ist commented out.
When I check the session-variable $_SESSION['Download-Authorized'] is set
the download will fail.
What's wrong with my code?
Any help appreciated.
After adding session_start() to the beginning of download.php the script still does not work.
It appears to be the case that the Session-ID as well as the Session-Name changes when "download.php" is called. Additionally $_SESSION['Downlad-Autorized'] is reset.
Your initial script stores the flag in a session explicitely renamed (session_name("My-Download");), but the download script uses the default session name (no session_name()).
Therefore your download script starts with another (possibly empty) session.
I am new to PHP and trying my hands into it. I am creating a file and writing back to it. Creating a file in some path and writing to it, works fine for me. But when i try to download the same file from the same path, its not getting downloaded instead I'm getting empty file.
header('Content-type: text/xml');
header("Content-Disposition: attachment; filename=".'check.xml');
header("Content-Length: " . filesize('./download/'.$_SESSION['user_name'].'/check.xml'));
readfile('download/'.$_SESSION['user_name'].'/check.xml');
exit;
Hi, Thanks for everyone. But I saw very unusual thing. When i downloaded the file, I didn't got the full file.
Why this case
Try removing ./ from the start of the filepath, like follows:
header('Content-type: text/xml');
header("Content-Disposition: attachment; filename=".'check.xml');
header("Content-Length: " . filesize('download/'.$_SESSION['user_name'].'/check.xml'));
readfile('download/'.$_SESSION['user_name'].'/check.xml');
exit;
With Linux file systems, ./ means the root, so that's the equivalent of / and ../ means the directory above the current directory. It's best to use absolute file paths, but simply removing the ./ should suffice.
You will also need to flush the write buffers of PHP using flush()
Here is a good working function to download a file
Here is a version adapted from that page:
public static function downloadFile($fileName) {
$filePath = $fileName;
$size = filesize($filePath);
// Taken from http://w-shadow.com/blog/2007/08/12/how-to-force-file-download-with-php/
header("Content-type: text/plain");
header("Content-Disposition: attachment; filename=\"$fileName\"");
header("Content-Transfer-Encoding: binary");
header("Accept-Ranges: bytes");
// The three lines below basically make the download non-cacheable
header("Cache-control: private");
header("Pragma: private");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Content-Length: " . $size);
if ($file = fopen($filePath, "r")) {
$buffer = fread($file, $size); // this only works for small files!
print $buffer;
flush();
fclose($file);
}
}
I have to show a download link on my site linking it to a file hosted on another domain. I am using the following approach.
1) Pick up the actual URL from the database
$fileDownloadLink = "http://whatever.com/thefile.docx";
2) Encode the url and pass it as parameter to download.php
$shortUrl = base64_encode($fileDownloadLink);
Download Please
3) Download.php decodes the passed string and try reading the file.
<?php
$str = $_GET["session"];
$path = base64_decode($str);
$mm_type="application/octet-stream";
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Type: " . $mm_type);
header("Content-Length: " .(string)(filesize($path)) );
header('Content-Disposition: attachment; filename="'.basename($path).'"');
header("Content-Transfer-Encoding: binary\n");
readfile($path);
exit();
?>
But I am getting this error from download.php
Not Acceptable!
An appropriate representation of the requested resource could not be
found on this server. This error was generated by Mod_Security.
Please help.
You may just redirect in download.php;
$str = #$_GET["session"];
$path = base64_decode($shortUrl );
header("Location: $path");
exit();
If I goto http://site.com/uploads/file.pdf I can retrieve a file.
However, if I have a script such as:
<?php
ini_set('display_errors',1);
error_reporting(E_ALL|E_STRICT);
//require global definitions
require_once("includes/globals.php");
//validate the user before continuing
isValidUser();
$subTitle = "Attachment";
$attachmentPath = "/var/www/html/DEVELOPMENT/serviceNow/selfService/uploads/";
if(isset($_GET['id']) and !empty($_GET['id'])){
//first lookup attachment meta information
$a = new Attachment();
$attachment = $a->get($_GET['id']);
//filename will be original file name with user name.n prepended
$fileName = $attachmentPath.$_SESSION['nameN'].'-'.$attachment->file_name;
//instantiate new attachmentDownload and query for attachment chunks
$a = new AttachmentDownload();
$chunks= $a->getRecords(array('sys_attachment'=>$_GET['id'], '__order_by'=>'position'));
$fh = fopen($fileName.'.gz','w');
// read and base64 encode file contents
foreach($chunks as $chunk){
fwrite($fh, base64_decode($chunk->data));
}
fclose($fh);
//open up filename for writing
$fh = fopen($fileName,'w');
//open up filename.gz for extraction
$zd = gzopen($fileName.'.gz', "r");
//iterate over file and write contents
while (!feof($zd)) {
fwrite($fh, gzread($zd, 60*57));
}
fclose($fh);
gzclose($zd);
unlink($fileName.'.gz');
$info = pathinfo($fileName);
header('Content-Description: File Transfer');
header('Content-Type: '.Mimetypes::get($info['extension']));
header('Content-Disposition: attachment; filename=' . basename($fileName));
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($fileName));
ob_clean();
flush();
readfile($fileName);
exit();
}else{
header("location: ".$links['status']."?".urlencode("item=incident&action=view&status=-1&place=".$links['home']));
}
?>
This results in sending me the file, but when I open it I receive an error saying:
"File type plain text document (text/plain) is not supported"
First off, I'd start by checking the HTTP headers. You can do this in Firefox easily using the "Live HTTP headers" extension; not sure about equivalents in other browsers offhand. This will let you verify if the header is actually getting set to "application/pdf" and whether your other headers are getting set as well.
If none of the headers are getting set, you might be inadvertently sending output before the calls to header(). Is there any whitespace before the <?php tag?
Are you sure application/pdf is the header your browser is actually seeing?
You can check that out with various HTTP dev tools, for instance HTTP Client for the Mac or Firebug for Firefox.
I use this one and it works.
if(file_exists($file_serverfullpath))
{
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private", false);
//sending download file
header("Content-Type: application/octet-stream"); //application/octet-stream is more generic it works because in now days browsers are able to detect file anyway
header("Content-Disposition: attachment; filename=\"" . basename($file_serverfullpath) . "\""); //ok
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($file_serverfullpath)); //ok
readfile($file_serverfullpath);
}
Try prepending "error_reporting(0);". I found this in the comments at http://php.net/readfile (where you took this example from).
Another thing that could be a problem is your file size. There have been issues reported in the past about PHP5 (we're talking 2005 here, so i hope this is fixed by now) having trouble reading files >2MB. If your file size exceeds this you may want to verify that it reads the whole file.