php nginx X-Accel-Redirect headers - php

i have an issue regarding protecting folder with static files using nginx
so basically i have root folder on nginx setup to :
/home/rise/rises/wwwdir
and the secured folder is :
/home/rise/rises/videop
as we can see i moved that folder outside root folder to prevent/allow only specific to see under criteria
when i first made a search before posting i read some ideas that to access the videop folder outside the root , i need to create alias in nginx conf like this which i made
and access internal
location /videop {
root /home/rise/rises/;
internal;
}
however i have an issue on php side to load the video...
$aliasedFile = '/videop/5_.m3u8';
$filename = '5_.m3u8';
header("Content-Description: File Transfer");
header("Content-Type application/x-mpegURL ");
header('Content-Disposition: attachment; filename='.$filename.'');
header('X-Accel-Redirect: '. $aliasedFile);
readfile($aliasedFile);
i'm missing something ?

Your root directive has a trailing / which will be followed by the leading / of the URL, so use:
location /videop {
root /home/rise/rises;
internal;
}
Your PHP has a badly formed header, which should include a : after Content-Type.
The PHP should should not include a body. The readfile is wrong. The whole purpose of the PHP is to issue an internal redirect which is picked up by nginx. So the PHP should return headers only.

Related

Can't load CSS and images if localhost folder is located on another disk

First, please do not mark my question as a duplicate of the question by the link php read images outside localhost on another disk because after reading my question to the end you'll notice that my path to static files should be dynamic in my index.php file
I use the simplest PHP server on Windows starting it by a .VBS file with the CMD-command
php -S localhost:80
My .VBS file and index.php are located in a folder inside of the hard disk C and should be located there. So when I start the server, it uses the folder on disk C as the root localhost folder. But static files are and should be located on hard disk D.
I can successfully load static HTML files to the browser using the following PHP code in my index.php
<?php
$path = $_SERVER['REQUEST_URI'];
if($path == '/') {
$path = 'index';
}
$pathToStaticWebsite = 'D:/static_websites/website1/';
$page = file_get_contents($pathToStaticWebsite.$path.'.html');
echo $page;
?>
But HTML file has relative paths to CSS and images like src="images/..." and they are not being loaded. I've tried to add the line
$page = str_replace('images/','file:///'.$pathToStaticWebsite.'images/',$page);
before echoing the page in the index.php, but it doesn't work, as I see because the server doesn't handle such local paths
How to resolve the problem?
ps. I mean without using .htaccess with path to index.php inside of the website1 folder and bearing in mind that index.php as main app file may swicth us from website1 to website2, so the path to static website folder is dynamic within index.php
to have a system like you describe you will have to setup a webserver - php -S is intended to aid application development (where all files are stored within the given folder)
also it is not possible to request local files from http (http:// and file://)
As What I Understanded From Your Question
I hope That Can Help You I Use This To Locate The Project DIRECTORY And Get The System DIRECTORY_SEPARATOR
Because In Windows OS The DIRECTORY_SEPARATOR is \
And In The Mac OS And UNIX OS DIRECTORY_SEPARATOR is /
<?php
define('DS', DIRECTORY_SEPARATOR);
define('ROOT', dirname(__FILE__));
?>

Access a file which is located before / outside the server root directory?

I'm making an intranet for a post-sale customer service entreprise. Employee need to be able to upload img files to the intranet's server and i need to store them in a directory with is BEFORE www (the website's root directory).
Doing this using php is pretty easy but how to include these imgs on the website once they're uploaded ?
I tried this code
<img src="../img/img.png"/>
This is not working because i can't send a file if it is OUTSIDE the server's www directory ...
Is there any proper way to do that ?
Current treeview :
server root directory
|www
|(all server files)
|img
|(all img files)
(the server's index.php is located in www and the files are in img)
You cannot directly access any file outside your web directory. As your question includes the tag PHP as well, I assume you may want to use it.
What you can do is the following:
Inside your www directory, create a "image.php" file, with a similar content to:
<?php
header('Content-Type: image/png');
readfile("../img/" . $_GET['img']);
?>
And call your images with
<img src="image.php?img=myimage.png" />
Please be aware that your PHP file shouldn't be that simple :) As you may want to address multiple image formats (and providing the correct header for them), checking for malicious file path/inclusions (you don't want to use $_GET without validating/sanitizing the input), extra caching etc. etc. etc.
But this should give you an idea on how you can target your issue.
It depends on what you are trying to accomplish and how.
With "simple" html commands it is as you found out. You can't go to a directory outside of the www root.
(for xampp applications on C for exmple it is most of the time c:\xampp\htdocs).
If you are ok with using serverside commands to accomplish what you want to achieve then you could use php to do a workaround, by reading the appropriate files in via PHP.
For example if your file is named "myimg.gif" and lies in "c:\pics"
<img SRC="data:image/gif;base64,<?php echo base64_encode(file_get_contents("c:\pics\myimg.gif"));?>">
With that you are reading the contents of the file and writing it directly into the img tag.
Be aware that you need to change image/gif to what you really need there.
You can't directly access file outside/above your root directory (www or public_html).
You can create virtual directory in Apache server configuration. Google "apache virtual directory" for more information.
Virtual directory configuration example:
<IfModule alias_module>
Alias /uploaded_images/ "/home/someuser/somewhere"
<Directory "/home/someuser/somewhere">
Allow from all
</Directory>
</IfModule>
uploaded_images directory will be available from web like normal directory in www directory. You can copy files from there to another location (kind of buffering).
You can also open/copy that file by ftp from php level without changing anything in apache, but this may be really slow (use it only if you can't control apache config, virtual directory is much better).
php.net: FTP
I Agree with #kamil's idea about creating a virtual directory. However if you want to go the php route, I wrote some code that open's images in a directory before WWW and copies them to the www/images folder.
<?php
$imagepath = "../images/";
define('IMGPATH', realpath($imagepath).DIRECTORY_SEPARATOR);
$cachewwwimg = "images/";
$imagename = 'image.jpg';
copy(IMGPATH.$imagename, $cachewwwimg.$imagename)
?>
<img src="<?php echo $cacheimg.$imagename;?>"/>
I solved this by simply creating a symbolic link pointing to the global physical folder on my hosting. I didn't have root access, so I created a simple PHP file, calling it symbolic_link.php, that i put in the root of my website and that creates the symbolic link for me. Here it is:
<?php
$target = '/home/<user>/images/'; // hosting physical directory
$link = 'images'; // symbolic link inside root of web site
unlink($link);
symlink($target, $link);
After the creation of the symbolic link, I deleted the file.
This is the hosting directory structure:
/home/<user> // hosting root
|
+--/images // hosting global dir
| |
| +--/logo.png // global image
|
+--/www.website.com // hosting website dir
|
+--/images // symbolic link
Now you can use the image as if it were in your website folder:
<img src="https://www.website.com/images/logo.png" alt="...">

linking to files above the root PHP

I recently switched servers. From shared w/ control panel to a VPS
On my old server this PHP worked:
header("Content-disposition: attachment; filename= 'welcome.doc'");
header('Content-type: application/msword');
readfile("/home/abcme/aboveroot/admin/welcome.doc");
The same folder structure exists in the new serve. There is a folder above home named aboveroot and a folder in that called admin and a file in that called welcome.doc
I changed the /home/abcme so that "abcme" is the correct new accountname
Now I get an error saying the file cannot be found. Is there something that needs to be enabled in my server or what else might explain this?
Based on what you said the structure would be like so:
>aboveroot
-home
-admin
-welcome.doc
So your header would say (assuming that /aboveroot is your webroot, which doesn't seem the case given the name):
header("Content-disposition: attachment; filename= 'welcome.doc'");
header('Content-type: application/msword');
readfile("/aboveroot/admin/welcome.doc");

PHP display/download directory files outside the webserver root

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.

Why are CodeIgniter application files in the public_html folder?

Isn't having all of the files in public view a bad thing?
Surely things such as /system/application/config/database.php should not be publicly visible!
The developers of CodeIgniter, EllisLabs, have set up the framework in this way for ease of use. It means that people wishing to try out the framework don't have to fiddle with any permissions settings on their server.
Of course on a production server, you are absolutely right, putting your PHP files in the public HTML folder is not a good idea.
A better way to organise your folders would be:
root
code_igniter
application_folder
config
controllers
models
...
system_folder
public_html
css
js
images
index.php
.htaccess
The only other change to be made here would be to change line 26 of index.php to read:
$system_folder = "../../code_igniter/system-folder";
You can add the following rule to your .htaccess file to further protect the system and application directories from being viewed (sends a 403 Forbidden error):
# Protect application and system files from being viewed
RewriteRule ^(application|system) - [F,L]
With this structure:
/application
/system
/public
index.php
You can change in public/index.php these two settings and you are done
$application_folder = '../application';
$system_path = '../system';
Jon Winstanley's answer is perfect,
also don't forget to secure file uploads folder, if you have one. I did that by also moving it outside public root, and get the images using below code:
<?php
// $details = getimagesize($_GET["path"] . '/' . $_GET["image"]);
$details = getimagesize($_GET["path"] . strip_tags($_GET["image"]));
header ('Content-Type: ' . $details['mime']);
readfile($_GET["path"] . strip_tags($_GET["image"]));
exit;
?>
Accessing the files within /system/ from a browser will not reveal any sensitive information, because the PHP will be parsed and nothing is output from those files (CI system files may even check to see if a variable has been defined that indicates the file wasn't accessed directly).
That being said, however, you should probably install your entire system folder above web root anyway.
You can always place the system directory outside the public directory. Don't forget to update paths inside the the front controller (index.php).

Categories