2016-10-21 55 views
3

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

在这一点上,因为在包括包括只能有一个路径结构我的相对路径的策略失败。

我读过几个职位推荐使用绝对路径:

  • 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" ?> 

这对我的作品,通常提及。

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

+1

不要在'include'所使用的网址。当你通过网络服务器访问一个PHP脚本时,它会在远端执行它,它不会返回源代码,但是'include'需要源代码。 – Barmar

+0

看一下'php.ini'中的'include_path'设置。将你的包含文件放在那个目录中,然后你可以从任何脚本访问它们。 – Barmar

+0

http://php.net/manual/en/ini.core.php#ini.include-path – Barmar

回答

8

不要

我会使用任何需要的东西PHP之外,像$_SERVER可变建议

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

也不要使用网址。 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包括其他文件:我正在定义一个常数(ROOT_DIR

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

注意,不是一个变量。变量可以改变,但你项目的根目录不会,所以常数更适合。

真实路径()

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等框架。如果你不想要一个“完整的堆栈”解决方案,看看像Silex,Slim,流明等微观框架。

+0

很好的答案。它帮助我更好地了解需要完成的工作。谢谢。 –

+0

关于您对框架的建议,我从头开始重新设计现有的企业级网站。我正在使用框架*,我知道*在适当的地方。你在答案结尾提到的框架对我来说是新的。我会研究他们。 –

1

文件Arquitecture返修:

定义这样的文件的每个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 

配置文件示例:

0123该共享文件

申报根目录+路径

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

是一种简单的实现方式,但您需要了解有关注入和类加载器的更多信息。

+0

谢谢你的回答。它在常规知识方面很有用,但我很难将其应用于我的具体情况。如果您有任何其他建议,请告知。下面是我上面的问题的简要总结:https://jsfiddle.net/2npxxLwa/1/ –

+0

你能分享一个包含文件的内容吗? –

+0

这只是文字。构建框架。还没有实际内容 –

1

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/ 
+0

感谢您的详细答复。如果我不清楚'top_five_news_stories.php'的问题,我表示歉意。 –

+0

这里有一些更详细的信息:https://jsfiddle.net/2npxxLwa/ –

1

没有正确的方式”,要求/在项目中包含一个内部脚本。许多(大多数)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); 

,然后在你的控制器,模型和视图等中:如果您在这种情况下(index.php)宣布__FILE__所以我们可以使用它的任何方式(最好的做法是全球定义)

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

你的文件路径将会是文件路径。

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; 
+0

感谢您的回答。我很感谢你提到如何防止直接浏览器访问include/require文件,因为这是我一直在考虑的问题,但尚未解决。我仍在通过这里的答案来开发正确的解决方案。下面是你想添加更多内容的问题摘要:https://jsfiddle.net/2npxxLwa/ –

+0

看起来,阻止直接浏览器访问带有include/require文件的目录的最简单方法是将'.htaccess'文件在所有目录中用“”全部拒绝“”。在我所有的测试中工作到目前为止。 http://stackoverflow.com/a/409511/3597276 –

+0

是的,但使用'.htaccess'不是*可靠*,因为这也会阻止访问**图像**。最好将所有**不存在的请求奉献给索引文件,然后在那里路由请求。然后只允许使用'define()'和'defined()'方法访问特定的文件。许多开源Web应用程序中使用的基本最佳实践,如MyBB @Michael_B – KDOT