4

So basically, I'm writing a framework, and as part of it features, it's supposed to provide a set of well-established URIs/paths to the end-developer.

Some two of these paths make use of $_SERVER['DOCUMENT_ROOT']:

/**
 * Absolute filesystem path to web root install (aka docroot).
 * @example "C:/wamp/www" OR "/home/visitgoz/public_html/"
 */
CFG::set('ABS_WWW',
    str_replace(
        $tmpseps,
        DIRECTORY_SEPARATOR,
        truepath($_SERVER['DOCUMENT_ROOT']).'/'
    )
);

/**
 * K2F path relative to web root.
 * @example /K2F/
 */
CFG::set('REL_K2F',
    str_replace(
        array('//','\\'),
        '/',
        str_replace(CFG::get('ABS_WWW'),'/',CFG::get('ABS_K2F'))
    )
);

The code has been fine-tuned to work on both Linux and Windows. Apparently, it works most of the time on Linux, quite seamless in fact on VPSes.

However, as of late, I tried it on an HG Reseller Account (shared hosting) and it all broke up. I've printed out data inside $_SERVER on the problematic machine:

Array
(
**  [DOCUMENT_ROOT] => /usr/local/apache/htdocs
    [GATEWAY_INTERFACE] => CGI/1.1
    [HTTP_ACCEPT] => text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8
    [HTTP_ACCEPT_CHARSET] => ISO-8859-1,utf-8;q=0.7,*;q=0.7
    [HTTP_ACCEPT_ENCODING] => gzip,deflate
    [HTTP_ACCEPT_LANGUAGE] => en-gb,en;q=0.5
    [HTTP_CONNECTION] => keep-alive
    [HTTP_COOKIE] => <snip>
    [HTTP_HOST] => <snip>
    [HTTP_KEEP_ALIVE] => 115
    [HTTP_USER_AGENT] => <snip>
    [PATH] => /bin:/usr/bin
    [QUERY_STRING] => 
    [REDIRECT_STATUS] => 200
    [REMOTE_ADDR] => <snip>
    [REMOTE_PORT] => 49262
    [REQUEST_METHOD] => GET
    [REQUEST_URI] => /~sitename/
**  [SCRIPT_FILENAME] => /home/sitename/public_html/index.php
    [SCRIPT_NAME] => /~sitename/index.php
    [SERVER_ADDR] => <snip>
    [SERVER_ADMIN] => <snip>
    [SERVER_NAME] => <snip>
    [SERVER_PORT] => 80
    [SERVER_PROTOCOL] => HTTP/1.1
    [SERVER_SIGNATURE] => 
Apache mod_fcgid/2.3.5 mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635 Server at <snip> Port 80


    [SERVER_SOFTWARE] => Apache mod_fcgid/2.3.5 mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635
    [UNIQUE_ID] => TVox-Eo1Z8IAAG1kAh4AAAEZ
    [PHP_SELF] => /~sitename/index.php
    [REQUEST_TIME] => 1297756668
    [argv] => Array
        (
        )

    [argc] => 0
)

And my machine:

Array
(
    [HTTP_AUTHORIZATION] => 
    [HTTP_HOST] => <snip>
    [HTTP_USER_AGENT] => <snip>
    [HTTP_ACCEPT] => text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8
    [HTTP_ACCEPT_LANGUAGE] => en-gb,en;q=0.5
    [HTTP_ACCEPT_ENCODING] => gzip,deflate
    [HTTP_ACCEPT_CHARSET] => ISO-8859-1,utf-8;q=0.7,*;q=0.7
    [HTTP_KEEP_ALIVE] => 115
    [HTTP_CONNECTION] => keep-alive
    [PATH] => <snip>
    [SystemRoot] => C:\Windows
    [COMSPEC] => C:\Windows\system32\cmd.exe
    [PATHEXT] => .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
    [WINDIR] => C:\Windows
    [SERVER_SIGNATURE] => 
    [SERVER_SOFTWARE] => Apache/2.2.11 (Win32) PHP/5.3.1
    [SERVER_NAME] => <snip>
    [SERVER_ADDR] => <snip>
    [SERVER_PORT] => 80
    [REMOTE_ADDR] => <snip>
**  [DOCUMENT_ROOT] => C:/wamp/www/
    [SERVER_ADMIN] => admin@localhost
**  [SCRIPT_FILENAME] => C:/wamp/www/K2F/cms/cms-joomla-1.5/index.php
    [REMOTE_PORT] => 49947
    [GATEWAY_INTERFACE] => CGI/1.1
    [SERVER_PROTOCOL] => HTTP/1.1
    [REQUEST_METHOD] => GET
    [QUERY_STRING] => 
    [REQUEST_URI] => /K2F/cms/cms-joomla-1.5/
    [SCRIPT_NAME] => /K2F/cms/cms-joomla-1.5/index.php
    [PHP_SELF] => /K2F/cms/cms-joomla-1.5/index.php
    [REQUEST_TIME] => 1297758541
)

** Parts you ought to read out, should explain my problem perfectly.

So basically, the expected DOCUMENT_ROOT is /home/sitename/public_html/, but instead I got /usr/local/apache/htdocs.

Oh, and sorry if I've been a bit too verbose ;)

Edit:

getcwd() => /home/visitgoz/public_html

__FILE__ => /home/visitgoz/public_html/K2F/config.php

Christian
  • 27,509
  • 17
  • 111
  • 155
  • I don't get it ... what do mean with "expected"? Why do you expect "/home/sitename/public_html/"? I guess you are confused that you get "/usr/local/apache/htdocs" as your document root on a shared host, but I guess it's just a faked directory, b/c they don't want you to have more information about their directory structure than necessary. – Raffael Feb 15 '11 at 08:41
  • Conspiracy aside ;), I can find the structure perfectly using `__FILE__` (for example). That is where I got the expected path from. – Christian Feb 15 '11 at 08:43
  • 1
    Hmmm, a lot of scripts will probably break because of this. Have you tried contacting HG and notifying them of the problem? – wimvds Feb 15 '11 at 09:17
  • It's a problem my script should take care of. – Christian Feb 15 '11 at 09:23

3 Answers3

5

Those (cheap) Mass-Hosters quite often do some Apache URL-Rewriting tricks - which basically make THEIR Life easier, since there's only ONE Apache V-Host, with ONE Document-Root for all shared Websites.

To find the "real" document Root in this case:

  • Compare DOCUMENT_ROOT to SCRIPT_FILENAME from left to right. If there are no matching Path-Components, it's such a shared host.
  • If it's such a shared host, remove REQUEST_URI from SCRIPT_NAME => "index.php" in your example.
  • Then: remove the result from above from the end of SCRIPT_FILENAME => your DOCUMENT_ROOT (/home/sitename/public_html/)

Edit (Christian Sciberras): This is the right answer, but it lacks code, which I had to write anyway, so here goes:

if(strpos($_SERVER['SCRIPT_FILENAME'],$_SERVER['DOCUMENT_ROOT'])===false){
    // how it works on reseller accounts...
    $path=str_common(getcwd(),__FILE__);
}else{
    // how it normally works...
    $path=truepath($_SERVER['DOCUMENT_ROOT']).'/';
}
Christian
  • 27,509
  • 17
  • 111
  • 155
Laph
  • 311
  • 2
  • 6
  • When removing `REQUEST_URI` from `SCRIPT_NAME`, don't forget that `REQUEST_URI` may be "/", "/index.php", "/?page=2" etc. And in case of rewritten URLs (`mod_rewrite`?) `REQUEST_URI` has nothing to do with `SCRIPT_NAME`. – binaryLV Feb 15 '11 at 09:24
3

I would use dirname(__FILE__), dirname(dirname(__FILE__) . '/../..') or something like that to create constant DOCUMENT_ROOT which would then be used instead of $_SERVER['DOCUMENT_ROOT'].

binaryLV
  • 9,002
  • 2
  • 40
  • 42
  • That only works in case if hard-coded paths, something I was trying to avoid in the first place. – Christian Feb 15 '11 at 09:26
  • What's the point in using `$_SERVER['DOCUMENT_ROOT']` then? I.e., why is invalid value of `$_SERVER['DOCUMENT_ROOT']` a problem for you? For making paths, it does not really matter if you use server-provided `$_SERVER['DOCUMENT_ROOT']` or "script-calculated" constant `DOCUMENT_ROOT`. – binaryLV Feb 15 '11 at 09:31
  • You used back double-dots to calibrate the path correctly, I cannot know how far I'm inside the web directory: `__FILE__` could be `/www/aaa/index.php` as well as `/www/aaa/bbb/index.php`. – Christian Feb 15 '11 at 09:55
  • True. But if index.php (main entry file for the whole page/system) resides in `/www/aaa/bbb`, I would expect `DOCUMENT_ROOT` to point to `/www/aaa/bbb` rather than to some meaningless directory. – binaryLV Feb 15 '11 at 10:37
1

The document root is per virtual host. But using UserDir (e.g. ~sitename) tells the server to look elsewhere for the files to process. You will need to handle this difference if you want your script to work properly.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • How do I find that out? That is, I can know about this issue by making my script compare `DOCUMENT_ROOT` with `SCRIPT_FILENAME`, but how can I find the real `DOCUMENT_ROOT`? – Christian Feb 15 '11 at 08:36