Как узнать, вызван ли скрипт php через require_once ()?

У моего webapp есть buch модулей. Каждый модуль имеет «основной» 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'] но мне было интересно, есть ли какой-то элегантный способ сделать это.

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

Скажите, что ваш веб-каталог / 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, если она у вас не пустая, чтобы включить в нее свой каталог).

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

Я искал способ определить, был ли файл включен или вызван напрямую, все из файла. В какой-то момент в моих поисках я прошел через эту тему. Проверяя различные другие темы на этом и других сайтах и ​​страницах из руководства 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 (string $ path) – это функция, возвращающая конечный компонент имени пути, который в этом случае является именем файла. Вы могли бы также просто сравнить полный путь и имя файла, что было бы действительно лучше, на самом деле не обязательно использовать эту функцию, но он чувствует себя более чистым таким образом, jajaj.
    (basename (): http://php.net/manual/en/function.basename.php )

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

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

 // index.php define("LEGIT_REQUEST", true); // in each module if (!defined("LEGIT_REQUEST")) die ("This module cannot be called directly."); 

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

 # # Private directory # Order allow,deny Deny from all 

Общим методом является добавление этого в основной модуль (до включения)

 define('TEST', true); 

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

 if (!defined('TEST')) { die('Do not cheat.'); } 

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

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

global.php

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

module.php

 define("in_myscript", 1); include("global.php"); 

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

 <?php $inc = get_included_files(); if(basename(__FILE__) == basename($inc[0])) exit(); 

Как практика привычки, у меня есть консольный класс, созданный для отправки сообщений, ошибок и т. Д. Для консоли с FirePHP. Внутри метода write () метода класса Console у меня есть проверка, чтобы увидеть, есть ли $ _REQUEST [debug] == 1, таким образом я не подвергаю ошибки пользователям, если что-то появляется на производстве, и им нужно будет знать, что запрос переменная – это доступ к отладочной информации.

В верхней части каждого файла я добавляю:

 Console::debug('fileName.php is loaded.'); 

вот отрывок из него, чтобы дать вам правильную идею:

 class Console{ public static function write($msg,$msg_type='info',$msg_label=''){ if(isset($_REQUEST['debug']) && $_REQUEST['debug'] == 'PANCAKE!'){ ob_start(); switch($msg_type){ case 'info': FB::info($msg, $msg_label); break; case 'debug': FB::info($msg, 'DEBUG') break; ... } } } public static function debug($msg){ Console::write($msg, ''); } } 

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

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