[绝对原创]PHP中路径问题的解决方案

发表于:2007-05-25来源:作者:点击数: 标签:php绝对题的原创路径
[绝对原创] PHP 中路径问题的 解决方案 bylon .net pro 引言: 关于PERL与PHP中的包含路径一直是一个比较难解的问题,主要是与操作系统和WEB 服务器 有关,不可能非常智能化的解决这个路径问题。相对于PERL,PHP的路径好得多,解决起来也容易得多,因为PHP的

[绝对原创]PHP中路径问题的解决方案 by lon.netpro

引言:
关于PERL与PHP中的包含路径一直是一个比较难解的问题,主要是与操作系统和WEB服务器有关,不可能非常智能化的解决这个路径问题。相对于PERL,PHP的路径好得多,解决起来也容易得多,因为PHP的相对路径在PHP程序中的任何场合都可以使用,而不象PERL在某些语句中必须用绝对路径而导致移植的极其复杂。

基于此,在PHP中,我设计了一个绝对稳妥的解决方案,如下所述。

原则:
使用相对路径,但在相对路径中用绝对路径(有点绕,待会儿详解),一是可以保证可移植性,二是可以方便地修改,三是公式化且结构清晰明了,易于扩展。

步骤详解:
1、先确定好一个程序的根目录,注意是文件系统下的,不是WEB服务器下的虚拟目录,不过一般情况下该目录下的子目录的相对路径与URL下该目录的虚拟子目录是相同的。
2、在定义好的程序根目录下的每个子目录下(其实不一定是每个,根据需要)建立一个settings.php,里面定义一个变量或是常数(常数比较好,因为作用域比较大),如APPROOT,但这个APPROOT却不是绝对路径,而是该目录相对于你指定的程序根目录的相对路径。
3、在此目录下的所有程序入口文件(也即第一个包含其它文件的文件,或是允许直接在浏览器中浏览的文件)中第一句写上require_once('settings.php');,但要注意,所有被包含文件最好不要加此句——其实加上也可以,因为你可以在settings.php中写上 if(!defined(APPROOT)) define(APPROOT, '../..');这类的语句以防重定义。
4、如果你要包含其它文件,无论是直接还是间接地包含,都可以写成 include(APPROOT.$path);,这里$path为被包含文件相对于你所指定的程序根目录的绝对路径。

原理:
定下的程序根目录是相对路径,但具体的目录位置是相对于那个根目录的绝对路径,两者组合起来就是具体文件相对于程序根目录的相对路径了。例如目录c:\wwwroot\app为你指定的程序根目录,然后有这么两个文件c:\wwwroot\app\a\index.php和c:\wwwroot\app\b\inc.php。对子目录a来说,APPROOT是'..',而对程序根目录来说,inc.php的绝对路径是$path='/b/inc.php',两者组合为'../b/inc.php'。如果要在index.php中包含inc.php就要写成include('../b/inc.php');,而这个路径不就正好是刚才组合而成的APPROOT.$path吗?


结论:
经过以上处理,各个路径绝对整齐划一,唯一罗嗦一点的就是每个目录下要定义一下这个APPROOT,但每个目录下只需在本目录的settings.php中定义一次就足够了。如果你整个程序只有一个入口文件,如index.php,而其它文件全部都是直接或是间接地被包含进这个唯一的入口文件的话,就只需在index.php的所在目录下的settings.php中定义一次就OK了。如果有朋友做过Delphi的工程并对工程文件研究过的话,就会发现我刚才说的一个程序只有一个主入口文件的情况与Delphi的工程十分相似,因为Delphi除了一个主程序文件(dpr文件),其余的全部是单元文件或是资源文件,都不能独立执行。在PHP中,如果这种情况出现,只需定义一次APPROOT,并在主程序文件中第一句话写成require_once('settings.php');,而以后所有的包含全都可以用include(APPROOT.$path);,就保证不会有任何问题,除非你不会写这个“包含文件相对于程序根目录的绝对路径”$path。

这个方法我用了不止一次,收效很好。另外还可以参考JSP的WEB-INFO中路径的定义方式。

我这个是以不变应万变的公式化的方案,如果有朋友有更好的方案,欢迎提出讨论!如有不明白的也欢迎提出。

 tonera 回复于:2003-12-13 11:44:13
加精华啊!PHP版的精华总这么少?其实很多文章即使不加精华也应该保留啊。比如说前段时间的几个论题,都是大家的实际心得,不保留下来太可惜了。建议版主考虑一下,还可以提高老同志发贴的积极性嘛。 :D 

[b:afclearcase/" target="_blank" >cc144654]要是楼主再贴个实例就更好了。[/b:afcc144654]

 longnetpro 回复于:2003-12-13 12:43:45
我修改了一下原文,提供了一个简单的例子。不过各位最好自己去试试,我想我讲得还是比较清楚的,而且这样印象比较深刻,也比较容易发现其中的问题。

另外,它也不光只用于包含文件的路径,什么图片等的路径,原理都是一样的。

 麻辣 回复于:2003-12-13 23:22:47
perl的路径太复杂了,我可能要给你讲一火车

相对路径不可靠,比如当前目录打开一个文件

open "123.text";####在有的服务器下可以,有的不行,所以,相对路径不能用!

必须用变量控制

open "cgipath/123.text";####

这个$cgipath从哪里得到呢?

可以由安装的时候设定,这样不太方便,程序搬家需要从新安装,所以也可以环境变量里面去取,perl的当前脚本路径存储在环境变量中,但问题又来了。

不同的web服务器,这个路径存储在不同的环境变量中,非常复杂

所以,雷傲的程序每个脚本前面有个

BEGIN {
    $cgi_path = '.';
    $pgm      = $0;###这个是当前脚本名称
    $pgm =~ s/\\/\//g;
    $pgm =~ s/^.*\/([^\/]+)$/$1/g;
    unless ( -e $cgi_path . '/' . $pgm ) {
        foreach ( $0, $ENV{'SCRIPT_FILENAME'}, $ENV{'PATH_TRANSLATED'} ) {
            s!\\!/!g;
            s/^(.*)\/[^\/]+$/$1/g;
            if ( -e $_ . '/' . $pgm ) { $cgi_path = $_; last; }
        }
    }
    unshift( @INC, "$cgi_path/ccblib","$cgi_path" );
}

其中

$0, ###相对路径
$ENV{'SCRIPT_FILENAME'}, ###有可能存储绝对路径
$ENV{'PATH_TRANSLATED'}####有可能存储绝对路径
这三个变量,肯定有一个是对的,哪个对用哪个

路径识别问题是perl的最大不便,这也是perl的程序一换空间脚本就容易出错的一个主要原因,很多是路径问题没处理好,造成 use 或require找不到文件。

实际情况比上面还要复杂,再加上虚拟目录,更乱。。。我只是说了一部分

 longnetpro 回复于:2003-12-13 23:27:37
所以嘛,幸好是PHP,不是PERL。

 夜猫子 回复于:2003-12-14 00:14:23
python也有类似的问题,需要以sys.path.append的形式来加上模块的路径,但是已经比perl的方便许多。
还是php的require、include最方便。

 jhsea3do 回复于:2003-12-14 16:51:21
[code:1:7c6dedf8cf]
/*index.php*/
$webapp_home = "./";
$phpExt = "php";

/*path.inc.php*/
$webapp_path1 = "somewhere1/";
$webapp_path2 = "somewhere2/";

e.g. 

require($webapp_home . $webapp_path . $FileName . '.' . $phpExt);

......
[/code:1:7c6dedf8cf]

基本上大点的程序都是这么做的!

 夜猫子 回复于:2004-03-06 22:16:03
我现在完全使用longnetpro的方法了,非常好用,赞!其实和phpbb的那种每页声明$root_path差不多,但是更加的容易维护。

 dualface 回复于:2004-03-08 23:41:24
我也在最近的一个项目里用上了,非常方便的说!

 syshome 回复于:2004-04-21 00:36:51
反反复复看了若干次,今天终于有些懂了。
这的确是一个困惑人的问题。

原文转自:http://www.ltesting.net