I want to allow users to download pdf file from one of my folder. Is there any way i can hide the download path from the user when user "mouseover" to the file download icon ?
Suggest any method using PHP or javascript.
Point the browser at a PHP script instead, passing a key that represents the filename to download. Decode the key, and send the file via the PHP script.
At some point you will have to give the browser the real URI so it can fetch the file.
Trying to conceal it is pointless.
I don't believe this to be true. There's a simple way to protect the files on your server from unprivileged downloading using PHP's fpassthru. If you were to have a file called download.php, with the following contents:
<?php
/**
* Make sure the downloads are *not* in a publically accessible path, otherwise, people
* are still able to download the files directly.
*/
$filename = '/the/path/to/your/files/' . basename( $_GET['filename'] );
/**
* You can do a check here, to see if the user is logged in, for example, or if
* the current IP address has already downloaded it, the possibilities are endless.
*/
if( file_exists( $filename ) ) {
/**
* Send some headers indicating the filetype, and it's size. This works for PHP >= 5.3.
* If you're using PHP < 5.3, you might want to consider installing the Fileinfo PECL
* extension.
*/
$finfo = finfo_open( FILEINFO_MIME );
header( 'Content-Disposition: attachment; filename= ' . basename( $filename ) );
header( 'Content-Type: ' . finfo_file( $finfo, $filename );
header( 'Content-Length: ' . filesize( $filename ) );
header( 'Expires: 0' );
finfo_close( $finfo );
/**
* Now clear the buffer, read the file and output it to the browser.
*/
ob_clean( );
flush( );
readfile( $filename );
exit;
}
header( 'HTTP/1.1 404 Not Found' );
echo "<h1>File not found</h1>";
exit;
You can call download.php with ?filename=test.foo, and it will download /the/path/to/your/files/test.foo, which is not publicly accessible.
At some point you will have to give the browser the real URI so it can fetch the file. Trying to conceal it is pointless.
Set some sort of time limited credentials and authenticate before allowing access to the download if you want to limit who can access it.
Yes, you can use javascript to redirect the user when they click a link that leads to '#', e.g.
Secret File
However, this is pointless since it will always be possible to trace what file is being downloaded (by using an HTTP sniffer, for example, or other tools). Essentially, what you're asking for is impossible and unreasonable.
If you need to make sure that the file is accessed only by some people, make them log in and check the credentials before giving them the data. Hiding the path is not the way to go.
Before Passing FilePath it to download_file() fucntion. Append the path to file id. Like Below.
$FilePaths='../Uploaded Files/'.$FilePath;
download_file($FilePaths);
function download_file( $fullPath )
{
// Must be fresh start
if( headers_sent() )
die('Headers Sent');
// Required for some browsers
if(ini_get('zlib.output_compression'))
ini_set('zlib.output_compression', 'Off');
// File Exists?
if( file_exists($fullPath) ){
// Parse Info / Get Extension
$fsize = filesize($fullPath);
$path_parts = pathinfo($fullPath);
$ext = strtolower($path_parts["extension"]);
// Determine Content Type
switch ($ext) {
case "pdf": $ctype="application/pdf"; break;
case "exe": $ctype="application/octet-stream"; break;
case "zip": $ctype="application/zip"; break;
case "doc": $ctype="application/msword"; break;
case "xls": $ctype="application/vnd.ms-excel"; break;
case "ppt": $ctype="application/vnd.ms-powerpoint"; break;
case "gif": $ctype="image/gif"; break;
case "png": $ctype="image/png"; break;
case "jpeg":
case "jpg": $ctype="image/jpg"; break;
default: $ctype="application/force-download";
}
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false); // required for certain browsers
header("Content-Type: $ctype");
header("Content-Disposition: attachment; filename=\"".basename($fullPath)."\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".$fsize);
ob_clean();
flush();
readfile( $fullPath );
}
else
die('File Not Found');
}
Like other have pointed out, at some point, you have to reveal the URL but if all you want to do is hide it from the status bar, you can do this:
Description
Related
Hi I've been working on this for a while and seem to be getting no where so I hope someone can help me out, i've read multiple different stack-overflow answers and tried multiple different things and don't seem to be getting anywhere.
The Problem
I am working on a Wordpress plugin which on a page in the public side of the website displays multiple buttons on one page all of which are meant to trigger downloads of different files. I have tried to debug this myself and have checked that the url is getting selected correctly and is then being broken down correctly providing all the correct paths and filenames and file formats for each file. Having echoed out a lot of the variables checking there contents are correct (Commenting out the headers).
The following Italic text contains the original issue, However this is no longer the case, opening the pdf file in sublime text shows that the pdf is present. It seems to also contain a load of html before the pdf file (This is not present in my php but looks to be present by other php files and wordpress it's self) I have also edited the original code since thanks to #Marc B comment to add exit(); in after the readfile(); stopping any more html after the pdf data. All i need to know now is how can I delete all the code before the readfile(); in php, which I believe will then leave the download with purely just the pdf and will hopefully open correctly. The following line doesn't seem to be getting the file it's meant to download. I have commented out and written the result of the parsed_url variable next to it incase i'm passing the wrong thing to readfile.
readfile($parsed_url['localpath']); /* /var/www/web/wp-content/uploads/2016/10/pdfdownload.pdf */
Currently the code triggers a download to start and creates the attachment, it then downloads a file which although the name of which is the right name it contains the html of the current page instead of the data of the file it is downloading.
On the click of the button it adds the urlid into the url at the top and then on that being present the code then gets the id and finds the file url out of the url array to download.
Any help with this would be great heres my code.
The PHP Code
if(isset($_GET['urlid'])){
/*
// Code is a modified version from
author: pixeline
website: http://www.pixeline.be
last updated: 14 January 2009
*/
$urlid = $_GET['urlid'];
$filename = urldecode(urls_array[$urlid]); /* http://example.co.uk/wp-content/uploads/2016/10/pdfdownload.pdf */
// converting url to local path so Apache can find the file.
// force download:
// required for IE, otherwise Content-disposition is ignored
if (ini_get('zlib.output_compression'))
ini_set('zlib.output_compression', 'Off');
$parsed_url = parse_url($filename);
$fileinfo = pathinfo($filename);
$parsed_url['extension'] = $fileinfo['extension']; // .pdf
$parsed_url['filename'] = $fileinfo['basename']; // pdfdownload.pdf
$parsed_url['localpath'] = $_SERVER['DOCUMENT_ROOT'] . $parsed_url['path']; /* /var/www/web/wp-content/uploads/2016/10/pdfdownload.pdf */
// just in case there is a double slash created when joining document_root and path
$parsed_url['localpath'] = preg_replace('/\/\//', '/', $parsed_url['localpath']);
if (!is_readable($parsed_url['localpath'])) {
die('File not found: ' . $parsed_url['localpath']);
}
$allowed_ext = array('pdf', 'png', 'jpg', 'jpeg', 'zip', 'doc', 'xls', 'gif', 'exe', 'ppt');
if (!in_array($parsed_url['extension'], $allowed_ext)) {
die('This file type is forbidden.');
}
switch ($parsed_url['extension']) {
case "pdf": $ctype = "application/pdf";
break;
case "exe": $ctype = "application/octet-stream";
break;
case "zip": $ctype = "application/zip";
break;
case "doc": $ctype = "application/msword";
break;
case "xls": $ctype = "application/vnd.ms-excel";
break;
case "ppt": $ctype = "application/vnd.ms-powerpoint";
break;
case "gif": $ctype = "image/gif";
break;
case "png": $ctype = "image/png";
break;
case "jpeg":
case "jpg": $ctype = "image/jpg";
break;
default: $ctype = "application/force-download";
}
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private", false); // required for certain browsers
header("Content-Type: $ctype");
header("Content-Disposition: attachment; filename=\"" . $parsed_url['filename'] . "\";");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($parsed_url['localpath']));
flush();
readfile($parsed_url['localpath'] ); /* /var/www/web/wp-content/uploads/2016/10/pdfdownload.pdf */
exit();
}
?>
<a href="http://<?php print($_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']) ?>&urlid=<?php print($downloadablepdf->urlidentity1) ?>">
<button type="button" value="Download1" class="button button-blue" >Download pdf one</button>
</a>
<a href="http://<?php print($_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']) ?>&urlid=<?php print($downloadablepdf->urlidentity2) ?>">
<button type="button" value="Download2" class="button button-blue" >Download pdf two</button>
</a>
<a href="http://<?php print($_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']) ?>&urlid=<?php print($downloadablepdf->urlidentity3) ?>">
<button type="button" value="Download3" class="button button-blue" >Download pdf three</button>
</a>
Since you can't delete html that already exists in a php file. I created a separate php file to hold the php for downloading the files. Then back in the original file I changed the buttons to submit buttons and put them within a form with a post action to the new download.php file.
When a submit button is clicked it posts to the php file and triggers the download. This is the only way I could find to get rid of the html Wordpress was adding to the top of the page breaking the downloaded file.
Thanks everyone for you help this is now solved.
I'm looking to add a download image on click function for a website. I'm attempting to use PHP to do it as as far as I am aware, there is no way to do it in HTML without it linking to another blank page and then right click save as, which is not what I want.
I found this code on here and wish to adapt it, but I'm concerned of breaking it because my understanding of PHP is not vast. Also, I need to use this on multiple files, but the PHP I'm using suggests you can only use it in one file, meaning I may need numerous PHP files, one for each image download?
Anyway, I'm not sure, but I could do with some help adapting the code if anyone is able to assist me?
The images are in the following directory directly from the site:
/img/bkg/img1.jpg
This also follows into img2-5 also.
Anyway, here is the code used in the main file to show the image and link to the PHP file download:
<a href="download.php?file=path/<?=$row['img1.jpg']?>">
<img src="img/bkg/img1.jpg" alt="CWP - Wallpaper 1" width="1056" height="600"/>
</a>
Here is the code I need to adapt for these files and the correct directories:
<?php
$file = $_GET['file'];
download_file($file);
function download_file( $fullPath ){
// Must be fresh start
if( headers_sent() )
die('Headers Sent');
// Required for some browsers
if(ini_get('zlib.output_compression'))
ini_set('zlib.output_compression', 'Off');
// File Exists?
if( file_exists($fullPath) ){
// Parse Info / Get Extension
$fsize = filesize($fullPath);
$path_parts = pathinfo($fullPath);
$ext = strtolower($path_parts["extension"]);
// Determine Content Type
switch ($ext) {
case "pdf": $ctype="application/pdf"; break;
case "exe": $ctype="application/octet-stream"; break;
case "zip": $ctype="application/zip"; break;
case "doc": $ctype="application/msword"; break;
case "xls": $ctype="application/vnd.ms-excel"; break;
case "ppt": $ctype="application/vnd.ms-powerpoint"; break;
case "gif": $ctype="image/gif"; break;
case "png": $ctype="image/png"; break;
case "jpeg":
case "jpg": $ctype="image/jpg"; break;
default: $ctype="application/force-download";
}
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false); // required for certain browsers
header("Content-Type: $ctype");
header("Content-Disposition: attachment; filename=\"".basename($fullPath)."\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".$fsize);
ob_clean();
flush();
readfile( $fullPath );
} else
die('File Not Found');
}
?>
I am sorry if the above is a silly question, but I would rather seek help in this than break it over and over. I am unsure where I am replacing files and directories etc. etc. and I would like to get it right.
Any help is much appreciated.
Your script will handle multiple downloads on one page just fine, you can add as many:
<a href="download.php?file=path/<?=$row['img1.jpg']?>">
to the page as you like. Each time a link is clicked, the script will run and process the download according to the information you sent to it (file=path/<?=$row['img1.jpg']?> in the example).
However, this script has no input validation whatsoever so people can request system file by issuing requests like download.php?file=../../../etc/passwd.
To solve that I would get rid of the path in the query string (you can append that again in php, it's not anybody's business) and use something like a regular expression to check if the sent in variable contains illegal characters.
A simple example to illustrate:
if (preg_match('#[^\w.-]#', $_GET['file']))
{
// if $_GET['file'] contains anything that is not a word character, a dot or a -
die("invalid input");
}
else
{
$file = 'path/' . $_GET['file'];
// rest of your code
I would also remove the mime types you are not using, so only leave jpg or all image types.
So firstly i would like to tell that i am quite newbie in header usage and playing with output buffers. So im developing php portlet for liferay and i have some problem with file downloads. I tried to do it simply with 'a href' but problem is that file uploaded via php is unavailable till apache is refreshed so i tried another way with header() function.
So i will try to explain my problem. When i tried following code on simple php project it works fine :
<?php
$path = "/mysecretdir/upload/"; // change the path to fit your websites document structure
$fullPath = $path.$_GET['download_file'];
if ($fd = fopen ($fullPath, "r")) {
$fsize = filesize($fullPath);
$path_parts = pathinfo($fullPath);
$ext = strtolower($path_parts["extension"]);
switch($ext) {
case "pdf":
$ctype = "application/pdf";
break;
case "exe":
$ctype = "application/octet-stream";
break;
case "zip":
$ctype = "application/zip";
break;
case "doc":
$ctype = "application/msword";
break;
case "xls":
$ctype = "application/vnd.ms-excel";
break;
case "ppt":
$ctype = "application/vnd.ms-powerpoint";
break;
case "gif":
$ctype = "image/gif";
break;
case "png":
$ctype = "image/png";
break;
case "jpeg":
$ctype = "image/jpg";
break;
case "jpg":
$ctype = "image/jpg";
break;
case "mp3":
$ctype = "audio/mp3";
break;
case "wav":
$ctype = "audio/x-wav";
break;
case "wma":
$ctype = "audio/x-wav";
break;
case "mpeg":
$ctype = "video/mpeg";
break;
case "mpg":
$ctype = "video/mpeg";
break;
case "mpe":
$ctype = "video/mpeg";
break;
case "mov":
$ctype = "video/quicktime";
break;
case "avi":
$ctype = "video/x-msvideo";
break;
case "src":
$ctype = "plain/text";
break;
default:
$ctype = "application/force-download";
}
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: " . $ctype);
header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\"");
header("Content-Transfer-Encoding: binary");
//header("Content-length: $fsize");
header("Cache-control: public"); //use this to open files directly
while(!feof($fd)) {
echo fread($fd, 4096);
flush();
}
}
fclose ($fd);
?>
from index.php im calling it with href="download.php?download_file=/something/"
Ok but now the point. When i am using it in liferay portlet the file is weird. It puts whole generated HTML file in the created file. So its broken. I dunno why. I dont know if headers are sending some information from elsewhere and also dont know how to fix it.
I was searching for hours for some solution but dont know how to make somehow "session" for headers, because i think there is problem with them. Becasue without echo it prints only content of file and in other project - more simple php app not as a part of portal it works! but maybe i am wrong.
So please can someone help me? Any advise?
I can't help you on specific php-portlet problems (I never used Liferay with php) but it sounds like you get the whole page HTML generated "around" your downloaded file. This is what you get when you just render a portlet: A portlet is always embedded in a HTML page, thus you cannot provide specific headers on the HTTP level with the standard render output of a portlet.
What you want is the serveResource lifecycle phase of a portlet. This will allow you to serve content that is not part of the page, but you have full control over the download and HTTP headers. How to do that with php portlets, I'll have to leave to you.
Edit (additional information): As you asked in the comments, I found an older (might need to be adapted) Wiki article that talks about using state=exclusive to do the same trick - instead of the serveResource that I suggested above. I don't know if this is due to the age of the article or because PHP portlets don't support that lifecycle, but you might find something there and in the related&linked articles. Note: serveResource would - if I'm not mistaken - generate a p_p_lifecycle=2 parameter, while this example uses p_p_lifecycle=0 (render) and p_p_state=exclusive. Try if this fits your requirements
However, please consider Marc B's comment about your code being insecure and too hardcoded. There are better solutions for the underlying problem - e.g. Liferay provides the Document Library to up/download files out of the box. And that doesn't have these problems.
If you started your PHP file with a space or any other character, headers won't work and the display/download will fail. Make sure you don't have anything before the <?php tag.
Other than that, this should work (if you're not getting errors in the browser).
On the other hand, if you see the actual PHP code, your server does not support PHP.
The following script is what I usually use to push headers to the browser so that the dialog box appears for users to download a file.
However, in this case the file resides on a different server. I though this should make no difference but it does as when I execute this script with the URL of an externam MP3 file it gives me a "ERROR: File not found". However, this file exists, and I can get to it using the same URL I pass to this script.
Any ideas why? I would appreciate any help.
<?php session_start();
//below variable contains full path to external site where file resides
$filename = $_SESSION['$serverURL'].'audio/'.$_SESSION['fileName'].'.mp3';
//below variable contains a chosen filename of the file to be downloaded
$properFilename = $_GET['properFilename'].'.mp3';
// required for IE, otherwise Content-disposition is ignored
if(ini_get('zlib.output_compression'))
ini_set('zlib.output_compression', 'Off');
// addition by Jorg Weske
$file_extension = strtolower(substr(strrchr($filename,"."),1));
if( $filename == "" )
{
//echo "download file NOT SPECIFIED";
exit;
} elseif ( ! file_exists( $filename ) )
{
//echo "ERROR: File not found";
exit;
};
switch( $file_extension )
{
case "pdf": $ctype="application/pdf"; break;
case "exe": $ctype="application/octet-stream"; break;
case "zip": $ctype="application/zip"; break;
case "doc": $ctype="application/msword"; break;
case "xls": $ctype="application/vnd.ms-excel"; break;
case "ppt": $ctype="application/vnd.ms-powerpoint"; break;
case "gif": $ctype="image/gif"; break;
case "png": $ctype="image/png"; break;
case "jpeg":
case "jpg": $ctype="image/jpg"; break;
default: $ctype="application/force-download";
}
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false); // required for certain browsers
header("Content-Type: $ctype");
// change, added quotes to allow spaces in filenames, by Rajkumar Singh
header("Content-Disposition: attachment; filename=\"".basename($properFilename)."\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($filename));
readfile("$filename");
exit();
?>
Single-quotes strings are not parsed for variables, so $_SESSION['$serverURL'] is probably not going to work as you expect. I suspect you mean $_SESSION[$serverURL] or $_SESSION['serverURL'].
Also calling filesize() and then readfile() will probably result in your script making two HTTP requests to fetch the file from the other server (unless this gets cached somehow). You could do it in one HTTP request using cURL, which may be a better option. Here is a brief example, you should be able to adapt it to do what you want. You might also want to consider forwarding other headers such as the Content-Type header from the other server (if reliable) rather than re-generating them yourself.
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://example.com');
//set callbacks to receive headers and content
curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'on_receive_header');
curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'on_receive_content');
//send your other custom headers somewhere like here
if (false === curl_exec($ch)) {
//handle error better than this.
die(curl_error($ch));
}
function on_receive_header($ch, $string) {
//You could here forward the other headers received from your other server if you wanted
//for now we only want Content-Length
if (stripos($string, 'Content-Length') !== false) {
header($string);
}
//curl requires you to return the amount of data received
$length = strlen($string);
return $length;
}
function on_receive_content($ch, $string) {
echo $string;
//again return amount written
$length = strlen($string);
return $length;
}
I'm trying to display an image using a PHP script. Basically so the php script is passed on the full path to the image, and it then displays that image in the browser. I've checked to make sure the image exists, it is being read correctly, etc, however in the browser i just see the broken image box (e.g the small red cross in IE) if I go there.
My script sends out these headers:
<?php
header('Last-Modified: ' . gmdate('D, d M Y H:i:s T', filemtime($file)));
header('Content-Type: '.$mime);
header('Content-Length: '.filesize($file)."\n\n");
header('Etag: '.md5($file));
echo $file;
die;
$file contains something like '/var/www/htdocs/images/file.jpg' which works. the $mime is 'image/jpeg'.
I have also tried echoing file_get_contents($file) but it didn't work either.
What is the problem, any thoughts?
<?php
$filename = basename($file);
$file_extension = strtolower(substr(strrchr($filename,"."),1));
switch( $file_extension )
{
case "gif":
$ctype="image/gif";
break;
case "png":
$ctype="image/png";
break;
case "jpeg":
case "jpg":
$ctype="image/jpeg";
break;
default:
}
ob_clean(); // add this before header
header('Content-type: ' . $ctype);
readFile($file);
?>
Some time extra space may be produced in any other file.So those extra spaces can be removed by calling ob_clean() before header() is called.
Striving for simplicity...
<?php
header('Content-type:' . mime_content_type($file));
readfile($file);
should function as expected.
I found the answer, i had some extra whitespace after the ?> tag which was causing the header to not work. grrrrrrr