设置包含/需要文件的路径

Setting the path for include / require files

我所有的 PHP 包含文件都在一个目录中:

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只能有一个路径结构。

我读过几篇推荐使用绝对路径的帖子:

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

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

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

然后:

<?php include $base . "logo.php" ?>

考虑到我已经使用了以类似方式工作的 HTML base element,这种方法让我印象深刻。

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

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

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

这对我有用并且经常被提及。

但我想知道使用变量是否是一种可靠、有效的方法?

不要

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

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

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

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

如果您支持的最低 PHP 版本是 5.3(希望是!),您可以使用 magic constant __DIR__。 2 个示例:

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

如果需要支持低版本,使用dirname(__FILE__)。 2 个示例:

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() 会将任何相关部分和符号链接解析为规范化的绝对​​路径名。

因此给出以下文件和符号链接:

/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
  • .. 是上一级目录(所以我们得到 /path/to/symlink
  • symlink指向/path/to/another

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

自动加载

如果您需要包含包含 类 的文件,您最好使用 autoloading。这样你就根本不需要 include 语句。

使用框架

最后一点忠告:这个问题已经解决了很多很多次了。我建议你去研究 Symfony、Zend Framework、Laravel 等框架。如果你不想要 "full stack" 解决方案,请研究 Silex、Slim、Lumen 等微框架。

文件架构返工:

像这样为每个文件类型定义一个路径:

+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'          );

包括或需要 class

require_once $APP_DIR_CLASS     . DBMANAGER_CLASS;

当你处于 class 并且需要使用 DB class 时,你可以简单地调用它:

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);
    }
}

是一种简单的实现方式,但您需要了解更多有关注入和 Class 加载程序的知识。

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

正如 Barmar 指出的那样,PHP 明确提供了为包含声明基目录的功能。虽然这通常在配置中设置,但在您的代码中 can be overridden/added to at runtime。您从不 想在您的include/require 指令中看到一个变量。它破坏了自动工具并隐藏了漏洞。您也不应该使用文件包装器。

在 OO 编程中有一个论点是 never 显式使用 include/require 但只是自动加载 class 定义。然而,定位代码的问题仍然存在。

简短的回答是,对于您描述的问题,没有最佳 解决方案。每种方法都有其缺点 - 最佳解决方案完全取决于上下文。对于企业应用程序,设置 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/

没有正确的方法”require/include您项目中的内部脚本。许多(大多数)MVC 框架使用类似的 最佳实践 来访问 路由器 对象中的全局文件。

举个例子,这是我们的目录结构:

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

在我们的 .htaccess 中,我们将在您服务器的 root 目录中对 index.php 设置一个 rewrite 规则。

在这个文件中,我们实际上 运行 整个软件。例如,这是我使用的很棒的路由器 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),您的文件路径将是 root 文件路径,因此我们可以以任何方式使用它 (最佳实践是全局定义的)。

 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;