我所有的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;