Как узнать, вызывается ли php-скрипт через require_once ()? - PullRequest
2 голосов
/ 28 декабря 2010

В моем веб-приложении есть набор модулей.У каждого модуля есть «основной» php-скрипт, который загружает подмодули на основе запроса, отправленного главному модулю:

//file: clientes.php

//check for valid user...
//import CSS and JS...

switch( $_GET["action"] )
{
    case "lista" :          require_once("clientes.lista.php"); break;
    case "listaDeudores" :  require_once("clientes.listaDeudores.php"); break;
    case "nuevo" :          require_once("clientes.nuevo.php"); break;
    case "detalles" :       require_once("clientes.detalles.php"); break;
    case "editar" :         require_once("clientes.editar.php"); break;         
    default : echo "<h1>Error</h1><p>El sitio ha encontrado un error.</p>";
} 

Этот основной модуль имеет дело с безопасностью и импортирует много ресурсов, необходимых всем подмодулям.Большая проблема проявляется, когда пользователь запрашивает любой из подмодулей, минуя все меры безопасности на главном модуле!Моя идея состояла в том, чтобы добавить строку в каждый подмодуль, чтобы проверить, вызывается ли он напрямую и запретить доступ, или он вызывался через другой скрипт, и продолжить.Меньшее, что я хотел бы сделать, это повторить проверку безопасности для каждого отдельного файла, поскольку он выполняет несколько запросов к базе данных.

Знает ли скрипт php, был ли он вызван с помощью require_once() илипрямой звонок?Я пытался реализовать какую-то ловушку $_SERVER['REQUEST_URI'] и $_SERVER['PHP_SELF'], но мне было интересно, есть ли какой-нибудь элегантный способ сделать это.

Ответы [ 11 ]

17 голосов
/ 29 августа 2011

Я искал способ определить, был ли файл включен или вызван напрямую из файла. В какой-то момент моего квеста я прошел через эту ветку. Проверяя различные другие темы на этом и других сайтах и ​​страницах из руководства по PHP, я понял, что такое код:

if ( basename(__FILE__) == basename($_SERVER["SCRIPT_FILENAME"]) ) {
  echo "called directly";
}

else {
  echo "included/required"
}

По сути, он сравнивает, совпадает ли имя текущего файла (которое может быть включено) с исполняемым файлом.


ПОЯСНЕНИЯ:

  • __ FILE__ - это магическая константа PHP, которая хранит полный путь и имя файла файла, прелесть этого в том, что, если файл был включен или требуется, он по-прежнему возвращает полный путь и имя файла такого файла ( включенный файл).
    (Руководство по магическим константам: http://php.net/manual/en/language.constants.predefined.php)

  • $ _ SERVER ["SCRIPT_FILENAME"] возвращает абсолютный путь к исполняемому в данный момент сценарию. Так как когда файл включен / требуется, он не выполняется (просто включается), он возвращает имя пути (скажем, «родительского» файла (тот, который включает в себя другой файл, и тот, который исполняется).

  • basename (строка $ path) - это функция, которая возвращает завершающий компонент имени пути, который в данном случае является именем файла. Вы также можете просто сравнить полный путь и имя файла, это было бы действительно лучше, использовать эту функцию на самом деле не обязательно, но при этом она кажется чище, jajaj.
    (базовое имя (): http://php.net/manual/en/function.basename.php)

Я знаю, что "немного" поздно отвечать на главный вопрос, но я догадался, что это может быть полезно всем, кто находится в той же ситуации, что и я, и это также проходит мимо.

13 голосов
/ 28 декабря 2010

Одним из элегантных способов является размещение всех ваших файлов, доступ к которым возможен только через include , вне веб-каталога .

Скажите, что ваш веб-каталог - / foo / www /, создайте каталог включения / foo / includes и установите его в своем include_path:

$root = '/foo';
$webroot = $root.'/www'; // in case you need it on day
$lib = $root.'/includes';
// this add your library at the end of the current include_path
set_include_path(get_include_path() . PATH_SEPARATOR . $lib); 

Тогда никто не сможет получить доступ к вашим библиотекам напрямую.

Есть много других вещей, которые вы могли бы сделать (проверить, установлена ​​ли глобальная переменная, использовать только классы в библиотеках и т. Д.), Но этот является наиболее безопасным. Каждый файл, который не находится в вашем DocumentRoot, не может быть доступен через URL. Но это не означает, что PHP не может получить доступ к этому файлу (также проверьте свою конфигурацию open_basedir, если она у вас не пустая, чтобы разрешить включение в нее директории включения).

Единственный файл, который вам действительно нужен в вашем веб-каталоге, это то, что мы называем начальной загрузкой (index.php), с хорошим правилом перезаписи или хорошим управлением URL, вы можете ограничить все ваши запросы в приложении этим файлом, это будет быть хорошей отправной точкой для безопасности.

6 голосов
/ 28 декабря 2010

Один из популярных способов убедиться, что модули не вызываются напрямую, - это определение константы в основном скрипте и проверка этой константы в модуле.

// index.php
define("LEGIT_REQUEST", true);

// in each module
if (!defined("LEGIT_REQUEST")) 
  die ("This module cannot be called directly.");
5 голосов
/ 28 декабря 2010

Ради полноты, другая возможность состоит в том, чтобы переместить такие файлы в каталог, который не является общедоступным. Однако некоторые панели управления, используемые хостинг-провайдерами, делают это невозможным. В таком случае, если вы используете Apache, вы можете поместить файл .htaccess в каталог:

#
# Private directory
#
Order allow,deny
Deny from all
4 голосов
/ 28 декабря 2010

Обычный метод - добавить это в основной модуль (перед включением)

define('TEST', true);

и добавить что-то подобное в первой строке каждого подмодуля

if (!defined('TEST')) {
    die('Do not cheat.');
}
3 голосов
/ 28 декабря 2010

Альтернатива определению константы и ее проверке заключается в простом размещении файлов, которые index.php включает за пределы корневой области документа.Таким образом, пользователь вообще не сможет получить к ним прямой доступ через ваш веб-сервер.Это также очевидно самый безопасный способ, в случае, если ваш веб-сервер будет иметь ошибку конфигурации в будущем, например,.отображает файлы PHP в виде простого текста.

1 голос
/ 22 марта 2014

Общий способ, который работает без необходимости определять константу или использовать htaccess, использовать определенную структуру каталогов или зависеть от массива $ _SERVER, который теоретически может быть изменен, состоит в том, чтобы запустить каждый файл «только для включения» (без прямого доступа) с этим код:

<?php $inc = get_included_files(); if(basename(__FILE__) == basename($inc[0])) exit();
1 голос
/ 28 декабря 2010

global.php

if(!defined("in_myscript"))
{
    die("Direct access forbidden.");
}

module.php

define("in_myscript", 1);
include("global.php");
1 голос
/ 28 декабря 2010

Вы можете define('SOMETHING', null) в clientes.php, а затем проверить if (!defined('SOMETHING')) die; в модулях.

0 голосов
/ 20 января 2015

Коротко и просто (для CLI):

if (__FILE__ == realpath($argv[0]))
    main();
...