include within include, using a relatve path
include within include, using a relatve path
am 28.01.2008 02:36:08 von Sebastian Lisken
Hi,
I have noticed something in PHP's include mechanism that surprised me.
If you include a script that itself contains an include command using
a relative path, that path is interpreted from the position of the
'outermost' script, not that of the script in which the relative path
appears. Here is a simplified example, with error checking, php tags
etc. left out for clarity. I'll use the extension ".inc.php" to mark
scripts that are intended to be included.
Let x be the full path to some point in the file system, and imagine
that the server has been configured so that x/htdocs is reachable through
some URL, but x itself is not.
Say there is an include script doing database access and some more setup,
like this:
*** x/htdocs/setup.inc.php ***
require "../include/secrets.inc.php";
$link = mysql_connect($server, $user, $password);
mysql_select_db($database, $link);
/*
imagine more code that reads initial stuff from the database
*/
***
Because this script does more than just connect (and other included
scripts might also connect and do other "extra" things), the actual
secrets are taken out and appear just once, like this:
*** x/include/secrets.inc.php ***
global $server, $user, $password, $database;
$server = "...";
$user = "...";
$password = "...";
$database = "...";
***
x/include can not be reached by an URL, so we have implemented a common
piece of security advice.
Now of course we have scripts in, say, x/htdocs/script1.php, that use
this setup through the statement
*** x/htdocs/script1.php (extract) ***
include "setup.inc.php";
***
This all looks fine, but it fails if x/htdocs/setup.inc.php is included
from files at other depths in the file tree under x/htdocs. If I have
a script x/htdocs/subdir/script2.php that says:
*** x/htdocs/subdir/script2.php (extract) ***
include "../setup.inc.php";
***
then the relative path "../include/secrets.inc.php" in setup.inc.php
causes PHP to look for "x/htdocs/include/secrets.inc.php", as reported
by an error caused by the "require" statement. It must therefore be the
case that the relative path after "require" is interpreted relative to
x/htdocs/subdir/script2.php - my expectation would have been that it's
relative to x/htdocs/setup.inc.php, i.e. to the script in which the
"require" statement actually appears.
I do have a solution that I'm not fully comfortable with: after the
"require" within x/htdocs/setup.inc.php I put an expression using regular
expression replacement and __FILE__, similar to this:
*** x/htdocs/setup.inc.php (extract) ***
require ereg_replace('/htdocs/.*', '/include/secrets.php', __FILE__);
***
ereg is used instead of preg here because preg would include the first
slash as a delimiter of the regular expression, not a required character.
You will know that __FILE__ behaves somewhat similarly to the
"include" mechanism: it evaluates to the path of the 'outermost' script,
i.e. "x/htdocs/script1.php" or "x/htdocs/subdir/script2.php". One reason
for my discomfort is that I can't exactly know where within __FILE__
the string "/htdocs/" appears. It will appear at least once because my
scripts are under x/htdocs - but what I call "x" will be a longer path
that might in theory contain "/htdocs/" somewhere earlier.
I'd be happier with an expression that, if used in x/htdocs/setup.inc.php,
would evaluate exactly to "x/htdocs/setup.inc.php" - some special variable
whose meaning would be 'the script file this line actually appears in'. I
haven't found such a variable. Have I missed something?
I could use $_SERVER["DOCUMENT_ROOT"] to construct an absolute path
within the server's file system, but for that I'd need to know where
x is in relation to the document root. (It might not even be under that
root if aliases are used.) So I'd prefer to get by without that knowledge.
Of course I could get rid of my excessively complicated setup and
avoid the 'double include' structure. I'm considering that anyway, but
I'd expect others to stumble over the same expectation of how 'double
includes' work, so I'd be curious about other solutions.
So I'm wondering: have other more experienced PHP programmers come across
the same problem, and is there a 'canonical' solution?
Thanks for reading all this, and for your replies.
Sebastian Lisken
Re: include within include, using a relatve path
am 28.01.2008 02:53:17 von Jerry Stuckle
Sebastian Lisken wrote:
> Hi,
>
>
> So I'm wondering: have other more experienced PHP programmers come across
> the same problem, and is there a 'canonical' solution?
>
> Thanks for reading all this, and for your replies.
>
> Sebastian Lisken
>
>
It's very easy. Make every include absolute. You can find the path to
the server's document root via $_SERVER['DOCUMENT_ROOT']. Reference
every include from there and you'll be in much better shape.
--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
jstucklex@attglobal.net
==================
Re: include within include, using a relatve path
am 28.01.2008 03:00:36 von Sebastian Lisken
Jerry Stuckle wrote:
> It's very easy. Make every include absolute. You can find the path to
> the server's document root via $_SERVER['DOCUMENT_ROOT']. Reference
> every include from there and you'll be in much better shape.
Thanks Jerry, I know this would be a solution. I did consider this near
the end of my (admittedly very long) post and explained why I regard
such a solution less than ideal. Could you think of another one not
using the document root?
Sebastian Lisken
Re: include within include, using a relatve path
am 28.01.2008 03:15:18 von Jerry Stuckle
Sebastian Lisken wrote:
> Jerry Stuckle wrote:
>> It's very easy. Make every include absolute. You can find the path to
>> the server's document root via $_SERVER['DOCUMENT_ROOT']. Reference
>> every include from there and you'll be in much better shape.
>
> Thanks Jerry, I know this would be a solution. I did consider this near
> the end of my (admittedly very long) post and explained why I regard
> such a solution less than ideal. Could you think of another one not
> using the document root?
>
> Sebastian Lisken
>
>
Yes, I read that. But there isn't a better one.
You should *always* know where a file is relative to DOCUMENT_ROOT. And
it can be above the directory.
--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
jstucklex@attglobal.net
==================
Re: include within include, using a relatve path
am 28.01.2008 15:03:11 von Logos
On Jan 27, 6:36 pm, Sebastian Lisken
deletethis.de> wrote:
> Hi,
>
> I have noticed something in PHP's include mechanism that surprised me.
> If you include a script that itself contains an include command using
> a relative path, that path is interpreted from the position of the
> 'outermost' script, not that of the script in which the relative path
> appears. Here is a simplified example, with error checking, php tags
> etc. left out for clarity. I'll use the extension ".inc.php" to mark
> scripts that are intended to be included.
>
> Let x be the full path to some point in the file system, and imagine
> that the server has been configured so that x/htdocs is reachable through
> some URL, but x itself is not.
>
> Say there is an include script doing database access and some more setup,
> like this:
>
> *** x/htdocs/setup.inc.php ***
>
> require "../include/secrets.inc.php";
> $link = mysql_connect($server, $user, $password);
> mysql_select_db($database, $link);
> /*
> imagine more code that reads initial stuff from the database
> */
>
> ***
>
> Because this script does more than just connect (and other included
> scripts might also connect and do other "extra" things), the actual
> secrets are taken out and appear just once, like this:
>
> *** x/include/secrets.inc.php ***
>
> global $server, $user, $password, $database;
>
> $server = "...";
> $user = "...";
> $password = "...";
> $database = "...";
>
> ***
>
> x/include can not be reached by an URL, so we have implemented a common
> piece of security advice.
>
> Now of course we have scripts in, say, x/htdocs/script1.php, that use
> this setup through the statement
>
> *** x/htdocs/script1.php (extract) ***
>
> include "setup.inc.php";
>
> ***
>
> This all looks fine, but it fails if x/htdocs/setup.inc.php is included
> from files at other depths in the file tree under x/htdocs. If I have
> a script x/htdocs/subdir/script2.php that says:
>
> *** x/htdocs/subdir/script2.php (extract) ***
>
> include "../setup.inc.php";
>
> ***
>
> then the relative path "../include/secrets.inc.php" in setup.inc.php
> causes PHP to look for "x/htdocs/include/secrets.inc.php", as reported
> by an error caused by the "require" statement. It must therefore be the
> case that the relative path after "require" is interpreted relative to
> x/htdocs/subdir/script2.php - my expectation would have been that it's
> relative to x/htdocs/setup.inc.php, i.e. to the script in which the
> "require" statement actually appears.
>
> I do have a solution that I'm not fully comfortable with: after the
> "require" within x/htdocs/setup.inc.php I put an expression using regular
> expression replacement and __FILE__, similar to this:
>
> *** x/htdocs/setup.inc.php (extract) ***
>
> require ereg_replace('/htdocs/.*', '/include/secrets.php', __FILE__);
>
> ***
>
> ereg is used instead of preg here because preg would include the first
> slash as a delimiter of the regular expression, not a required character.
>
> You will know that __FILE__ behaves somewhat similarly to the
> "include" mechanism: it evaluates to the path of the 'outermost' script,
> i.e. "x/htdocs/script1.php" or "x/htdocs/subdir/script2.php". One reason
> for my discomfort is that I can't exactly know where within __FILE__
> the string "/htdocs/" appears. It will appear at least once because my
> scripts are under x/htdocs - but what I call "x" will be a longer path
> that might in theory contain "/htdocs/" somewhere earlier.
>
> I'd be happier with an expression that, if used in x/htdocs/setup.inc.php,
> would evaluate exactly to "x/htdocs/setup.inc.php" - some special variable
> whose meaning would be 'the script file this line actually appears in'. I
> haven't found such a variable. Have I missed something?
>
> I could use $_SERVER["DOCUMENT_ROOT"] to construct an absolute path
> within the server's file system, but for that I'd need to know where
> x is in relation to the document root. (It might not even be under that
> root if aliases are used.) So I'd prefer to get by without that knowledge.
>
> Of course I could get rid of my excessively complicated setup and
> avoid the 'double include' structure. I'm considering that anyway, but
> I'd expect others to stumble over the same expectation of how 'double
> includes' work, so I'd be curious about other solutions.
>
> So I'm wondering: have other more experienced PHP programmers come across
> the same problem, and is there a 'canonical' solution?
>
> Thanks for reading all this, and for your replies.
>
> Sebastian Lisken
Hey Sebastian! I was bit by this too, just a few weeks ago. Sadly,
it doesn't seem like there is a much better solution than the absolute
path that's been mentioned.