Can an included file 'know' where it's been included?
I have a fairly straightforward problem. I work for a University's IT department. Long story short, we have a lot of PHP content providers who don't know what they're doing and have had several major security breaches due to bad file uploading code. We want to write a function as an include to handle all uses of move_uploaded_file with proper data sanitisation and security measures.
Due to the way we distribute authority/responsibility for content at the University, we need our code to know where it is being called from so we can look up directory permissions and match them to the target directory. We need a foolproof way of determining where the function is being included from.
I tried wrapping the function in an object with a constructor that remembers the value of PHP_SELF, but that returned an empty string.
So, to wrap it up: is there any way to get the path to the including page in the code on the included one? Sadly, we are stuck with PHP 4.4.0 for now, so PHP5-only solutions won't do the trick (if the only way to do it is with PHP5, that would still be quite valuable to know).
I apologise if this is not really an 'advanced' question, but a lot of time on PHP.net yielded nothing and I figure the readers of this board have the best chance of knowing some obscure trick.
So just to clarify, what you're asking of is to interrupt the call to the function move_uploaded_files, and to essentially call another function prior to calling move_uploaded_files -- and then passing that sanitised data to move_uploaded_files?
Edit: There is $_SERVER['REQUEST_URI'], but that merely gets the root file that's being accessed, it's not the magical item you're looking for that knows the included file's parent.
The man who comes back through the Door in the Wall will never be quite the same as the man who went out.
I set up a test of your code: a main page with nothing but require()s, and a bunch of includes, one of which with your code verbatim and the others all empty. When I only had the include with your code required by the parent, the code worked, but when I threw a bunch of empty includes before and after the 'real' include, it started reporting paths to other includes and not the real parent.
Based on my limited understanding of what your code does, it looks like the problem is this line:
return $aIncluded[$iKey - 1];
My test setup right now looks like this (the common portion of the test files' path was replaced here with $path; it's a literal string in the actual code):
main page (the one being requested via http):
b.php, bb.php and bbb.php are all identical:
//nothing to see here...
a.php is a copy-paste of your code.
The result: Included parent: $path/aa/bb.php
It seems like this should be a recursive call somehow, but I'm not sure how to make it work. I tried this on a whim, but it failed as well:
If I move around the requires, your code consistently returns the require immediately before the one with the code in it, unless it's first in which case it returns the correct parent.
I did a little playing around, and it seems like the parent is always at index 0. Are there cases in which this would not be the case? I don't have time right now to try anything too complex, but adding/moving/removing things seemed to have no effect. The include running the code always sees itself as last. It looks like it stores the files in the order they are called, so first the parent, then the first include, then that include's first include, etc. If this is the case, can't I just do something like:
$x = get_included_files();
$parent = $x;
I assume there's a reason this wouldn't always work, which is why you tried a more complex method, but might it be easier to check for those exceptions and use this method in all other cases? You can't get much more efficient than that (unless you can somehow eliminate the get_included_files call, of course, but that seems to be the function that makes any of this even possible...).
Oh, by the way, in case anyone is still unclear: we're not trying to interrupt calls to move_uploaded_file. We've blocked uploads of PHP containing that function using RATS and our own deployment software; instead, we plan to provide an include that our content providers can call instead. It will basically provide a secure wrapper for move_uploaded_file; it will perform all the security checks on the data that we feel are necessary, since we don't trust many of our content providers to write secure PHP. We also want to be able to monitor and control uploads more tightly as issues arise in the future, so routing them all through a piece of code we control would be quite handy.