I have a pretty stable development machine set up running Apache and using virtual hosts to keep my projects separate, and running a dyndns.org service which I use to access them. Each VHost directive typically looks like this:
<VirtualHost *:80>
ServerName [my_internal_subdomain].[my_dyndns_name].dyndns.org
ServerAlias home
DocumentRoot "D:/webserver/[projectDirectory]/httpdocs"
php_admin_value open_basedir "c:/WINDOWS/TEMP;D:/webserver/[projectDirectory]/"
ErrorLog "D:/webserver/[projectDirectory]/logs/error.log"
TransferLog "D:/webserver/[projectDirectory]/logs/access.log"
</VirtualHost>
Obviously [projectDirectory], [my_internal_subdomain] and [my_dyndns_name] are all values I know/change for each directive, just no need to post them here :)
One thing has always confounded me however, in PHP, if I want to require a file from say /includes/, I would expect to use:
require("/includes/myfile.php");
Except doing so throws an open_basedir restriction error - because "/" is trying to go, presumably to the root of D:/ - whereas I would like each virtual host to recognise that the value of DocumentRoot is in fact where I would like PHP to go if I call a file by "/".
This is how my production server seems to work, and its a bit of a pain having to code everything to work out what the relative path to /includes/ is for the benefit of my dev machine.
I expect this is a fairly simple/obvious directive I'm missing but I can't find it. Can anyone help?
Do you mean this?
require($_SERVER['DOCUMENT_ROOT'] . '/includes/myfile.php');
require paths takes filesystem paths so "/" will always be the root of the filesystem OR paths that relate to your include_path setting. You can change your includes slightly and set the include path like this to get around it:
ini_set('include_path', ini_get('include_path') . PATH_SEPARATOR . 'D:/.../httpdocs');
require('includes/myfile.php');
This will work because it will find the includes folder in your include_path.
PHP by itself has no real concept of a DocumentRoot for its file-related functions. It seems only the file system of the server. The whole DocumentRoot business is something applied at the webserver layer.
If you want to use require('/....') in your code, you'd need to use mod_chroot (or mod_security's chroot functionality), so you can "jail" each vhost into its own directory tree, and make the / directory be whatever you want for each one.
However, chrooting has its own problems - it would lock off the rest of the file system. If your script exec()'s something externally, or connects to MySQL, or does anything on the filesystem, you'd need to have copies of those executables, .so libraries, MySQL socket file, etc... within the jail.
In linux it's more common to have a 'chrooted' environment then in windows. You may determine your root by setting a configuration directive from a file in your root and get the directory name like this
$dirname = dirname(__FILE__);
// or however you wish to arrange your affairs.
$myConfigObject->set('root',$dirname);
Edit: This approach does not nescesairly use the document root, however I find that in many cases I will have multiple instances of the same project, and that most of my php files will be outside the document root for security reasons.
It will be something along the lines of this:
/home/dir (project root
/home/dir/stable (project instance root)
/home/dir/dev (project instance root2)
/home/dir/stable/lib (php files)
/home/dir/stable/web (webroot)
Related
I'm using a new server host and $_SERVER["DOCUMENT_ROOT"] is not working because returns a different path than the real one.
Example, I added includes/inc.php to the public_html folder on the server and used this code:
include_once($_SERVER["DOCUMENT_ROOT"] . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'inc.php');
This is the result:
Warning: include_once(/var/www/html/includes/inc.php): failed to open stream: No such file or directory in /home/tom_server/public_html/index.php on line 4
$_SERVER["DOCUMENT_ROOT"] is returning something unexpected. If I use dirname(__FILE__) it returns the right path:
/home/tom_server/public_html/includes/inc.php
But dirname(__FILE__) is not a useful solution as I need main root folder for relative paths. Is this a server configuration issue?
/home/<username>/public_html is the default user's web content directory used by apache if this feature is enabled.
When activated, the usual intended use of such personal directories is to store some static pages (cv, personal page in the company/institution...) and small dev/tests for easy access without having to configure anything. I used them a lot for students when I worked in a university a very long while ago so they could store and share their assignments.
When this feature is enabled, the pages in personal directories are served by the default webserver/virtual host, for which the document root is configured to /var/www/html by default on most linux distributions.
If you want to have a document root starting at the root of your php application, you can:
Fast and easy but ugly: move your application files to /var/www/html
Single user/app solution: modify the default webserver to point to your app (in place or in a new folder).
Prefered: use a dedicated folder for your app and configure a new Virtual Host in apache
If you do not have access to your server configuration and can only publish your files in your current user web directory, well... I have a bad news: you will not be able to use DOCUMENT_ROOT anymore in this context.
Details for configuring apache are beyond the scope of your question and probably belong to an other stackexchange site.
/ in the beginning of a link to get to the root folder doesn't work in php include.
for example "/example/example.php"
What is the solution?
I'm assuming by root folder you mean your web document root, rather than filesystem root.
To that end, you can either
add the web root folder to the include path, and include('example/example.php')
or you can include($_SERVER['DOCUMENT_ROOT'].'/example/example.php')
I had this issue too. Paul Dixon's answer is correct, but maybe this will help you understand why:
The issue here is that PHP is a server side language. Where pure HTML documents can access files based on the root url you set up on the server (ie. to access an image from any sub-directory you're on you would use /images/example.jpg to go from the top directory down), PHP actually accesses the server root when you use include (/images/example.jpg)
The site structure that you have set up actually lies within a file system in the Apache Server. My site root looks something like this, starting from the server root and going down:
/home2/siteuserftp/public_html/test/
"test" represents your site root
So to answer your question why your PHP include isn't getting the result you want (it is working exactly as it should) is because you're asking the PHP code to try and find your file at the server root, when it is actually located at the HTML root of your site which would look something like the above.
Your file would be based on the site root of "test/" and would look something like this:
/home2/siteuserftp/public_html/test/about/index.php
The answer Paul Dixon provided:
include($_SERVER['DOCUMENT_ROOT'].'/example/example.php')
is exactly what will fix your problem (don't worry about trying to find the document root to replace 'DOCUMENT_ROOT', PHP will do it for you. Just make sure you have 'DOCUMENT_ROOT' literally in there)
EDIT:
More information DOCUMENT_ROOT and other PHP SERVER variables can be found here
include() (and many other functions like require(), fopen(), etc) all work off the local filesystem, not the web root.
So, when you do something like this
include( "/example/example.php" );
You're trying to include from the root of your *nix machine.
And while there are a multitude of ways to approach what you're doing, Paul Dixon's suggestions are probably your best bets.
Every web server has a public_html folder, in which you usually keep your files etc. By using /, you will not get to public_html, instead you direct towards the main (unaccesible) root. So, use $_SERVER['DOCUMENT_ROOT']."/your/locati.on" instead
I solved this on a machine running Windows and IIS with the following:
<?php
$docroot = 'http://www.example.com/';
include ($docroot.'inc-header.php');
?>
If you're on a local dev machine, you can force your domain to point to localhost by adding the following in C:\Windows\System32\drivers\etc\hosts
127.0.0.1 www.example.com
Also, you'll need to enable allow_url_include in php.ini like so
allow_url_include = On
For me, the following trick worked.
I'm using Windows with IIS, so DOCROOT is C:\Inetpub\wwwroot.
do subst of C:\Inetpub\wwwroot to a drive. Let it be W: (WEB contents).
subst W: C:\Inetpub\wwwroot
edit php.ini this way: append W:\ to include_path, change doc_root to W:\
include_path = ".;c:\php\active\includes;W:\"
doc_root = W:\
put subst command into CMD file within Startup folder to make mapping automatically.
Now, both versions allowed:
include '/common/common.inc'; // access to mapped W: root
include 'common/common.inc'; // access to W: within include_path
some versions of PHP may have the delimiter at the end of document root while others may not. As a practical matter you may want to use:
$r = trim(filter_input(INPUT_SERVER, 'DOCUMENT_ROOT', FILTER_SANITIZE_STRING));
if (substr($r, 0, 1) == '/')
{
define("PATCH_SEPARATOR", "/");
}
else
{
define("PATCH_SEPARATOR", "\\");
}
if (substr($r, -1) == PATCH_SEPARATOR)
{
include_once ($r . 'example/example.php');
}
else
{
include_once ($r . PATCH_SEPARATOR . 'example/example.php');
}
maybe it's a bit unconventional
If I have a case like
/var/www/namedir/ <= root
/var/www/namedir/example/example.php <= file to include
-- directory when i need the include --
/var/www/namedir/dir1/page.php
/var/www/namedir/dir1/dirA/page.php
/var/www/namedir/dir1/dirB/page.php
the solution that I use is simple.
get the path before the "Dir1"
something like this
include (substr(dirname(__FILE__),0,strpos(dirname(__FILE__), '/dir1'))."/example/example.php");
I found it usefull id i need to rename the main subdir
for example from
/var/www/namesite/internalDirA/dirToInclude/example.php
/var/www/namesite/internalDirA/dir1/dirA/example.php
/var/www/namesite/internalDirA/dir1/dirB/example.php
TO
/var/www/namesite/dirReserved/dirToInclude/example.php
/var/www/namesite/dirReserved/dir1/dirA/example.php
/var/www/namesite/dirReserved/dir1/dirB/example.php
This answer is not really for the root directory, but one workaround is to use ../ to jump to the parent directory.Of course, you need to know the file structure for this approach though.
For example, you could use:
include('../parent.php');
include('../../grand_parent.php');
I am writing an HTML/CSS/JS project on my localhost.
The project root is found at http://localhost/projects/project1/.
I want to know if it is possible to make the HTML files treat my project
root as its' base URL so that referencing the same javascript/css files
doesn't depend on the path of the HTML file(unless I reference relative to
current directory).
Here is my project structure:
projects
project1
index.html
pages (directory)
page1.html
page2.html
apps(directory)
app1(directory)
index.html
style.css
app.js
deps(directory)
jquery.js
As you can see, to refer to jquery.js inside my /projects/project1/index.html,
I have to write:
<script src="deps/jquery.js"></script>
To refer to jquery.js inside /projects/project1/pages/index1.html,
I have to write
<script src="../deps/jquery.js"></script>
To refer to jquery.js inside http://localhost/projects/project1/apps/app1/index.html,
I have to write
<script src="../../jquery.js"></script>
At which point I am not sure I wrote the correct number of ../s and can easily
cause errors.
Worse, If i reorder my directories around or rename them, it means I have to deal with
rewriting the paths again, which can be very daunting.
I have thought of various ways to address them none of which are appealing(although option 3 comes close).
Thoughts/Attempts:
I tried playing with .htaccess RewriteEngine/RewriteBase but nothing worked.
I could just create a new server for each project as NodeJS makes it really easy to do so.
This way, each server has the directory as its' static path and is '/'.
The problem with this approach is that this managing
many servers up at once on different ports which can be confusing.
I could set an absolute path variable in .htaccess via
SetEnv PROJECT_PATH /projects/project1/
However doing this means I have to open .htaccess each time I move the folder
or rename it and change the PROJECT_PATH. This may seem simple but if you
give the project to somebody else and they don't know how .htaccess works,
it is very painful to explain how to find this path, and how to change it,
and even more problematic if the .htaccess is longer than one line.
Ideally, I want this SetEnv to figure out the folder it is inside by itself,
but I don't know how to accomplish this. This also has a problem that the pathing becomes dependent on the PHP preprocessing which makes it painful to move to another server that does not have .htaccess or PHP such as NodeJS(which can still invoke php but even then it needs to deal with .htaccess).
I want to know if it is possible to either
Make .htaccess file create an environment variable containing deduced path
of this particular .htaccess file so that php files inside this directory can
do pathing relative to $_ENV{PROJECT_ROOT}. This way if the project is moved or shared, it will still work without needing to modify .htaccess.
Make .htaccess to force HTML files contained in the same or lower directories that all "/" references treat this directory as the root.
Or if there are other things to address this issue that I have not thought of.
Thanks ahead of time.
Dmitry, you can try this:
1) In your file httpd.conf, add the following line at the end:
Redirect permanent /deps http://localhost/projects/project1/deps/
2) Restart apache service
3) Refresh your index page(/projects/project1/pages/index1.html)
I have used something like this:
<html>
<head>
<script src="/deps/jquery.min.js"></script>
</head>
</html>
<?php
echo "welcome to index"
?>
How do I access a directory outside of my document root?
This explain how to give users access to a directory that is outside of your directory root on Windows.
Assuming that your directory is located at C:/www/newfolder/ then you would create the following in your httpd.conf file.
Alias /newfolder/ "C:/www/newfolder/"
<Directory "C:/www/newfolder">
Options Indexes MultiViews
AllowOverride AuthConfig
Order allow,deny
Allow from all
</Directory>
Now, when a user goes to www.domain.com/newfolder/ then they see the folder that is outside your document root and it appears in the browser to be a directory contained below the document root..
One thing to consider is that if you have virtualhosts, then an alias works for every virtualhost, so try to use uncommon names for your alias.
Hope this helps
I have a php applicaiton and i'm planning to keep critical settings in a .ini file. However, i think that file can be accessed from over the web, so where is a "standard place" for it to be placed?
You can store it above the document/web root or specifically block access to it. For example, a common structure for PHP applications is:
application/
public/
Where public is the web root - so I usually store application configuration in application/config where I know it can't be accessed.
An alternative would be to block it using Apache:
<!-- Block access to all .ini files -->
<Files ~ "\.ini">
Order deny,allow
Deny from all
</Files>
The "standard place" is anywhere not affected by the directory root of the apache. For example you can place it under /home/someuser/, or somewhere else.
Place the .ini file outside the web root or protect it with .htaccess if you really want to keep it under the web root.
It can be accessed if you place your INI file in your webroot/docroot.
Making sure the file is not accessible via the docroot is the first step.
I would use a database to be honest.
However, if you really want to use a flat file (e.g. .ini), you can place it in a directory, and use .htaccess to stop people from accessing it via their browser. That way, you can still access the file via php file functions.
To do this, make a file called .htaccess in the folder you want to protect (e.g. ini/)
Then, in this file put:
deny from all
The folder is now not accessible by going to the url in the browser.
Place the configuration in a directory that isn't readable by the webserver, yet is readable for the application. Generally, you have a specific directory that's readable by the webserver, such as "web", "www", "public" or "public_html". Make sure you put it in the directory below that one.
That way, your application can read the file:
$cfg = parse_ini_file(
realpath( dirname( __FILE__ ) . '/../' ) . '/config.php'
);
Your webserver doesn't know how to reach it though, so it's secure.
a good example is Zend FW or any other php frameworks. directory structue is:
application/config/config.ini
library/Zend/
public/index.php
where public is accesible from web
/ in the beginning of a link to get to the root folder doesn't work in php include.
for example "/example/example.php"
What is the solution?
I'm assuming by root folder you mean your web document root, rather than filesystem root.
To that end, you can either
add the web root folder to the include path, and include('example/example.php')
or you can include($_SERVER['DOCUMENT_ROOT'].'/example/example.php')
I had this issue too. Paul Dixon's answer is correct, but maybe this will help you understand why:
The issue here is that PHP is a server side language. Where pure HTML documents can access files based on the root url you set up on the server (ie. to access an image from any sub-directory you're on you would use /images/example.jpg to go from the top directory down), PHP actually accesses the server root when you use include (/images/example.jpg)
The site structure that you have set up actually lies within a file system in the Apache Server. My site root looks something like this, starting from the server root and going down:
/home2/siteuserftp/public_html/test/
"test" represents your site root
So to answer your question why your PHP include isn't getting the result you want (it is working exactly as it should) is because you're asking the PHP code to try and find your file at the server root, when it is actually located at the HTML root of your site which would look something like the above.
Your file would be based on the site root of "test/" and would look something like this:
/home2/siteuserftp/public_html/test/about/index.php
The answer Paul Dixon provided:
include($_SERVER['DOCUMENT_ROOT'].'/example/example.php')
is exactly what will fix your problem (don't worry about trying to find the document root to replace 'DOCUMENT_ROOT', PHP will do it for you. Just make sure you have 'DOCUMENT_ROOT' literally in there)
EDIT:
More information DOCUMENT_ROOT and other PHP SERVER variables can be found here
include() (and many other functions like require(), fopen(), etc) all work off the local filesystem, not the web root.
So, when you do something like this
include( "/example/example.php" );
You're trying to include from the root of your *nix machine.
And while there are a multitude of ways to approach what you're doing, Paul Dixon's suggestions are probably your best bets.
Every web server has a public_html folder, in which you usually keep your files etc. By using /, you will not get to public_html, instead you direct towards the main (unaccesible) root. So, use $_SERVER['DOCUMENT_ROOT']."/your/locati.on" instead
I solved this on a machine running Windows and IIS with the following:
<?php
$docroot = 'http://www.example.com/';
include ($docroot.'inc-header.php');
?>
If you're on a local dev machine, you can force your domain to point to localhost by adding the following in C:\Windows\System32\drivers\etc\hosts
127.0.0.1 www.example.com
Also, you'll need to enable allow_url_include in php.ini like so
allow_url_include = On
For me, the following trick worked.
I'm using Windows with IIS, so DOCROOT is C:\Inetpub\wwwroot.
do subst of C:\Inetpub\wwwroot to a drive. Let it be W: (WEB contents).
subst W: C:\Inetpub\wwwroot
edit php.ini this way: append W:\ to include_path, change doc_root to W:\
include_path = ".;c:\php\active\includes;W:\"
doc_root = W:\
put subst command into CMD file within Startup folder to make mapping automatically.
Now, both versions allowed:
include '/common/common.inc'; // access to mapped W: root
include 'common/common.inc'; // access to W: within include_path
some versions of PHP may have the delimiter at the end of document root while others may not. As a practical matter you may want to use:
$r = trim(filter_input(INPUT_SERVER, 'DOCUMENT_ROOT', FILTER_SANITIZE_STRING));
if (substr($r, 0, 1) == '/')
{
define("PATCH_SEPARATOR", "/");
}
else
{
define("PATCH_SEPARATOR", "\\");
}
if (substr($r, -1) == PATCH_SEPARATOR)
{
include_once ($r . 'example/example.php');
}
else
{
include_once ($r . PATCH_SEPARATOR . 'example/example.php');
}
maybe it's a bit unconventional
If I have a case like
/var/www/namedir/ <= root
/var/www/namedir/example/example.php <= file to include
-- directory when i need the include --
/var/www/namedir/dir1/page.php
/var/www/namedir/dir1/dirA/page.php
/var/www/namedir/dir1/dirB/page.php
the solution that I use is simple.
get the path before the "Dir1"
something like this
include (substr(dirname(__FILE__),0,strpos(dirname(__FILE__), '/dir1'))."/example/example.php");
I found it usefull id i need to rename the main subdir
for example from
/var/www/namesite/internalDirA/dirToInclude/example.php
/var/www/namesite/internalDirA/dir1/dirA/example.php
/var/www/namesite/internalDirA/dir1/dirB/example.php
TO
/var/www/namesite/dirReserved/dirToInclude/example.php
/var/www/namesite/dirReserved/dir1/dirA/example.php
/var/www/namesite/dirReserved/dir1/dirB/example.php
This answer is not really for the root directory, but one workaround is to use ../ to jump to the parent directory.Of course, you need to know the file structure for this approach though.
For example, you could use:
include('../parent.php');
include('../../grand_parent.php');