This question already has answers here:
Check if a file was included or loaded
(12 answers)
Closed 2 years ago.
My webapp has a buch of modules. Each module has a 'main' php script which loads submodules based on a query sent to the main module:
//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>";
}
This main module deals with security and imports many resources all submodules need. The big problem shows up when a user asks for any of the submodules, bypassing all the security measures on the main module! My idea was to add a line on every submodule to test if it was being called directly and deny access or if its been called via another script, and continue. The least thing I would like to do is redo the security checking on every single file, since it does a bunch of query's to the database.
Does a php script know if its been called via a require_once() or a direct call ? I've been trying to implement some sort of $_SERVER['REQUEST_URI'] and $_SERVER['PHP_SELF'] pitfall but I was wondering if there was some sort of an elegant way of doing this.
I was looking for a way to determine if a file have been included or called directly, all from within the file. At some point in my quest I passed through this thread. Checking various other threads on this and other sites and pages from the PHP manual I got enlightened and came up with this piece of code:
if ( basename(__FILE__) == basename($_SERVER["SCRIPT_FILENAME"]) ) {
echo "called directly";
}
else {
echo "included/required"
}
In essence it compares if the name of the current file (the one that could be included) is the same as the file that is beeing executed.
EXPLANATION:
__FILE__ is a PHP magic constant that stores the full path and filename of the file, the beauty of it is that if the file has been included or required it still returns the full path and filename of such file (the included file).
(Magic Constants Manual: http://php.net/manual/en/language.constants.predefined.php)
$_SERVER["SCRIPT_FILENAME"] returns the absolute pathname of the currently executing script. As when a file is included/required it's not executed (just included) it returns the path name of the (let's say) "parent" file (the one that includs the other file and the one that gets executed).
basename(string $path) is a function that returns the trailing name component of path, that in this case is the file name. You could also just compare the full path and filename, that would be indeed better, it isn't really neceseary to use this function but it feels cleaner this way, jajaj.
(basename(): http://php.net/manual/en/function.basename.php)
I know it's a "bit" late to be answering the main question but I guessed that it could be useful to anyone who's on the same situation that I was and that also passes by.
One elegant way is putting all your files which should only be accessed via include outside the web directory.
Say your web directory is /foo/www/, make an include directory /foo/includes and set this in your 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);
Then nobody will be able to access your libraries directly.
There's a lot of other things you could do (test a global variable is set, use only classes in libraries, etc) but this one is the most secure one. Every file which is not in your DocumentRoot cannot be accessed via an url,. But that does not mean PHP cannot get access to this file (check as well your open_basedir configuration if you have it not empty, to allow your include dir in it).
The only file you really need in your web directory is what we call the bootstrap (index.php), with a nice rewrite rule or a nice url managment you can limit all your requests on the application to this file, this will be a good starting point for security.
One popular method to make sure modules are not called directly is defining a constant in the main script, and checking for that constant in the module.
// index.php
define("LEGIT_REQUEST", true);
// in each module
if (!defined("LEGIT_REQUEST"))
die ("This module cannot be called directly.");
For the sake of completeness, the other possibility is to move such files to a directory that's not publicly available. However, some control panels used by hosting providers make this impossible. In such case, if you are using Apache you can place an .htaccess file inside the directory:
#
# Private directory
#
Order allow,deny
Deny from all
A common technique is to add this to the main module (before the includes)
define('TEST', true);
and to add something like that at the first line of every submodule
if (!defined('TEST')) {
die('Do not cheat.');
}
An alternative to defining a constant and checking it is to simply put the files that index.php includes outside of the document root area. That way the user can't directly access them via your web server at all. This is also obviously the most secure way, in case your web server has a configuration error in future that eg. displays PHP files as plain text.
You can define('SOMETHING', null) in clientes.php and then check if (!defined('SOMETHING')) die; in the modules.
global.php
if(!defined("in_myscript"))
{
die("Direct access forbidden.");
}
module.php
define("in_myscript", 1);
include("global.php");
A generic way that works without having to define a constant or use htaccess or use a specific directory structure or depend on the $_SERVER array that could theoretically be modified is to start each include-only (no direct access) file with this code:
<?php $inc = get_included_files(); if(basename(__FILE__) == basename($inc[0])) exit();
As practice of habit I have a console class built to send messages, errors, etc. to console with FirePHP. Inside the Console class write() method I have a check to see if a $_REQUEST[debug] == 1, that way I'm not exposing errors to users if something pops up on production and they would have to know what the request variable is to access the debug information.
At the top of every file I add:
Console::debug('fileName.php is loaded.');
here is a snippit from it to give you the right idea:
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, '');
}
}
Short and simple (for CLI):
if (__FILE__ == realpath($argv[0]))
main();
Related
I am new to PHP and very likely I am using the incorrect approach because I am not used to think like a PHP programmer.
I have some files that include other files as dependencies, these files need to have global code that will be executed if $_POST contains certain values, something like this
if (isset($_POST["SomeValue"]))
{
/* code goes here */
}
All the files will contain this code section, each one it's own code of course.
The problem is that since the files can be included in another one of these files, then the code section I describe is executed in every included file, even when I post trhough AJAX and explicitly use the URL of the script I want to POST to.
I tried using the $_SERVER array to try and guess which script was used for the post request, and even though it worked because it was the right script, it was the same script for every included file.
Question is:
Is there a way to know if the file was included into another file so I can test for that and skip the code that only execute if $_POST contains the required values?
Note: The files are generated using a python script which itself uses a c library that scans a database for it's tables and constraints, the c library is mine as well as the python script, they work very well and if there is a fix for a single file, obviously it only needs to be performed to the python script.
I tell the reader (potential answerer) about this because I think it makes it clear that I don't need a solution that works over the already existant files, because they can be re-generated.
From the sounds of it you could make some improvements on your code structure to completely avoid this problem. However, with the information given a simple flag variable should do the trick:
if (!isset($postCodeExecuted) && isset($_POST["SomeValue"]))
{
/* code goes here */
$postCodeExecuted = true;
}
This variable will be set in the global namespace and therefore it will be available from everywhere.
I solved the problem by doing this
$caller = str_replace($_SERVER["DOCUMENT_ROOT"], "", __FILE__);
if ($_SERVER["REQUEST_METHOD"] === "POST" and $caller === $_SERVER["PHP_SELF"])
performThisAction();
I'm trying to make an interface for updating all instances of a WordPress plugin on a server that hosts 20+ WordPress sites. I've got everything working except for the fact that I have a loop with:
require_once($path.'/wp-load.php');
require_once($path.'/wp-admin/includes/admin.php');
require_once($path.'/wp-admin/includes/class-wp-upgrader.php');
where $path is equal to a website directory ($path changes with every iteration of my loop).
The reason I need to require the files this way is because wp-load.php includes (among other things) a file called wp-config.php, which defines things like the SQL database, which is different between each website.
TL&DR and stating my actual question:
Is there any way for me to do something like the following code?
require_once("dir1/a.php"); // define("VAR","dir1");
echo VAR; // displays "dir1"
unrequire_once("dir1/a.php");
require_once("dir2/a.php"); // define("VAR","dir2");
echo VAR; // displays "dir2"
Since you've mentioned this is an in-house tool, you could consider using runkit in order to remove the constant at runtime, allowing it to be redefined later: http://www.php.net/manual/en/function.runkit-constant-remove.php
Afraid not - even if you could, you wouldn't get the behaviour you're looking for because constants (define) can only be created once, and are like that for the rest of execution. They cannot be removed, or changed thereafter.
Unfortunately, you're going to have to re-architect your script (e.g. to use variables instead of constants).
Yes: fork the process. You can do something like:
foreach ($pathlist as $path) {
$pid = pcntl_fork();
if(!$pid) {
require_once($path.'/wp-load.php');
require_once($path.'/wp-admin/includes/admin.php');
break;
}
}
This will create a copy of your script for each $path in your list and gets around the require_once problem.
You need to "break" the loop if it's a child, as you only want the child process to run for its individual $path setting and not continue the loop itself!
as we know, return keyword will RETURN some value and exit current function. Mean, that this one used only inside some functions.
BUT, I saw some php-dev's use return keyword outside functions, even in index.php file (in root of web server). What is that mean???? By the way, maybe it's logical to require some file inside function, but this style isnt mine.
There's not much more to say than what the docs do.
About the common usage of return:
If called from within a function, the return statement immediately
ends execution of the current function, and returns its argument as
the value of the function call. return will also end the execution of
an eval() statement or script file.
About the less common usage:
If called from the global scope, then execution of the current script
file is ended. If the current script file was included or required,
then control is passed back to the calling file. Furthermore, if the
current script file was included, then the value given to return will
be returned as the value of the include call. If return is called from
within the main script file, then script execution ends. If the
current script file was named by the auto_prepend_file or
auto_append_file configuration options in php.ini, then that script
file's execution is ended.
Its documented somewhere within the manual
// myFile.php
return array( 'foo' => 'bar');
// somewhere else
$config = include 'myFile.php';
echo $config['foo'];
If you use return in the main scope php will leave the file inclusion and use the value as "return value" of the inclusion (include[_once](), require[_once]()).
BUT, I saw some php-dev's use return keyword outside functions, even
in index.php file (in root of web server). What is that mean???
You know the common purpose. But what you are asking is used to prevent code injection in php include files. Take a look at this post which explains it:
Prevent Code Injection in PHP include files
While discussing Coding Standards it was not long ago I argued against
adding ?> at the end of php files. But miqrogroove pointed to me an
interesting aspect why it actually can make sense to have it and an
additional return statement at the end of each file: That one (merely
the return statement) can prevent an attacker to append payload code
to existing PHP files, for example known include files. The
countermeasurement is pretty easy, just add a return statement at the
end of the file. It will end the include “subroutine”:
Example:
/* all the include file's php code */
return;
?>
I really have read the other articles that cover this subject. But I seem to be in a slightly different position. I'm not using modrewrite (other articles).
I would like to 'include' a webpage its a 'Joomla php' generated page inside a php script. I'd hoped to make additions on the 'fly' without altering the original script. So I was going to 'precomplete' elements of the page by parasing the page once it was included I hadent wanted to hack the original script. To the point I can't include the file and its not because the path is wrong -
so
include ("/home/public_html/index.php"); this would work
include ("/home/public_html/index.php?option=com_k2&view=item&task=add"); this would not!
I've tried a variety of alternates, in phrasing, I can't use the direct route "http:etc..." since its a current php version so must be a reference to the same server. I tried relative, these work without the ?option=com_k2&view=item&task=add
It may be the simple answer that 'options' or variables can be passed.
Or that the include can't be used to 'wait' for a page to be generated - i.e. it will only return the html.
I'm not the biggest of coders but I've done alot more than this and I thought this was so basic.
this would work include ("/home/public_html/index.php?option=com_k2&view=item&task=add"); this would not!
And it never will: You are mixing a filesystem path with GET parameters, which can be passed only through the web server (utilizing a http:// call... But that, in turn, won't run the PHP code the way you want.)
You could set the variables beforehand:
$option = "com_k2";
$view = "item";
$task = "add";
include the file the normal way:
include ("/home/public_html/index.php");
this is assuming that you have access to the file, and can change the script to expect variables instead of GET parameters.
It's functionality is so strong that I worry about its stability and performance.
What do you think?
UPDATE
What I'm doing is this:
$old_dir = getcwd();
chdir( dirname($included_file) );
include ( $included_file );
chdir( $old_dir );
Essentially it just does include ( $included_file );,but inside that $included_file it can't find 3.php which is in the same directory as itself is in,so I manually set the cwd and it works.But it would be nice if I find the reason why it can't find.As for why debug_backtrace is needed,it's because 3.php is included by another func,since the relative path doesn't work,it has to use debug_backtrace to get the including file path,finally using the absolute path as mentioned below.
It's not easy to reproduce,as the above code is in the context of a method,and much more..If no one else has met this kinda problem I'd like to just stop here,anyway,the cost is just the 3 extra lines,not a big deal.
debug_backtrace is relatively expensive in my experience, so you should be careful it is not used in loops (e.g. in a custom error handler that catches warnings or notices and performs a backtrace every time).
For any kind of error logging, I think it's pretty invaluable, and because it's going to be called only once, definitely not a performance problem. It is surely always good to include a backtrace in an error report.
I can't see why there would be any specific issues with this function's stability (i.e. calling it causing another crash), I've never heard of any problems. The only "gotcha" I can see is this note in the User Contributed Notes when using objects as function parameters that have no _toString method defined.
Of course, you should never output the results of a backtrace to the end user - that goes without saying.
Well, considering its name, I'm not sure I would use it as a "normal" part of my application -- even though I don't remember having read anything which said that it was either good nor bad.
I don't really know what you mean about "serious usage", but :
If you need that function for your application to work, it migh indicate some problem in your design
This function can be useful in an error-handler, when you want to log how/where an error happened : it will make the log files more useful, when it comes to tracking down the sources of errors
Though, not sure that "error logging" corresponds to your definition of serious usage ?
Ok, from my understanding, the problem is following
You've got a php file, let's call it "main.php". In "main.php" you're including "A.php" from some directory:
# in "main.php"
include '/some/dir/A.php';
A.php, in turn, includes 'B.php', which is in the same directory as A.php
# in "A.php"
include 'B.php';
the problem: since "/some/dir/" (where A and B reside) is not the current for "main.php", php does not see B.php from A.php
the solution: in A.php use an absolute full path to /some/dir. Either hardcode it or obtain it dynamically via dirname(__FILE__)
# in "A.php"
include dirname(__FILE__) .'/B.php';