I am using Martin Barker's code/answer from ( PHP to protect PDF and DOC ) almost verbatum, only difference is the file I am protecting is in my user folder above the public_html folder
Folder structure
/users/websupport
/public_html
File to download is at:
/users/websupport/FileToDownload.pdf
The download.php file is at
/public_html/download.php
but Firefox tells me it cannot find the file at Firefox can't find the file at download.php.
I have verified that the file is there via ftp.
If placing the file outside the webroot do I need to add something to the sites .htaccess ? Just not sure where I am going wrong with this. Below is the code within download.php
//check users is loged in and valid for download if not redirect them out
// YOU NEED TO ADD CODE HERE FOR THAT CHECK
// array of support file types for download script and there mimetype
$mimeTypes = array(
'doc' => 'application/msword',
'pdf' => 'application/pdf',
);
// set the file here (best of using a $_GET[])
$file = "../users/websupport/2011cv.pdf";
// gets the extension of the file to be loaded for searching array above
$ext = explode('.', $file);
$ext = end($ext);
// gets the file name to send to the browser to force download of file
$fileName = explode("/", $file);
$fileName = end($fileName);
// opens the file for reading and sends headers to browser
$fp = fopen($file,"r") ;
header("Content-Type: ".$mimeTypes[$ext]);
header('Content-Disposition: attachment; filename="'.$fileName.'"');
// reads file and send the raw code to browser
while (! feof($fp)) {
$buff = fread($fp,4096);
echo $buff;
}
// closes file after whe have finished reading it
fclose($fp);
Make sure the user your php script runs as has read access to that directory.
On php embedded in apache on most debian derivatives, the user will be 'www-data'.
I had the same issue recently where readfile() and fpassthru() just would not work on my server.
What I ended up doing was creating symlinks for the files as needed and passing those to the user. You can learn how to create symlinks here.
I used
exec("ln -s source_file_full_path full_path_to_fake_file");
if you wanted your user to have a link like 'http://somesite.com/folder/fake_file.pdf' then the full path would be to where 'folder' lives on your server and you would include 'fake_file.pdf' in your fake file path.
then to expire the links I made another call to find all of the symlinks with a creation date older than x minutes. You can see how to do that in this answer. (That could be a cron job to ensure they expire on time.)
Related
I want to upload an mp3 file and add it into a directory on my server. I am executing the php code from the server directory I want to add the file to. This is what I have so far:
$dir=basename(dirname(__FILE__));
$folder = dirname(dirname($_SERVER['SCRIPT_NAME']));
$file_name = $_FILES['upload']['name'];
//remember to remove this line
$file_name = "test.mp3";
$add_file[0] = "<a
href='//mydomain.com$folder/$dir/$file_name'>$file_name</a>";
$path = "https://nerjabible.com$folder/$dir/";
so I have $add_file[0] and I have the $path to append to. I have tried put and write append, but they all seem to work by opening a file, I am already in the directory, I just want to append my linked file to the existing links in the directory.
The mp3 is in a directory on my PC as a hyperlink playable file and I am using a file upload script to obtain the file which ends up in $file_name but as a non linked file name, so i want to append this into the same directory the script is running from, but as a linked file.
printscreen of the local and remote directories
I'm trying to save a txt file in my pc locally with php, but not in the download folder. I need to add in different folder.
Here is my code
$txt = "$dirname/Contact.txt";
$fh = fopen($txt, 'w+');
exit();
fwrite($fh,$txt);
close($fh);
You can use $_SERVER variable to specify your path
$myTxt = $_SERVER['DOCUMENT_ROOT'] . "you/path/directory"
But remember that the path first is in your project, you may go out with "../"
And your exit(); command, this kills your code. Put this at the end of the file. It will never reaches close($fh);
Maybe only fixing this exit(); will solve your problem.
Trying to update a file file.xml, which is with folders dirA/dirB/dirC/file.xml where dirA is the current working dir. The file file.xml exists and has write permissions.
Using the following code works in local but on server it created a file by name "dirA\dirB\dirC\file.xml" outside dirA and saves into it
$file = fopen("dirA\dirB\dirC\file.xml", "w+")
fputs($file, $xmlFile);
fclose($file);
Any idea why?
Maybe because you are running another environment on your server?
Windows and Linux are a little bit itchy on their folders.
You may also check if you have to use backslashes or not!
Probably you also have to quote them:
$file = fopen("dirA\/dirB\/dirC\/file.xml", "w+");
I am having some trouble providing the directory path in tempnam();. When i use tempnam('', 'xyz'); , the file is getting stored in tmp directory. But i need to store the file in a specific directory permanently. I am using CodeIgniter. I want to save the files in folder docs which is located in the same directory as application and system. What location should I give in tempnam();? UPDATE: I tried providing with location path ie tempnam($_SERVER['DOCUMENT_ROOT'].'/exotel/docs' , 'xyz'); but still the file is saved in tmp folder
RTLM: http://www.php.net/manual/en/function.tempnam.php
As per the above docs, if the specified directory does not exist, tempnam() may use the system temp dir. You're specifying an empty string directory (''), which will not exist, so PHP is free to use whatever directory it wants.
Try
$temp = tempnam('/path/to/where/you/want/the/file', 'xyz');
instead.
see documentation for tempnam here. First parameter is a directory.
Example from docs:
<?php
$tmpfname = tempnam("/tmp", "FOO");
$handle = fopen($tmpfname, "w");
fwrite($handle, "writing to tempfile");
fclose($handle);
// do here something
unlink($tmpfname);
?>
I have downloaded and added this very simple, one file, php web file explorer system(called Indexer) to my XAMPP server.
My XAMMP server is on my C: drive, but I want Indexer to display a directory on my G: drive. But when I change (what I think are) the right configuration variables, it doesn't work properly.
Here is the code I think is to do with the problem:
// configuration
$Root = realpath("G:/test");
$AllowDownload = TRUE;
$WebServerPath = dirname("G:/test");
and later on in the code...
elseif ($AllowDownload) {
echo "".$item["name"]."";
}
This is what happens: The script does correctly display the contents of the "test" directory on the G: drive, but when I click the filename, to download/view the file, the link is broken because the php constructs the link wrong (I suppose).
The link looks like this: http://localhostg//[name of file].
Would you know how to solve this problem?
This script works perfectly if I change the configuration variables so it displays the contents of a relative subdirectory. And it also says $Root variable can be located outside the webserver root.
Also, even though clicking the link doesn't work, right-clicking and selecting "Save Target As" allows me to save/download the file.
(Feel free to ask if you need more information) :)
Your web server can not see the files outside the DocRoot, so it can not serve the files via the browser with direct links. You need to print their contents into the browser with readfile() with the headers properly set.
To make this work, you need to change the configuration in indexer.php:
// this way it works with accentuated letters in Windows
$Root = utf8_decode("G:\test"); // define the directory the index should be created for (can also be located outside the webserver root)
$AllowDownload = TRUE; // enclose file items with the anchor-tag (only makes sense when the files are in the webserver root)
// you need to place download.php in the same directory as indexer.php
$WebServerPath = dirname($_SERVER['SCRIPT_NAME']) . "/download.php?path="; // path where the indexed files can be accessed via a http URL (only required when $AllowDownload is TRUE)
And you have to place a new file called download.php in the same directory as indexer.php, with this content:
<?php
// it must be the same as in indexer.php
$Root = utf8_decode("G:\test");
function checkFileIsInsideRootDirectory($path, $root_directory) {
$realpath = realpath($path);
if (!file_exists($realpath))
die("File is not readable: " . $path);
// detects insecure path with for example /../ in it
if (strpos($realpath, $root_directory) === false || strpos($realpath, $root_directory) > 0)
die("Download from outside of the specified root directory is not allowed!");
}
function forceDownload($path) {
$realpath = realpath($path);
if (!is_readable($realpath))
die("File is not readable: " . $path);
$savename = (basename($path));
header("Pragmaes: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private", false);
header("Content-type: application/force-download");
header("Content-Transfer-Encoding: Binary");
header("Content-length: " . filesize($path));
header("Content-disposition: attachment; filename=\"$savename\"");
readfile("$path");
exit;
}
if (!isset($_GET['path']))
die("Path not specified!");
$fullPath = $Root . $_GET['path'];
checkFileIsInsideRootDirectory($fullPath, $Root);
forceDownload($fullPath);
You have to change your apache configuration. The problem is not the php script, the problem is the webserver (which is not able to serve files outside web root, unless you configure it to).
Try something like this in your apache configuration:
Alias /testalias "G:/test"
<Directory "G:/test">
Options Indexes FollowSymLinks MultiViews ExecCGI
AllowOverride All
Order allow,deny
Allow from all
</Directory>
This tells Apache to serve files from G:/test when you access http://localhost/testalias
Then change your script configuration like that:
$WebServerPath = dirname("testalias");
and it should work!
Let's take a look at that script:
$Root = realpath("."); // define the directory the index should be created for (can also be located outside the webserver root)
$AllowDownload = TRUE; // enclose file items with the anchor-tag (only makes sense when the files are in the webserver root)
$WebServerPath = dirname(getenv("SCRIPT_NAME")); // path where the indexed files can be accessed via a http URL (only required when $AllowDownload is TRUE)
Notice "only makes sense when the files are in the webserver root" and "path where the indexed files can be accessed via a http URL". Which indicates that this script was not designed to be able to download files that are outside the web server root dir.
However, you could modify this script to be able to do that in the way that styu has noted in his answer. You could then send your changes to the author of the script.
BTW, I tested this on my own server.