Solution
Knowing that the functions used to include files are include
, include_once
, require
and require_once
, also knowing that they are reserved words in PHP, meaning that it will not be possible to declare user functions with the same name, and based on wedgwood's idea of using debug_backtrace
you can actually work out from what file the include was called.
What we are going to do is iterate over the backtrace untill we find the most recent call to any of the four include functions, and the the file where it was called. The following code demostrate the technique:
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;
}
The above code will return the absolute path of the file where the last include happened, if there hasn't been any include it will return false. Note that the file may has been include from a file that was included from another file, the above function only works for the deepest include.
With a simple modification, you can also get the last included file:
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;
}
Observations
Note that __FILE__
is not the included file, but the current file. For example:
file A.php:
<?php
function callme()
{
echo __FILE__;
}
?>
file B.php:
<?php
include('A.php');
callme();
?>
file index.php:
<?php
include('B.php');
?>
In the above example, in the context of the file B.php the included file is B.php (and the including file is index.php) but the output of the function callme
is the path of A.php because __FILE__
is in A.php.
Also note that $_SERVER['SCRIPT_FILENAME']
will give the the absolute path to the script requested by the client. If $_SERVER['SCRIPT_FILENAME'] == __FILE__
it means that the current file is the requested one, and therefore there probably hasn't been any includes...
The above method checks if the current file is the requested one, but not if it hasn't been included (below is an example of how the requested file can be included). An actual solution to check if there has not been any inclusions could be to check count(get_included_files()) == 1
.
The requested file can be an included file in the following way:
file x.php
<?php
$var = 'something';
include('index.php');
?>
file index.php
<?php
if (!isset($var))
{
include('x.php');
exit;
}
echo 'something';
?>
In the above example, the file index.php will include x.php, then x.php will include index.php back, afterwards index.php outputs "something" and returns control to x.php, x.php returns control to index.php and it reaches exit;
This shows that even if index.php was the requested script, it was also included from another script.