我有一个php文件,我将专门将其用作包含文件。因此,我想抛出一个错误,而不是在直接通过输入URL而不是将其包含而直接访问它时执行它。

基本上,我需要在php文件中进行如下检查:

if ( $REQUEST_URL == $URL_OF_CURRENT_PAGE ) die ("Direct access not premitted");


有简单的方法吗?

评论

而不是die(),您应该测试'header(“ HTTP / 1.1 404 File Not Found”,404);出口;'。这将(至少在apache上)使服务器返回正常的404页面。

这是我已经解释过的两种简单方法,用于禁用PHP包含的文件中的直接访问-codespeedy.com/disable-direct-access-to-the-php-include-file

#1 楼

通用的“您可能会或可能不会完全控制的Apache服务器上运行的PHP应用程序”情况的最简单方法是将includes放在目录中,并拒绝访问.htaccess文件中的该目录。为了避免人们使用谷歌搜索的麻烦,如果您使用的是Apache,请将其放在您不希望访问的目录中的名为“ .htaccess”的文件中:

如果您实际上拥有服务器的完全控制权(相对于我初次写此答案时,如今对于小型应用程序来说,如今更为普遍),最好的方法是将要保护的文件粘贴到Web目录之外服务器正在提供服务。因此,如果您的应用程序位于/srv/YourApp/中,则将服务器设置为提供来自/srv/YourApp/app/的文件,并将包含内容放入/srv/YourApp/includes中,因此实际上没有任何URL可以访问它们。

评论


如果将配置放入虚拟主机配置文件中的目录指令中,则可以更好地控制服务器。 Apache在启动时仅读取一次,每次访问均读取.htaccess并降低服务器速度

– Eineki
09年1月3日,19:43

最好有一个示例.htaccess文件作为答案的一部分。

– Graham Lea
2012年6月5日在11:47

允许订单,拒绝全部拒绝

– Dracorat
2012年9月27日下午16:53

@James:而且,并不是每个人都认为Stack Overflow应该是“请发送Codez的网站”。如果它清楚地回答了问题,那么这是一个很好的答案。提供一个不需要示例的示例只会鼓励复制和粘贴代码。

–卡盘
2013年9月10日在21:03



我尝试了这个,如果您拒绝所有操作,即使在包含中也无法使用,它会404。

–迈克尔·罗杰斯(Michael Rogers)
17年7月3日在9:53

#2 楼

将此内容添加到只希望包含的页面中

<?php
if(!defined('MyConst')) {
   die('Direct access not permitted');
}
?>


然后在包含该页面的页面上添加

<?php
define('MyConst', TRUE);
?>


评论


我真的需要学习打字。这与我建议的方式相同,因为它比使用变量进行检查的方法更安全。由于使用某些PHP设置,可能可以覆盖该变量。

–马克·戴维森
09年1月3日在18:17

这就是一些“主流”应用程序处理它的方式。我知道Joomla就是这样做的,我认为Wiki,Wordpress以及其他也是如此。

– UnkwnTech
09年1月3日,18:20

只需发送404标头并退出-错误页面将看起来与普通404页面相同(至少在Apache上如此)。

– gnud
09年1月4日在13:24

@ Smile.Hunter:这是关于阻止直接访问您的包含/库脚本文件的访问,答案有效。如果他们在您的服务器上创建了somefile.php并在其中添加了您的定义,那仍然不允许他们直接访问包含文件。它将使它们“包含”您的库文件,但是如果它们足够远,无法在服务器上创建文件并知道您的定义/包含脚本,那么您可能会遇到其他问题,这些问题可能会否定首先用您的定义编写自己的文件。

–詹姆斯
2013年9月10日16:43



拒绝具有相同结果的访问的更短方法是:define('MyConst')|| die('不允许直接访问');

– MDeuerlein
16 Jan 10'在2:43



#3 楼

我有一个文件,当包含它时和直接访问它时,我需要采取不同的动作(主要是print()return()),这是一些修改后的代码:
被访问的文件始终是包含文件,因此== 1。

评论


检查包含的文件数实际上是个想法。我想知道哪个更好:使用定义还是使用此方法?这似乎是独立的。

– Akoi Meexx
2011年6月8日在16:40

我第一次见过有人提出这个建议。我不知道为什么,因为它看起来像是自给自足的,它直接测量您真正想知道的内容(如果包含或不包含),而不是测量被假定与之相关的东西(例如某个常数或.htaccess禁止的特定位置)。美丽。

–Jimbo Jonny
2012年8月8日在12:34

这真的很酷,因为可能无法一直使用.htaccess阻止所有.php文件,因为同一目录中可能有一些文件需要直接调用,甚至需要用javascript调用。感谢这个好主意!

– Anuj
2012-09-18 20:55

这仅适用于PHP5及更高版本。在PHP5之前的版本,您要再次比较0而不是1。

– jmucchiello
13年6月10日在1:26

这是一个非常聪明的解决方案,可以让您控制直接访问,而不仅仅是阻止它-这就是我想要的。我通常在文件本身中包含单元测试,这样我就可以在if语句中包装单元测试。想知道它的效率如何。

–whiteatom
13年7月12日在16:19

#4 楼

防止直接访问文件的最佳方法是将它们放置在Web服务器文档根目录之外(通常位于上一级)。您仍然可以包括它们,但是没有人通过http请求访问它们的可能性。引导程序文件-文档根目录中的一个孤独的index.php,开始路由整个网站/应用程序。

评论


如果可以的话,这是一个很好的解决方案。我只是最近才开始使用共享的Web主机,并且发现许多烦恼之一是所有内容都必须在文档根目录内。

–西蒙森(Beau Simensen)
09年1月3日,19:29

在与我合作的每个托管服务提供商中,我总是可以(完全)访问文档根目录之上的一个级别。

– Eran Galperin
09年1月3日在21:21

在某些主机上(包括我当前的主机),您可以将域指向所需的任何文件夹。

–黛娜
09年6月23日在15:43

这也是一个很好的选择..使用preg_match-> if(preg_match(“〜globalfile \ .php〜i”,$ _SERVER ['PHP_SELF'])){die('

设备安全警报-禁止直接访问!您的IP已被记录!

'); //停止进一步执行}

– MarcoZen
17年11月30日在15:13

url devzone.zend.com/node/view/id/70现在是404。答案应包括最初从该不存在的URL使用的代码。

–放克四十尼纳
18年5月8日在13:22



#5 楼

1:检查包含文件的数量
if( count(get_included_files()) == ((version_compare(PHP_VERSION, '5.0.0', '>='))?1:0) )
{
    exit('Restricted Access');
}

逻辑:如果未达到最小包含数量,则PHP退出。请注意,在PHP5之前,基本页面不被视为包含。

2:定义和验证全局常量
// In the base page (directly accessed):
define('_DEFVAR', 1);

// In the include files (where direct access isn't permitted):
defined('_DEFVAR') or exit('Restricted Access');

逻辑:如果未定义常量,那么执行不是从基础页面开始的,PHP会停止执行。
请注意,为了在升级和将来的更改中具有可移植性,将这种身份验证方法模块化可大大减少编码开销不必对每个文件都进行硬编码。值得赞扬的地方:可移植性的绝妙想法来自此答案。

3:远程地址授权
// Put the code in a separate file instead, say 'checkdefined.php':
defined('_DEFVAR') or exit('Restricted Access');

// Replace the same code in the include files with:
require_once('checkdefined.php');

这种方法的缺点是隔离执行,除非会话-内部请求随附的令牌。如果是单服务器配置,则通过回送地址进行验证;对于多服务器或负载平衡的服务器基础结构,则通过地址白名单进行验证。

4:令牌授权
类似与前一种方法相比,可以使用GET或POST将授权令牌传递到包含文件:

5:Web服务器特定的配置
大多数服务器允许您为单个文件或目录分配权限。您可以将所有包含项放在这些受限制的目录中,并配置服务器以拒绝它们。
例如在APACHE中,配置存储在checkdefined.php文件中。此处的教程。
但是请注意,我不建议使用服务器特定的配置,因为它们不利于跨不同Web服务器的可移植性。在诸如内容管理系统这样的拒绝算法很复杂或被拒绝目录的列表很大的情况下,它可能只会使重新配置会话变得非常麻烦。最后,最好用代码来处理。

6:将根目录放置在安全目录之外的站点根目录
由于服务器环境中的访问限制,它是首选,但它是一种相当强大的方法如果您有权访问文件系统。
// Call the include from the base page(directly accessed):
$includeData = file_get_contents("http://127.0.0.1/component.php?auth=token");

// In the include files (where direct access isn't permitted):
$src = $_SERVER['REMOTE_ADDR']; // Get the source address
$auth = authoriseIP($src); // Authorisation algorithm
if( !$auth ) exit('Restricted Access');

逻辑:

用户无法请求.htaccess文件夹之外的任何文件,因为链接将超出网站范围地址系统。
php服务器本机访问文件系统,因此可以像具有所需特权的普通程序一样访问计算机上的文件。
通过将包含文件放置在此目录中,您可以可以确保php服务器能够访问它们,而拒绝用户进行热链接。 >

请原谅我非正统的编码约定。感谢您提供任何反馈意见。

评论


我喜欢2号

–Baim错误
18年4月18日在14:53

#6 楼

Chuck解决方案的替代方案(或补充方案)是通过在您的.htaccess文件中放置类似这样的内容来拒绝访问与特定模式匹配的文件

<FilesMatch "\.(inc)$">
    Order deny,allow
    Deny from all
</FilesMatch>


评论


我相信使用.inc.php会更好,这是一种常见的做法

– Lis
19/12/16在9:37

#7 楼

实际上,我的建议是执行所有这些最佳实践。


将文档放在Webroot之外,或者放在Web服务器拒绝访问的目录中在可见文件中定义隐藏文件是否检查: />

#8 楼

我曾经遇到过这个问题,可以通过以下方法解决:

if (strpos($_SERVER['REQUEST_URI'], basename(__FILE__)) !== false) ...


,但是理想的解决方案是将文件放置在Web服务器文档根目录之外,如另一个anwser所述。

#9 楼

我想直接限制对PHP文件的访问,但也可以通过jQuery $.ajax (XMLHttpRequest)对其进行调用。这对我有用。

if (empty($_SERVER["HTTP_X_REQUESTED_WITH"]) && $_SERVER["HTTP_X_REQUESTED_WITH"] != "XMLHttpRequest") {
    if (realpath($_SERVER["SCRIPT_FILENAME"]) == __FILE__) { // direct access denied
        header("Location: /403");
        exit;
    }
}


#10 楼

您最好使用一个入口点构建应用程序,即应从index.php

访问所有文件。将其放在index.php

define(A,true);


此检查应在每个链接文件中运行(通过require或include)

defined('A') or die(header('HTTP/1.0 403 Forbidden'));


#11 楼

最简单的方法是在调用包含的文件中设置一些变量,例如

$including = true;


然后在要包含的文件中,检查变量

if (!$including) exit("direct access not permitted");


评论


如果register_globals打开,则很危险。

– jmucchiello
09年1月3日在18:51

如果打开register_globals,则PHP是危险的。

– David Precious
09年1月3日,18:56

#12 楼

我的答案在方法上有所不同,但包括此处提供的许多答案。我建议使用多管齐下的方法:

.htaccess和Apache的限制,以确保
defined('_SOMECONSTANT') or die('Hackers! Be gone!');

但是defined or die方法有很多缺点。首先,在进行测试和调试的假设中确实是一个痛苦。其次,如果您改变主意,它将涉及令人恐惧,令人麻木的无聊重构。 “查找和替换!”你说。是的,但是您如何确定它在所有地方都完全相同,嗯?现在,将其与成千上万个文件相乘... o.O

然后是.htaccess。如果将您的代码分发到管理员不是很谨慎的站点上会怎样?如果仅依靠.htaccess来保护文件安全,则还需要a)备份,b)一盒纸巾擦干眼泪,c)灭火器以扑灭人们发来的所有仇恨邮件使用您的代码。

所以我知道这个问题要求“最简单”,但是我认为这需要更多的“防御性编码”。

我建议的是:


在任何脚本require('ifyoulieyougonnadie.php');之前(不是include()并代替defined or die

ifyoulieyougonnadie.php中,请执行一些逻辑操作-检查不同的常量,调用脚本,进行localhost测试等-然后实现您的die(), throw new Exception, 403等。我的框架)-因此,根据切入点的不同,我会检查不同的内容。如果对ifyoulieyougonnadie.php的请求不是来自这两个文件之一,那么我知道这是在进行恶作剧!

但是如果我添加一个新的入口点怎么办?别担心。我只更改了ifyoulieyougonnadie.php并进行了排序,没有“查找并替换”。万岁!

如果我决定移动一些脚本以执行一个没有相同常量defined()的不同框架怎么办? ……万岁! ^ _ ^


我发现这种策略使开发变得更加有趣而更少:

/**
 * Hmmm... why is my netbeans debugger only showing a blank white page 
 * for this script (that is being tested outside the framework)?
 * Later... I just don't understand why my code is not working...
 * Much later... There are no error messages or anything! 
 * Why is it not working!?!
 * I HATE PHP!!!
 * 
 * Scroll back to the top of my 100s of lines of code...
 * U_U
 *
 * Sorry PHP. I didn't mean what I said. I was just upset.
 */

 // defined('_JEXEC') or die();

 class perfectlyWorkingCode {}

 perfectlyWorkingCode::nowDoingStuffBecauseIRememberedToCommentOutTheDie();


#13 楼

除了.htaccess方式以外,我还在各种框架中看到了有用的模式,例如在Rails上的ruby中。它们在应用程序根目录中有一个单独的pub /目录,而库目录位于与pub /处于同一级别的目录中。这样的事情(不是很理想,但您可以理解):

app/
 |
 +--pub/
 |
 +--lib/
 |
 +--conf/
 |
 +--models/
 |
 +--views/
 |
 +--controllers/


您将Web服务器设置为使用pub /作为文档根目录。这可以为您的脚本提供更好的保护:尽管它们可以从文档根目录伸出以加载必要的组件,但无法从Internet访问这些组件。除了安全性外,另一个好处是所有内容都在一个地方。而不是.htaccess配置,因为它不是基于白名单的:如果您破坏了文件扩展名,它将在lib /,conf / etc等目录中不可见。

评论


长时间之后,我只想评论一下您在上面描述的模型称为MVC(模型-视图-控制器)模型。如果您愿意,请检查google并为您的答案添加更多信息。 MVC还不仅支持Ruby on Rails和ASP.NET应用程序,还支持PHP(请参阅Lavarel,CakePHP)。

–user4108694
16-2-15在11:45



#14 楼

什么Joomla!是在根文件中定义一个常量,然后检查是否在包含的文件中定义了该常量。

通过将大多数文件(如CodeIgniter之类的建议)放置在webroot目录之外,将所有文件保留在http请求无法访问的范围内。

,或者即使将.htaccess文件放在include文件夹中并编写规则,也可以防止直接访问。

#15 楼

debug_backtrace() || die ("Direct access not permitted");


#16 楼

如果更精确地讲,您应该使用以下条件:
因此,当直接访问文件时,它的名称是数组中的第一个文件,因此包含了数组中的所有其他文件。

#17 楼

<?php
if (eregi("YOUR_INCLUDED_PHP_FILE_NAME", $_SERVER['PHP_SELF'])) { 
 die("<h4>You don't have right permission to access this file directly.</h4>");
}
?>


将上面的代码放在包含的php文件顶部。

例如:

<?php
if (eregi("some_functions.php", $_SERVER['PHP_SELF'])) {
    die("<h4>You don't have right permission to access this file directly.</h4>");
}

    // do something
?>


评论


if(preg_match(“〜globalfile \ .php〜i”,$ _SERVER ['PHP_SELF'])){die('

设备安全警报-禁止直接访问!您的IP已被记录!

'); //停止进一步执行} whre〜是分隔符

– MarcoZen
17年11月30日在15:12

#18 楼

Flatnux CMS(http://flatnux.altervista.org)中使用以下代码:

if ( strpos(strtolower($_SERVER['SCRIPT_NAME']),strtolower(basename(__FILE__))) )
{
    header("Location: ../../index.php");
    die("...");
}


#19 楼

我发现了这种仅适用于PHP且不变的解决方案,该解决方案可与http和cli一起使用:

定义一个函数:您要防止直接访问的文件:

function forbidDirectAccess($file) {
    $self = getcwd()."/".trim($_SERVER["PHP_SELF"], "/");
    (substr_compare($file, $self, -strlen($self)) != 0) or die('Restricted access');
}


上面给出的大多数解决方案不能在Cli模式下使用。

评论


在CLI模式下应该在哪里键入URL?

–您的常识
2011年4月6日13:48

这只是为了防止在cli模式下启动php脚本/包含。在具有多个开发人员的项目中很有用。

–钾。
2011年4月6日下午14:51

#20 楼

if (basename($_SERVER['PHP_SELF']) == basename(__FILE__)) { die('Access denied'); };


#21 楼

<?php       
$url = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
  if (false !== strpos($url,'.php')) {
      die ("Direct access not premitted");
  }
?>


#22 楼

已经多次提到将包含文件存储在Web可访问目录之外,并且在可能的情况下肯定是个不错的策略。但是,我还没有提到另一种选择:确保包含文件中不包含任何可运行的代码。如果您的包含文件仅定义函数和类,并且没有其他代码,则当直接访问它们时,它们只会产生一个空白页。它什么也不会做。它定义了一些函数,但是没有一个被调用,因此它们都不会运行。


最好将文件放在Web目录之外。


在这种情况下,您可能会意外停用PHP。您的服务器可能会将PHP文件的内容发送到浏览器,而不是运行PHP并发送结果。这可能会导致您的代码(包括数据库密码,API密钥等)泄漏。
Web目录中的文件正在占用您可能要用于应用程序的URL。我使用的CMS不能包含名为system的页面,因为这将与用于代码的路径冲突。我觉得这很烦人。


#23 楼

做类似的事情:

<?php
if ($_SERVER['SCRIPT_FILENAME'] == '<path to php include file>') {
    header('HTTP/1.0 403 Forbidden');
    exit('Forbidden');
}
?>


评论


这不会阻止将其加载到浏览器中。

– UnkwnTech
09年1月3日在18:21

#24 楼

您可以在下面使用以下方法,尽管它确实存在缺陷,因为它可以被伪造,除非您可以添加另一行代码以确保使用Javascript来仅来自服务器的请求。可以将这段代码放在HTML代码的“正文”部分中,因此错误在那里显示。
<?
if(!isset($_SERVER['HTTP_REQUEST'])) { include ('error_file.php'); }
else { ?>


像这样结束它,因此错误的输出将始终显示在body部分中,如果您希望的那样。

评论


我了解所有HTTP_ *服务器标头都不可信,因此最好不要使用此方法。

– andreszs
17年4月3日在15:01

#25 楼

我建议出于安全原因不要使用$_SERVER
您可以在包含另一个文件的第一个文件中使用类似$root=true;的变量。
在包含的第二个文件的开头使用isset($root)

#26 楼

您还可以做的是用密码保护目录,并将所有PHP脚本保存在该目录中,当然除了index.php文件,因为在包含include时不需要密码,因为只有HTTP访问才需要。这样做还为您提供了访问脚本的选项(如果需要),因为您将具有访问该目录的密码。您将需要为该目录​​设置.htaccess文件,并需要一个.htpasswd文件来对用户进行身份验证。

好,您也可以使用上面提供的任何解决方案,以防您不需要之所以可以正常访问这些文件,是因为您始终可以通过cPanel等访问它们。

希望这会有所帮助

#27 楼

最简单的方法是将包含内容存储在Web目录之外。这样服务器可以访问它们,但没有外部计算机。唯一的缺点是您需要能够访问服务器的这一部分。好处是不需要设置,配置或额外的代码/服务器压力。

#28 楼

我发现.htaccess的建议不是很好,因为它可能会阻止该文件夹中您可能希望用户允许访问的其他内容,
这是我的解决方案:

$currentFileInfo = pathinfo(__FILE__);
$requestInfo = pathinfo($_SERVER['REQUEST_URI']);
if($currentFileInfo['basename'] == $requestInfo['basename']){
    // direct access to file
}


#29 楼

if ( ! defined('BASEPATH')) exit('No direct script access allowed');


会使工作顺利进行

评论


从CodeIgnitor复制粘贴。太酷了,但实际上它本身并不能做任何事情。 BASEPATH常量在树结构底部的index.php文件中设置。 CI会重写URL,因此无论如何都无需直接访问脚本。

– jimasun
16-10-28在15:37



我知道没有必要,但如果有人尝试这样做

–Varshaan
16-10-28在15:43

#30 楼

前面提到的带有PHP版本检查的解决方案已添加:

    $max_includes = version_compare(PHP_VERSION, '5', '<') ? 0 : 1;
    if (count(get_included_files()) <= $max_includes)
    {
        exit('Direct access is not allowed.');
    }


评论


我不太了解如何阻止直接访问

–亚当·林赛(Adam Lindsay)
16-10-7在14:54