PHP:检查文件是否直接加载而不是包含?

问题描述 投票:0回答:15

有没有办法阻止用户查看文件,但仍将其用作包含在 PHP 中的另一个文件中?

php file include
15个回答
53
投票

如果您使用

define('APP_RAN'); 

在包含它的文件中,然后放入

if(!defined('APP_RAN')){ die(); }

或者另一种选择

defined('APP_RAN') or die();

(更容易阅读)

在包含的文件中,如果直接访问它们就会消失。


不过,将所有包含的文件放在 DocumentRoot 之上可能会更好。

例如,如果您的索引页位于

/my/server/domain/public_html

您应该将包含的文件放入

/my/server/domain/

15
投票

我的建议:

<?php
if (__FILE__ == $_SERVER['SCRIPT_FILENAME']) {
    header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found');
    exit("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n<html><head>\r\n<title>404 Not Found</title>\r\n</head><body>\r\n<h1>Not Found</h1>\r\n<p>The requested URL " . $_SERVER['SCRIPT_NAME'] . " was not found on this server.</p>\r\n</body></html>");
}
else {
   // your code
}
?>

1.)它检查是否直接调用它,否则会抛出错误

2.)它输出一个 404 标准 apache 错误页面(请与您的原始 404 页面进行比较或简单地包含该页面),以通过模糊性来增加安全性

3.) else 部分避免了文件上传到实时环境时的部分执行(PHP 不等待“?>”)。如果您的包含文件仅包含一个函数/一个类,则不需要它。


15
投票
if (defined('FLAG_FROM_A_PARENT'))
// Works in all scenarios but I personally dislike this

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 break on Windows due to mixed DIRECTORY_SEPARATOR

if (basename(__FILE__) == basename($_SERVER['SCRIPT_FILENAME']))
// Doesn't work with files with the same basename but different paths

if (realpath(__FILE__) == realpath($_SERVER['DOCUMENT_ROOT'].$_SERVER['SCRIPT_NAME']))
// Seems to do the trick

12
投票

不要在文件中使用任何全局代码,仅使用函数和方法。那么就不需要关心包含与直接使用。


8
投票

只需将文件存储在网络根目录之外。


7
投票
if (__FILE__ == $_SERVER['DOCUMENT_ROOT'].$_SERVER['PHP_SELF']){
  die("Direct access forbidden");
}

无论在哪里它都可以工作。 (为@col-sharpnel 指出一个不完整但很好的解决方案干杯。)


5
投票

get_included_files 函数。你可以像这样使用它:

if ( empty(get_included_files()) ) die("Direct access forbidden");

2
投票

在 Apache 下,这很简单:在 .htaccess 中添加

<Files>
指令以防止从 Web 浏览器访问它。这不适用于 PHP
includes
,隐藏多个文件以防止浏览器访问是一个很好的做法(尽管通常您会尝试将所有不可访问的文件放在一个目录中)。

<Files="myprivatefile.php">
    deny from all
</Files>

在不同的网络服务器下,您可以将文件隐藏在文档根目录之外,但在某些情况下(例如,如果您的脚本以严格的方式

open_basedir
),它将不起作用。


2
投票

检查有多少包含文件...

if(count(get_required_files()) < 2) { die(); }

或者最少应该有多少个而不是 2


1
投票

我会选择Chacha102的解决方案

此外,正如您的问题标题所示“如何检查”,您也可以执行此操作,而无需使用

定义变量
// secret.php is the name of this file.
if($_SERVER["SCRIPT_FILENAME"]=='secret.php') die();

1
投票

如果您想阻止它在未包含时显示,这里有一种更自动化的方法。

if (basename(__FILE__) == basename($_SERVER['PHP_SELF'])) header("HTTP/1.0 404 Not Found");

这样,如果您最终更改了文件名或其他内容,它仍然可以工作。


1
投票
if($argv[0] == basename(__FILE__))
    include_once('/path/to/file.php');

1
投票

这个帖子中有很多很好的答案 - 这是一个尚未提及的答案。

您可以在扩展名中使用

i
来命名包含的 PHP 文件,例如
someincludedfile.phpi
,然后配置 Apache,使其不提供
phpi
文件。瞧。

缺点:

  • (!) 高度依赖 Apache 配置(因此,如果有人忽略该行,您就很容易受到攻击)——在这种情况下,浏览器可能会以纯文本形式看到整个 PHP 脚本,因为它不会被忽略到 PHP(真的很糟糕!)
  • 重命名包含的文件可能很烦人

优点:

  • 清楚地表明哪些文件要包含在代码中,哪些文件不包含在代码中
  • 您不必移动文件层次结构

就我个人而言,我宁愿将文件移动到文档根目录之外的目录中,但如果您有大型旧应用程序,则更改速度可能会更快。

链接:http://www.ducea.com/2006/07/21/apache-tips-tricks-deny-access-to-certain-file-types/


0
投票

只是为了扩展带有

$_SERVER
变量的解决方案 - 下面是一个小的 .php 文件,注释中是我在 Ubuntu 上进行的
bash
测试的副本;重点是,这些变量可能会根据访问类型以及是否使用符号链接而发生很大变化(另请注意,在下面的代码中,我必须转义 echo 语句中的“
?\>
”,否则语法颜色中断;如果尝试代码,请删除反斜杠
):

<?php

function report($label, $value) {
  printf ("%23s: %s\n", $label, $value);
}

report("DOCUMENT_ROOT.PHP_SELF",  $_SERVER['DOCUMENT_ROOT'].$_SERVER['PHP_SELF'] );
report("SCRIPT_FILENAME",         $_SERVER['SCRIPT_FILENAME'] );
report("__FILE__",                __FILE__ );
report("PHP_SAPI",                PHP_SAPI );

/*
# the test (bash):

home~$ mkdir /tmp/ptest
home~$ cd /tmp/ptest/
ptest$ ln -s /real/path/to/varcheck.php .
ptest$ echo '<? require_once "varcheck.php"; ?\>' > varcheckincl.php


# ... and in a separate terminal, run
# php (>5.4) cli server at same (/tmp/ptest) location:

ptest$ php-5.4.10 -S localhost:8000

# back to first terminal, the test - and output:

ptest$ php varcheck.php
 DOCUMENT_ROOT.PHP_SELF: varcheck.php
        SCRIPT_FILENAME: varcheck.php
               __FILE__: /real/path/to/varcheck.php
               PHP_SAPI: cli

ptest$ php -r 'require_once "varcheck.php";'
 DOCUMENT_ROOT.PHP_SELF: -
        SCRIPT_FILENAME:
               __FILE__: /real/path/to/varcheck.php
               PHP_SAPI: cli

ptest$ php varcheckincl.php
 DOCUMENT_ROOT.PHP_SELF: varcheckincl.php
        SCRIPT_FILENAME: varcheckincl.php
               __FILE__: /real/path/to/varcheck.php
               PHP_SAPI: cli

ptest$ wget http://localhost:8000/varcheck.php -q -O -
 DOCUMENT_ROOT.PHP_SELF: /tmp/ptest/varcheck.php
        SCRIPT_FILENAME: /tmp/ptest/varcheck.php
               __FILE__: /real/path/to/varcheck.php
               PHP_SAPI: cli-server

ptest$ wget http://localhost:8000/varcheckincl.php -q -O -
 DOCUMENT_ROOT.PHP_SELF: /tmp/ptest/varcheckincl.php
        SCRIPT_FILENAME: /tmp/ptest/varcheckincl.php
               __FILE__: /real/path/to/varcheck.php
               PHP_SAPI: cli-server
*/
?>

0
投票

基于@HelpNeeder 的帖子。无论目录或上下文如何,都可以工作。

// if we called this file directly, then we are using stdout
if (get_included_files()[0] === __FILE__) {

    /** @noinspection PhpUnhandledExceptionInspection */
    print json_encode($deploymentMatrix, JSON_THROW_ON_ERROR);

} else {

    return $deploymentMatrix;

}
© www.soinside.com 2019 - 2024. All rights reserved.