设置包含/需要文件的路径
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只能有一个路径结构。
我读过几篇推荐使用绝对路径的帖子:
dirname(__FILE__)
realpath(dirname(__FILE__)
$_SERVER["DOCUMENT_ROOT"]
但是,它们都带有一些与 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;
我所有的 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只能有一个路径结构。
我读过几篇推荐使用绝对路径的帖子:
dirname(__FILE__)
realpath(dirname(__FILE__)
$_SERVER["DOCUMENT_ROOT"]
但是,它们都带有一些与 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;