【发布时间】:2011-04-26 22:21:19
【问题描述】:
我有一个包含在我的 php 脚本中的 php 文件,但我不希望人们能够直接运行该文件(不包含在内)。 我怎样才能防止这种情况发生?
【问题讨论】:
我有一个包含在我的 php 脚本中的 php 文件,但我不希望人们能够直接运行该文件(不包含在内)。 我怎样才能防止这种情况发生?
【问题讨论】:
使包含的脚本根本无法通过 HTTP 访问。例如。通过保护子文件夹或将它们移动到文档根目录上方。
如果你不能这样做,define() 类似于 IS_INCLUDED 在你的主脚本中,exit; 如果这个常量不是 defined() 在你包含的脚本中。
【讨论】:
.htaccess 的解决方案也很简单——而且大多数人都在使用 Apache。
.htaccess 不会帮助您。
检查脚本是否是 PHP 进程的父进程可能不是阻止用户直接请求包含文件的最佳方法。但它在许多其他情况下也很方便,例如 AJAX 模块等。我不会以此开始新话题。
if (__FILE__ == get_included_files()[0])
// Doesn't work with PHP prepend unless calling [1] instead.
if (__FILE__ == $_SERVER['DOCUMENT_ROOT'] . $_SERVER['SCRIPT_FILENAME'])
// May not work on Windows due to mixed DIRECTORY_SEPARATOR (machine specific)
if (basename(__FILE__) == basename($_SERVER['SCRIPT_FILENAME']))
// Doesn't work with files with the same basename but different paths
if (defined('FLAG_FROM_A_PARENT'))
// Works in all scenarios but I personally dislike this
if (realpath(__FILE__) == realpath($_SERVER['DOCUMENT_ROOT'] . $_SERVER['SCRIPT_FILENAME']))
// Should work flawlessly
请记住,某些使用虚拟路径的机器可能会在不同的 php 组件中返回不同的路径。 realpath() 是你的朋友。
【讨论】:
if(strtolower($_SERVER['SCRIPT_FILENAME']) === strtolower(__FILE__)) {版本。当我想测试一个我通常需要_once() 的文件时,我会使用它。
我使用一个 sentinel 常量,在“包含”脚本中定义,“包含”脚本会查找它。
例子:
/* main.php */
define('SENTINEL', 1);
include "included.inc.php"
/* included.inc.php */
if (!defined('SENTINEL')) die("Wanted to be smart?? Nice try.");
【讨论】:
2 种良好保护的解决方案:
使用 htaccess:
RedirectMatch 404 "\.(sql|sh|java|class|inc\.php)$"
或者在/etc/apache2/sites-enabled:
<VirtualHost *:80>
#...
RedirectMatch 404 "\.(sql|sh|java|class|inc\.php)$"
#...
</VirtualHost>
然后像这样命名你的文件:myInternalFileIncludeOnly.inc.php
通过这个示例代码,PHP 能够检测包含:
if( get_included_files()[0] == __FILE__ ){
echo '2.php direct access';
}else{
echo '2.php was included';
}
编辑: 请参阅 Tim 的答案,因此,如果您有前置 include (cf php.ini),请使用:
if(
(!ini_get('auto_prepend_file') && get_included_files()[0] === __FILE__)
||
ini_get('auto_prepend_file') && (($__FILE__=str_replace('\\','/',__FILE__)) === str_replace('\\','/',$_SERVER['DOCUMENT_ROOT'].$_SERVER['SCRIPT_FILENAME']) || $__FILE__ === str_replace('\\','/',$_SERVER['SCRIPT_FILENAME']) )
)
echo '2.php direct access',"\n";
【讨论】:
我在一些应用程序中看到了这种模式:
define('SOMETHING', 'SOMEVALUE');
if(!defined('SOMETHING')) return; 开头
【讨论】:
包含的 PHP 文件应包含类/函数/变量定义,而不是内联逻辑/输出。
直接运行它们基本上是无操作的。
【讨论】:
include 来获取请求的页面内容,而无需使用数据库或其他复杂的东西(模板等...)