Как проследить всю цепочку вызовов в скрипте РНР?
Допустим, у Вас на сервере есть масса скриптов PHP, установлен некий фреймворк, а то и не один. Зачастую, на сайтах, использующих фреймворки, запрос от клиента (например, из браузера) передается к файлу index.php. А вот из него уже – как говорится, во многие веси. И кто же его знает, в какой последовательности и какие конкретно файлы РНР используются при этом. Как это узнать? Рассмотрим несколько способов.
1. Вручную
Самый примитивный способ – это, да, вручную. Открываем каждый файл, смотрим, где там директивы типа include, require, затем открываем файлы, указанные в этих директивах и т.д. Однако, в современных фреймворках таких файлов бывает множество. Часть из них являются исполняемыми, а часть – содержат разные настройки, устанавливают параметры, задают классы и др. И если вручную перебирать их все – на это может быть затрачен не один рабочий день. Т.е. ручной способ можно применять, разве что, для очень небольших проектов.
2. Смотреть логи фреймворков
Многие (если не все) современные фреймрворки позволяют вести логи, т.е. записывают информацию о происходящих процессах в специальные файлы. По умолчанию, туда обычно пишется информация об ошибках, сбоях при работе скриптов РНР. Но, если установить самый подробный уровень логирования (info), то тогда в лог будет сохраняться вся основная информация, происходящая с момента получения клиентского запроса сервером и до момента отправки последнего сообщения сервера клиенту.
Однако, даже при подробном уровне логирования в логи все-таки не включается информация о ВСЕХ подключаемых в процессе обработки клиентского вызова файлах со скриптами РНР. Т.е. логи фреймворков хороши для получения общей информации об обработке вызова (по крайней мере, так обстоит дело с фреймворком laravel). А для детализации все же необходима более подробная информация.
3. Добавить небольшой код в index.php
Теперь рассмотрим, похоже, универсальный способ, который позволяет выяснить, какие файлы со скриптами PHP (с указанием полных путей, естественно) подключались в процессе обработки клиентского вызова.
Для этого следует использовать функцию get_included_files() .
Для наглядности, сразу рассмотрим практический пример. Пусть есть следующие четыре файла: test.php, t1.php, t2.php, t3.php
Получить имя вызываемого файла из include ()
Я хочу получить имя файла, который включает другой файл из встроенного файла.
Я знаю, что __FILE__ волшебная константа __FILE__ , но это не помогает, так как она возвращает имя включенного файла, а не включающего его.
Есть какой-либо способ сделать это? Или это невозможно из-за того, как интерпретируется PHP?
Это на самом деле просто частный случай того, что делают PHP-шаблоны. Рассмотрим эту функцию:
function ScopedInclude($file, $params = array())
Тогда A.php может включать C.php следующим образом:
Кроме того, B.php может включать C.php таким же образом без проблем.
C.php может знать его включение, просматривая массив $ params.
Так что этот вопрос довольно старый, но я искал ответ и, оставив здесь неудовлетворенный, наткнулся на $_SERVER[‘SCRIPT_FILENAME’]; Конечно, это работает, если файл php, делающий включение, является веб-страницей.
Это дает вам полный путь «включая файл» на сервере. например, /var/www/index.php. поэтому, если вы хотите просто имя файла, например index.php, вам нужно будет использовать basename (), например
Итак, если в вашем index.php у вас есть следующая строка:
и в некоторыхphp.php у вас есть
echo «this is the file that included me: » . basename($_SERVER[‘SCRIPT_FILENAME’]);
this is the file that included me: index.php
вывода в браузер. Это также работает, если пользователь обращается к вашему файлу без явного указания имени файла в URL-адресе, например www.example.com а не на www.example.com/index.php .
Я не могу найти простой способ охватить это. Но если включение одного действительно важно для вас, вы можете взломать его с помощью некоторой глобальной переменной и вашей собственной функции include.
Может быть, это полезно для вас 🙂
Решение
Зная, что функции, используемые для включения файлов, include , include_once , require и require_once , также зная, что они зарезервированные слова в PHP, что означает, что невозможно будет объявить пользовательские функции с тем же именем и на основе идеи wedgwood использовать debug_backtrace вы можете реально решить, из какого файла был вызван include.
То, что мы собираемся делать, это перебрать обратную линию до тех пор, пока мы не найдем самый последний вызов любой из четырех функций include и файла, где он был вызван. Следующий код демонстрирует технику:
function GetIncludingFile() < $file = false; $backtrace = debug_backtrace(); $include_functions = array('include', 'include_once', 'require', 'require_once'); for ($index = 0; $index < count($backtrace); $index++) < $function = $backtrace[$index]['function']; if (in_array($function, $include_functions)) < $file = $backtrace[$index]['file']; break; >> return $file; >
Вышеприведенный код вернет абсолютный путь к файлу, в котором произошло последнее включение, если оно не было включено, оно вернет false. Обратите внимание, что файл может быть включен из файла, который был включен из другого файла, указанная выше функция работает только для наиболее глубокого включения.
С помощью простой модификации вы также можете получить последний включенный файл:
function GetIncludedFile() < $file = false; $backtrace = debug_backtrace(); $include_functions = array('include', 'include_once', 'require', 'require_once'); for ($index = 0; $index < count($backtrace); $index++) < $function = $backtrace[$index]['function']; if (in_array($function, $include_functions)) < $file = $backtrace[$index - 1]['file']; break; >> return $file; >
наблюдения
Обратите внимание, что __FILE__ не является включенным файлом, а текущим файлом. Например:
В приведенном выше примере в контексте файла B.php включен файл B.php (и включенный файл – index.php), но вывод функции callme – это путь A.php, потому что __FILE__ находится в A .php.
Также обратите внимание, что $_SERVER[‘SCRIPT_FILENAME’] предоставит абсолютный путь к скрипту, запрошенному клиентом. Если $_SERVER[‘SCRIPT_FILENAME’] == __FILE__ это означает, что текущий файл является запрошенным, и, следовательно, в нем, вероятно , не было никаких …
Вышеупомянутый метод проверяет, является ли текущий файл запрошенным, но не был ли он включен (ниже приведен пример того, как можно включить запрошенный файл). Фактическое решение проверить, не было ли каких-либо включений, может быть проверка count(get_included_files()) == 1 .
Запрошенный файл может быть включенным файлом следующим образом:
echo 'something'; ?>
вecho 'something'; ?>
В приведенном выше примере файл index.php будет включать в себя x.php, затем x.php будет включать index.php назад, впоследствии index.php выводит «что-то» и возвращает управление x.php, x.php возвращает управление индексу .php и достигает выхода;
Это показывает, что даже если index.php был запрошенным скриптом, он также был включен из другого сценария.
php: определить, откуда была вызвана функция
есть ли способ узнать, откуда была вызвана функция в PHP? пример:
function epic() < fail(); >function fail() < //at this point, how do i know, that epic() has called this function? >
Вы можете использовать debug_backtrace() .
function fail( $string ) < $backtrace = debug_backtrace(); print_r( $backtrace ); >epic( 'Hello', 'World' );
Array ( [0] => Array ( [file] => /Users/romac/Desktop/test.php [line] => 5 [function] => fail [args] => Array ( [0] => Hello World ) ) [1] => Array ( [file] => /Users/romac/Desktop/test.php [line] => 15 [function] => epic [args] => Array ( [0] => Hello [1] => World ) ) )
Так что, если вы все еще ДЕЙСТВИТЕЛЬНО не знаете, как это, а вот решение:
$backtrace = debug_backtrace(); echo 'Mu name is '.$backtrace[1]['function'].', and I have called him! Muahahah!';
Самое быстрое и простое решение, которое я нашел
public function func() < //function whose call file you want to find $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); >$trace: Array ( [0] => Array ( [file] => C:\wamp\www\index.php [line] => 56 [function] => func [class] => (func Class namespace) [type] => -> ) )
Я тестирую скорость на ноутбуке Lenovo: процессор Intel Pentium N3530 2,16 ГГц, оперативная память 8 ГБ
global $times; $start = microtime(true); $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); $times[] = microtime(true) - $start;
count($times): 97 min: 2.6941299438477E-5 max: 10.68115234375E-5 avg: 3.3095939872191E-5 median: 3.0517578125E-5 sum: 321.03061676025E-5 the same results with notation without E-5 count($times): 97 min: 0.000026941299438477 max: 0.0001068115234375 avg: 0.000033095939872191 median: 0.000030517578125 sum: 0.0032103061676025
Попробуйте ввести код ниже.
foreach(debug_backtrace() as $t) < echo $t['file'] . ' line ' . $t['line'] . ' calls ' . $t['function'] . "()
"; >
function findFunction($function, $inputDirectory="") < //version 0.1 $docRoot = getenv("DOCUMENT_ROOT"); $folderArray = null; $dirArray = null; // open directory $directory = opendir($docRoot.$inputDirectory); // get each entry while($entryName = readdir($directory)) < if(is_dir($entryName) && $entryName != "." && $entryName != "..")< $folderArray[] = str_replace($inputDirectory, "", $entryName); >$ext = explode(".", $entryName); if(!empty($ext[1])) < $dirArray[] = $docRoot.$inputDirectory."/".$entryName; >> // close directory closedir($directory); $found = false; if(is_array($dirArray))< foreach($dirArray as $current)< $myFile = file_get_contents($current); $myFile = str_replace("", "", $myFile); if(preg_match("/function ".$function."/", $myFile)) < $found = true; $foundLocation = $current; break; >> > if($found) < echo $foundLocation; exit; >else if(is_array($folderArray)) < foreach($folderArray as $folder)< if(!isset($return))< $return = findFunction($function, $inputDirectory."/".$folder); >else if($return == false) < $return = findFunction($function, $inputDirectory."/".$folder); >> > else < return false; >> findFunction("testFunction", "rootDirectory");
Надеюсь, это поможет кому-то. Если фактическая функция находится за пределами httpdocs, она не может быть найдена, потому что сервер будет настроен так, чтобы не разрешать ее. Проверяли только одну папку, но рекурсивная методология должна работать теоретически.
Это похоже на версию 0.1, но я не намерен продолжать ее разработку, поэтому, если кто-то обновляет ее, он может перепроверить ее.
Php чем был вызван файл
Создание игр на Unreal Engine 5
Данный курс научит Вас созданию игр на Unreal Engine 5. Курс состоит из 12 модулей, в которых Вы с нуля освоите этот движок и сможете создавать самые разные игры.
В курсе Вы получите всю необходимую теоретическую часть, а также увидите массу практических примеров. Дополнительно, почти к каждому уроку идут упражнения для закрепления материала.
Помимо самого курса Вас ждёт ещё 8 бесплатных ценных Бонусов: «Chaos Destruction», «Разработка 2D-игры», «Динамическая смена дня и ночи», «Создание динамической погоды», «Создание искусственного интеллекта для NPC», «Создание игры под мобильные устройства», «Создание прототипа RPG с открытым миром» и и весь курс «Создание игр на Unreal Engine 4» (актуальный и в 5-й версии), включающий в себя ещё десятки часов видеоуроков.
Подпишитесь на мой канал на YouTube, где я регулярно публикую новые видео.
Подписаться
Подписавшись по E-mail, Вы будете получать уведомления о новых статьях.
Подписаться
Добавляйтесь ко мне в друзья ВКонтакте! Отзывы о сайте и обо мне оставляйте в моей группе.
Мой аккаунт Моя группа