设置include / require文件的路径


Setting the path for include / require files

我所有的PHP include文件都在一个目录下:

https://www.mywebsite.com/includes

将这些文件插入顶级页面是很容易的:

<?php include 'includes/logo.php'; ?>
<?php include 'includes/main_nav.php'; ?>
<?php include 'includes/news.php'; ?>
etc.

对于子目录页面,我一直这样做:

<?php include '../includes/logo.php'; ?>
<?php include '../includes/main_nav.php'; ?>
<?php include '../includes/news.php'; ?>

:

<?php include '../../includes/logo.php'; ?>
<?php include '../../includes/main_nav.php'; ?>
<?php include '../../includes/news.php'; ?>

到目前为止一切顺利,但我怀疑不会再这么轻松了。

现在我需要包含这个文件:

top_five_news_stories.php

:

news.php
此时,我的相对路径策略失败了,因为include中的include只能有一个路径结构。

我读过一些推荐绝对路径的帖子:

  • dirname(__FILE__)
  • realpath(dirname(__FILE__)
  • $_SERVER["DOCUMENT_ROOT"]

然而,它们都带有一些与PHP配置、服务器配置或操作系统相关的警告。换句话说,经常有人评论说它在他们的情况下不起作用,或者在IIS中不起作用,或者在UNIX中不起作用,或者其他什么。

我还没见过一个我认为最简单的解决方案:只要设置一个变量:

$base = "https://www.mywebsite.com/includes";

:

<?php include $base . "logo.php" ?>
考虑到我已经使用了HTML base 元素,它以类似的方式工作,这个方法给我的印象是简单而有效的。

但是因为在我读到的任何帖子中都没有提到它,我想知道我是否忽视了一个潜在的问题。

坦率地说,如果我今天必须去生产,我会用这个:

<?php include  $_SERVER['DOCUMENT_ROOT'] . '/logo.php" ?>

这对我来说很有效,而且经常被提及。

但我想知道如果使用变量是一个可靠的,有效的方法?

不要

我建议不要使用任何需要PHP之外的东西,比如$_SERVER变量。

$_SERVER['DOCUMENT_ROOT']通常由web服务器设置,这使得它无法用于从命令行运行的脚本。所以不要用这个

也不要使用url。url中的路径部分与文件在磁盘上的路径不同。事实上,这个路径甚至不能在磁盘上存在(想想Apache重写)。

包含url也需要您打开allow_url_include,如果使用不当,将引入(严重的)安全风险。

如果您支持的最小PHP版本是5.3(我希望是!),您可以使用神奇常数__DIR__。两个例子:

define(ROOT_DIR, __DIR__);
define(ROOT_DIR, realpath(__DIR__ . '/..'));

如果需要支持较低版本,请使用dirname(__FILE__)。两个例子:

define(ROOT_DIR, dirname(__FILE__));
define(ROOT_DIR, realpath(dirname(__FILE__) . '/..'));

确保ROOT_DIR指向项目的根目录,而不是其中的子目录。

您可以安全地使用ROOT_DIR来包含其他文件:

include ROOT_DIR . '/some/other/file.php';

注意,我定义的是一个常量(ROOT_DIR),而不是一个变量。变量可以改变,但是项目的根目录不能改变,所以常量更合适。

realpath ()

realpath()将解析任何相对部分和符号链接到规范化的绝对路径名。

那么给定以下文件和符号链接:

/path/to/some/file.php
/path/to/another/file.php
/path/to/symlink => /path/to/another

/path/to/file.php包含:

define(ROOT_DIR, realpath(__DIR__ . '/../symlink'));

ROOT_DIR将变成/path/to/another,因为:

  • __DIR__ = /path/to/some(所以我们得到/path/to/some/../symlink)
  • ..是1目录向上(所以我们得到/path/to/symlink)
  • symlink指向/path/to/another

使用realpath()并不需要,但是如果您依赖于相关部分或符号链接,它确实会整理路径。它也更容易调试。

半自动的

如果需要包含包含类的文件,最好使用自动加载。这样你就根本不需要include语句了。

使用框架

最后一个建议:这个问题已经被解决过很多次了。我建议你去看看Symfony、Zend framework、Laravel等框架。如果你不想要一个"全栈"的解决方案,看看像Silex, Slim, Lumen等微框架

Jasper提出了一些很好的观点,不使用DOCUMENT_ROOT的另一个原因是,通过URL访问的内容不必在这个目录中(例如,考虑Apache的别名,scriptalias和mod_user_dir)。

正如Barmar指出的那样,PHP显式地提供了为包含声明基目录的功能。虽然这通常是在配置中设置的,但可以在运行时在代码中重写/添加。你永远不希望在include/require指令中看到一个变量。它破坏了自动工具并隐藏了漏洞。也不应该包括使用文件包装器。

在OO编程中有一个关于永远不要显式地使用include/require 而只是自动加载类定义的争论。然而,定位代码的问题仍然存在。

简短的回答是,对于你所描述的问题,没有最佳解决方案。每种方法都有其缺点——最佳解决方案完全依赖于上下文。对于企业应用程序,设置include_path可以简化开发过程,如果不能从web服务器直接访问,则可以增强安全性。它还允许通过操纵路径中多个条目的顺序来选择性地覆盖功能。

另一方面,这不是一个很好的软件模型,你打算分发给技术水平较低的用户,可能会对多个路径感到困惑,这些用户可能无法访问文档根目录以外的目录或更改默认配置。

使用相对路径是一个健壮且可移植的解决方案。我不明白你为什么要加入top_five_news_stories.php

下面显示了一个解决方案,它同时提供了企业和低端主机的优势。然而,这有一个缺点,它需要在站点的每个入口点添加代码(并且要求应用程序安装在命名的子目录中):

define('APP_NAME', 'mikesdemo');
$base=substr(__DIR__, 0, strrpos(__DIR__, APP_NAME))
      . APP_NAME . '/include';
set_include_path(get_include_path() . PATH_SEPARATOR . $base);

更老练的用户可以直接....

mv /var/www/html/mikesdemo/include/* /usr/local/php/include/

File architecture Rework:

为每种类型的文件定义一个路径,如下所示:

+root
|
+------app(D)(all php script MVC)
|
+------conf(D)(all php Config file)
|
+------assets(D)(all file js and css static image)
|
+------fileup(D)(all file Uploades)
|
+------index.php(F)(Procesor of petition http)

在你的索引,你需要包括所有的文件配置像风格的c++:

<标题>例子:
require_once ('conf/config.security.php'); #Configuration around Security in PHP
require_once ('conf/config.conpro.php'); #Configuration around Constantent
require_once ('conf/config.classlib.php'); #Lib class around Generic DB Conection ETC
require_once ('conf/config.classlibmvc.php'); #Lib class around MVC specific class

配置文件的示例:

声明根目录+共享文件的路径

$APP_DIR_CLASS          =       $_SERVER['DOCUMENT_ROOT']   .   '/app/classgeneric/';
定义库文件:
if (!defined('DBMANAGER_CLASS'))                define('DBMANAGER_CLASS'            ,'class.managerdb.php'          );

包含或要求类

require_once $APP_DIR_CLASS     . DBMANAGER_CLASS;

当你在一个类,需要使用DB类,你可以调用它很容易:

class Class_Exmaple{
    public function __construct(){
        $this   ->  DBMANAGER               =   new Class_BDManager();
    }
    public function __destruct(){
        $this   ->  DBMANAGER               =   new Class_BDManager();
    }
    public function ConsultDB(){
        $query ='Selec * From Tablename';
        $result = $this -> DBMANAGER -> ExecuteQ($query);
        print_r(result);
    }
}

是一种容易实现的方法,但是你需要学习更多关于注入和类加载器的知识。

没有 "正确的方式"要求/在您的项目中包含一个内部脚本。很多(大多数)MVC框架使用类似的最佳实践路由器对象中访问全局文件。

让我们举一个例子,这是我们的目录基础结构:

App/
    Controllers/
        Controller.php
    Models/
        Model.php
    Views/
        View.php
    404/
        index.php
index.php
.htaccess

在我们的.htaccess中,我们将有一个rewrite规则到服务器的根目录中的index.php

在这个文件中,是我们实际运行整个软件的地方。例如,这是一个很棒的路由器,我使用AltoRouter。

首先,我们需要添加一种方法来阻止浏览器直接访问任何控制器、模型和视图,并提供错误路径:
define( 'ERROR_PATH', strtolower(explode( '/', $_SERVER['SERVER_PROTOCOL'][0]) . '://' . $_SERVER['SERVER_NAME'] . '/404' );
define( 'IN_APP', 0 );

然后在你的控制器,模型和视图中使用,如:

if( !defined( 'IN_APP' ) )    {
    header('Location: ' . ERROR_PATH);
    exit();
}

你的文件路径将是文件路径,如果你声明__FILE__在这个实例(index.php),所以我们可以使用它的任何方式(最佳实践是全局定义)。

 define( '_DIR_', dirname(  __FILE__ ) );

然后开始要求你的文件:

$includeFiles = [
    glob( _DIR_ . '/Controllers/*.php' ),
    glob( _DIR_ . '/Models/*.php' )
];
foreach( $includeFiles as $dir ):
    foreach( $dir as $file ):
        require_once( $file );
    endforeach;
endforeach;