PHP路径问题及其解决方法(包含路径问题的解决方案/目录规划)

PHP路径问题及其解决方法(包含路径问题的解决方案/目录规划)
初学PHP的时候,我们经常被PHP的绝对路径和相对路径弄的晕头转向。路径问题经常导致include及require命令不能加载到指定的页面,从而导致Web程序运行错误。本文将跟大家一起探讨一下PHP路径问题的常用解决方案。
其实php手册里讲得很明白(include()函数的说明里)

寻找包含文件的顺序先是在当前工作目录的相对的 include_path 下寻找,然后是当前运行脚本所在目录相对的 include_path 下寻找。例如 include_path 是 .,当前工作目录是 /www/,脚本中要 include 一个 include/a.php 并且在该文件中有一句 include “b.php”,则寻找 b.php 的顺序先是 /www/,然后是 /www/include/。如果文件名以 ../ 开始,则只在当前工作目录相对的 include_path 下寻找。

当一个文件被包含时,其中所包含的代码继承了 include 所在行的变量范围。从该处开始,调用文件在该行处可用的任何变量在被调用的文件中也都可用。不过所有在包含文件中定义的函数和类都具有全局作用域。

本文其实就是对这个引用目录规则的应用引申.
下面我们先做一个个简单的示例:
 上图是一个简单Web项目的结构图,其中各文件的代码如下:

root/index.php

<?php
require_once app/blog.php’;
$blog=new Blog();

echo $blog->GetBlogInfo();

?>

root/app/blog.php

<?php
require_once ‘../lib/smarty/functions.php’;
?>

<?php

class Blog

{

   public function GetBlogInfo()

    {

     return This is a test of blog!;

    }

}

?>

<?php

echo root/app/blog.php loaded successed!</br>;

?>

首先,我们从浏览器里直接输入http://localhost/root/app/blog.php,浏览器显示:

———————————————————————-

root/app/blog.php loaded successed!

———————————————————————-

文件加载成功,没发生任何警告或错误。

接下来,我们在浏览器中请求如下网站:http://localhost/root/index.php,浏览器显示出如下错误信息:

———————————————————————————
Warning: require_once(../lib/smarty/functions.php) [function.require-once]: failed to open stream: No such file or directory in T:\Study\PHP_REL\Projects\root\app\blog.php on line 2
Fatal error: require_once() [function.require]: Failed opening required ‘../lib/smarty/functions.php’ (include_path=’.;C:\php5\pear’) in T:\Study\PHP_REL\Projects\root\app\blog.php on line 2

———————————————————————————

为什么’../lib/smarty/functions.php’没能加载? 我们访问http://localhost/root/app/blog.php没有出现任何异常,这说明出现错误的原因很可能在root/index.phprequire_once ‘app/blog.php’语句。从Google里搜索一下:php路径问题,你就能找到问题的答案。当root/index.php引用root/app/blog.php后,blog.php中的require_once语句的参照点变成了root/index.php所在的目录(根目录root)。所以,以root/index.php为参照点加载‘../lib/smarty/functions.php’时,自然就出错了。

找到了问题所在,接下来,我们就来寻找解决问题的办法:

1.将所有文件放在一个文件夹下

将所有文件放在一个文件夹下,那么就不会存在路径问题了。但是,这绝对是个馊主意!!除非你写一个小的不能再小的项目,不然请不要尝试这种方法,没有结构的系统太可怕了!

2.使用绝对路径

注:PHP中的include和require使用的是文件系统的绝对路径,如c:\wwwroot\yourproject\index.php
刚刚发生异常是因为我们使用了相对路径,如果换成绝对路径就不会出现以上错误。让我们简单修改一下root/app/blog.php:
将前三行由

step1:

<?php
require_once ‘../lib/smarty/functions.php’;

?>
 
修改为:

 

<?php
require_once T:\\Study\\PHP_REL\\Projects\\root\\lib\\smarty\\functions.php’;
?>

现在,我们访问:http://localhost/root/index.php ,浏览器显示:

—————————————-
root/app/blog.php loaded successed!
This is a test of blog!

—————————————-

程序执行成功了。

step2虽然程序不报错了,但很明显,我们并没有真正的解决问题。没有人会在程序里写require_onceT:\Study\PHP_REL\Projects…functions.php’这样的东西,这样写将会使程序完全丧失灵活性,使程序难以移植!

让我们再重新回想一下出现错误的原因:1.不同层次文件之间的引用使require_once参照点发生了变化;2.参照点发生变化后,按相对路径加载文件会出错。如果我们把require_once的参照点固定,问题不就解决了吗.如何固定参照点?当然是使用绝对路径,具体实现方法:一个函数+一个常量:dirname()和__FILE__。让我们重新修改root/app/blog.php如下:
将前三行由
 

 

<?php
require_once T:\\Study\\PHP_REL\\Projects\\root\\lib\\smarty\\functions.php’;
?>

修改为:

<?php
require_once dirname(__FILE__).‘/.‘../lib/smarty/functions.php’;
?>

再次访问http://localhost/root/index.php程序运行正常,但这种解决方式很明显优于step1中的解决方式。应该说,这是一种“绝对路径+相对路径”的解决方式。

step3:上面的方法已经能够解决路径问题,但感觉代码不够优雅。让代码更优雅,我们可以这样做:在根目录(root)下新建一个settings.php:

 

root/settings.php :

<?php
if(!defined(ABSPATH))
define(ABSPATH’,dirname(__FILE__).‘/’);

?>

root/app/blog.php中的代码修改为:

<?php
require_once ABSPATH.‘lib/smarty/functions.php’;
?>

同时root/index.php中的代码修改为:

<?php
require_once ’settings.php’;
require_once ABSPATH.‘app/blog.php’;

$blog=new Blog();

echo $blog->GetBlogInfo();

?>

仔细考虑一下,如果直接访问http://localhost/root/app/blog.php又会出现问题:常量ABSPATH没有定义。所以,如果你的程序有直接访问http://localhost/root/app/blog.php这种情况类似的情况,那么最好直接使用dirname(__FILE__) .‘/’.‘相对路径’,或者在使用ABSPATH前加一个判断(但这样有点脱裤子放X的感觉)。

:在WordPress中使用了ABSPATH与dirname(__FILE__).‘/’.‘相对路径’相结合的方法,从网站统一入口(根目录/index.php)加载的文件,使用ABSPATH的解决方法(ABSPATH在根目录/wp-config-sample.php 中定义),而那些不直接通过统一入口访问的php文件,WP使用dirname(__FILE__).‘/’.‘相对路径’的解决方案。

3.设置Apache的include_path参数

在前面的错误信息中,有一句值得我们注意:

———————————————
Fatal error: require_once() [function.require]: Failed opening required ‘../lib/smarty/functions.php’ (include_path=’.;C:\php5\pear’) in T:\Study\PHP_REL\Projects\root\app\blog.php on line 2
———————————————

 

Apache的include_path参数保存的是require/include的读取目录,在上面的错误信息里,include_path包含了两个位置:
1) “.”表示从当前文件所在的目录中加载
2) “C:\php5\pear”表示从C盘的php5/pear目录下加载。

php函数库为我们提供了set_include_path()函数用于设置include_path参数。通过set_include_path()函数,我们可以自定义加载位置(ZendFramework中就是使用set_include_path()函数来解决路径问题)。

下面我们来演示一下如何用set_include_path()函数:

root/index.php :

<?php
set_include_path(‘./’.PATH_SEPARATOR.dirname(__FILE__));
require_once ‘app/blog.php’;

 

$blog = new Blog();
echo $blog->GetBlogInfo();
?>

root/app/blog.php ;

<?php
require_once ‘lib/smarty/functions.php’;
?>

<?php

class Blog

{

   public function GetBlogInfo()

   {

    return ‘This is a test of blog!’;

   }

}

?>

<?php

echo ‘root/app/blog.php loaded successed!<br/>’;

?>

测试http://localhost/root/index.php,运行正常。从root/app/blog.php可以看出,require_once的路径写法更简洁了(不需要使用ABSPATH或者dirname(__FILE__))。这种实现方式跟ABSPATH的解决方式一样,需要保证系统有统一的入口点(一般通过.htaccess文件实现)。

当然,解决php路径的方法不止以上几种,网上有很多人提供了针对php路径问题的解决方案,但多数都有一定的适用场景,不能生搬硬套。

发表评论?

2 条评论。

  1. :cry: :neutral:

发表评论