SitePoint Sponsor

User Tag List

Results 1 to 8 of 8
  1. #1
    SitePoint Evangelist hessodreamy's Avatar
    Join Date
    Apr 2005
    Location
    uk
    Posts
    522
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)

    detecting path to root vs include path

    What's the best way to determine the path to the document root and thereafter to a relevant include file?

    In the past I've used a function which looks at certain variables in the $_SERVER array and works out the path. However this falls down when running cron jobs or some debuggers because the $_SERVER array isn't available.

    I was just looking at setting the include path in the ini file, but this seems like it would be fairly slow and inefficient to rely on. ie looking for the file at this location, then that location etc. Seems like it would be slower than just saying where the file is.

    The third option I can think of is to manually set a variable containing the file path to the document root. This has portability issues (not major, I know).

    For added complication there are occasions where I call an include file from another include file (maybe this is a bad practice, but this is the code i've inherited), so I need to know the path from the original file (hence the __FILE__ constant is not good as it gives the location of the currectly included file).

    So what's the best way to do it?

  2. #2
    PHP Brainiac dg_den_golotyuk's Avatar
    Join Date
    Jul 2006
    Location
    Kiev, Ukraine
    Posts
    335
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    dirname(__FILE__);
    DG [Den Golotyuk], Lead Developer
    Chestnut Software
    Avoid web outsourcing scams!
    Click here
    for a free downloadable report

  3. #3
    SitePoint Evangelist hessodreamy's Avatar
    Join Date
    Apr 2005
    Location
    uk
    Posts
    522
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    yeah that does seem an easy method, but that gives the path to the currently included file. Can I get the path for the main executing file? And without using the $_SERVER variables?

  4. #4
    SitePoint Evangelist hessodreamy's Avatar
    Join Date
    Apr 2005
    Location
    uk
    Posts
    522
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    Thinking about it further, what would be very useful is finding the path to root, for php use, and also for use with html references (javascript files, images, css files etc) which can be used from any file (ie from within includes, and includes within includes - hence precluding use of the __FILE__ constant), at any level, including cron jobs (ie precluding use of $_SERVER variables). Using absolute paths isn't great, as you'll also need to worry about whether you're currently using a secure connection.

    I've written a function using the getcwd() function (which I hadn't seen before), and hard coding the document root.
    PHP Code:
    function pathToRoot()
    {
        
    $sep DIRECTORY_SEPARATOR;
        
    $my_docroot "D:".$sep."web";
        
    $cwd getcwd();
        
    $path_from_root=str_replace($my_docroot""$cwd);
        
    $levels count(explode($sep,$path_from_root));
        
    $path_to_root str_repeat("../"$levels -1);
        
        return 
    $path_to_root;

    That looks like it'll work great.
    However...
    I'd really like to have the document root in another file, preferably above the document root itself, so I don't accidentally overwrite the settings on the server with the path on my machine. But to call that file, I'd need to use this function, which needs to know the root. I'm in a confused state again. I really don't want to use any hard coding.

    Is there a better way?

  5. #5
    SitePoint Wizard silver trophy
    Join Date
    Mar 2006
    Posts
    6,132
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    like said above, dirname(__FILE__);

    define a constant or a variable to hold the value.

    define it in the currently executing file.
    now all your included scripts can use the value.

  6. #6
    SitePoint Evangelist hessodreamy's Avatar
    Join Date
    Apr 2005
    Location
    uk
    Posts
    522
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    Copying and pasting a line of code into every main executing file seems a tad going against decent software practices. I could put it in an include... oh wait, that won't work, as that'll give me the directory of the included file.

    Don't get me wrong, I know I'm coming across as the guy that rubbishes eveyone's suggestions and doesn't have any of his own. I'm just a bit exasperated that php doesn't seem to have simple solution to a simple and, I would presume, common problem.

    hmmm...

  7. #7
    SitePoint Evangelist hessodreamy's Avatar
    Join Date
    Apr 2005
    Location
    uk
    Posts
    522
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    So the $_SERVER['PHP_SELF'] value is perfectly good for working out the path, except that it's not available in cron.
    I've managed to work around this by setting a DOC_ROOT value in the cron environment, which then becomes accessable to php through the $_SERVER array.
    I've included in my function a check to see if PHP_SELF is available and, if not, assume that the file is running under cron and the DOC_ROOT is available, then compare getcwd() with the DOC_ROOT and hence find the path to the document root (which will be the same as the http root)
    Here's the function:
    PHP Code:
    function pathToRoot()
    {
        if(! empty(
    $_SERVER['PHP_SELF']))
        {
            
    $this_page $_SERVER['PHP_SELF'];
            
    $levels_above substr_count($this_page,"/")-1;
        }
        else 
    //for cron jobs
        
    {
              
    $sep DIRECTORY_SEPARATOR;
            
    $my_docroot $_SERVER['DOC_ROOT'];//this is set in the cron environment
            
    $cwd getcwd();
            
    $path_from_root=str_replace($my_docroot""$cwd);
            
    $levels_above count(explode($sep,$path_from_root)) -;
        }    
        
    $path_to_root str_repeat("../"$levels_above);
        return 
    $path_to_root;

    By jove, I do think I've sorted it. Still miffed that it should be so tricky.

  8. #8
    SitePoint Evangelist hessodreamy's Avatar
    Join Date
    Apr 2005
    Location
    uk
    Posts
    522
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    UPDATE:
    I've re-thought this, and it needn't be so hard, in fact the problem needn't really exist at all.

    The problem can be mostly solved by 2 points of general good practice:

    1. setting the include path(s) in php.ini, so that you can include a file without knowing your current location. Includes can then be called just by their name (or path relative to the include path in the ini file). So by setting the include path to <docroot>/includes, in your scripts <docroot>/includes/dbconnection.php becomes just dbconnection.php and <docroot>/includes/accounting/calc.php becomes accounting/calc.php
    2. Use paths relative to the document root for urls (links, images, scripts etc) (eg. /images/image1.jpg or /products/product.php) where necessary

    This covers most usages, including cron jobs and, other command line scripting (where the $_SERVER variables and many other apache specific variables are not available).

    The only situation left to resolve is where you need an actual (absolute or relative) file path, for working with files (getting the dimensions of an image, for example).

    I've modified my previous function because you really don't need to handle cron jobs separately. Just set the DOCUMENT_ROOT attribute in your cron environment (the same way you would the MAILTO attribute) and it because available in the $_SERVER vars. (This would probably rule out other command line scripts, but I don't really use them)
    Code:
    function pathToRoot()
    {
    	$my_docroot = strtolower((str_replace("\\","/",$_SERVER['DOCUMENT_ROOT']) ));
    	$cwd = strtolower(str_replace("\\","/",getcwd() ));
    	$path_from_root=str_replace($my_docroot, "", $cwd);
    	$levels_above = count(explode("/",$path_from_root)) -1 ;
    
    	$path_to_root = str_repeat("../", $levels_above);
    	return $path_to_root;
    }
    I've replaced windows backslashes with forward slashes, and made all paths lowercase, for better platform consistency.

    Thought this might be handy to anyone else who was having the same headaches I was.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •