我所有的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" ?>
对我有用,通常被提及。
但我想知道使用变量是否是一种可靠,有效的方法?
答案 0 :(得分:11)
<强>唐&#39;吨强>
我建议反对使用任何需要PHP之外的东西,比如$_SERVER变量。
$_SERVER['DOCUMENT_ROOT']
通常由Web服务器设置,这使得从命令行运行的脚本无法使用。所以不要使用它。
也不要使用网址。 url中的路径部分与磁盘上文件的路径不同。。实际上,该路径甚至不能存在于磁盘上(想想Apache重写)。
包括网址还需要您启用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
)..
是1个目录(所以我们得到/path/to/symlink
)symlink
指向/path/to/another
您并非需要来使用realpath()
,但如果您依赖相关部分或符号链接,它确实可以整理路径。它也更容易调试。
<强>自动加载强>
如果您需要包含包含类的文件,最好使用autoloading。这样你根本不需要include
语句。
使用框架
最后一点建议:这个问题已经解决了很多次。我建议你去看看像Symfony,Zend Framework,Laravel等框架。如果你不想要一个完整的堆栈&#34;解决方案,看看像Silex,Slim,Lumen等微框架。
答案 1 :(得分:2)
Jasper提出了一些好处,不使用DOCUMENT_ROOT的另一个原因是通过URL访问的内容不必在此目录中(例如,考虑Apache的别名,scriptalias和mod_user_dir)。
正如Barmar所指出的,PHP明确提供了声明包含基本目录的功能。虽然这通常在代码中的配置can be overridden/added to at runtime中设置。您从不想要在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/
答案 2 :(得分:1)
为每个文件tipe定义一个路径:
+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);
}
}
是一种简单的实施方法,但您需要了解有关注射和类加载器的更多信息。
答案 3 :(得分:1)
没有“正确方式”要求/包含项目中的内部脚本。很多(大多数)MVC框架在路由器对象中使用类似的最佳实践进行全局文件访问。
我们举一个例子,这是我们的目录基础设施:
App/
Controllers/
Controller.php
Models/
Model.php
Views/
View.php
404/
index.php
index.php
.htaccess
在我们的.htaccess
内,我们会在服务器的 root 目录中为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
,那么您的文件路径将是 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;