views:

294

answers:

3

I've recently gotten an error when I deployed an application. It used "is_readable" on a path within the include path, but one that was restricted by "open_basedir". This gave me a fatal error. Is there another function that I could use to see if a file is includable, before actually including it?


Edit: this works, but how do I detect if the error was because the include failed or because of some error inside the included file?

try {
 include 'somefile.php';
 $included = true; 
} catch (Exception $e) {
 // Code to run if it didn't work out
 $included = false;
}
A: 

You can check the value of the open_basedir rescriction (if set) using

ini_get( 'open_basedir' );

It will return the allowed path(s) or an empty string if not set.

Edit:

Checking the include path in a open_basedir restriction safe way could go something like this:

if ( strlen( ini_get( 'open_basedir' ) ) > 0 )
{
    $includeFile = 'yourInclude.php';
    $includePath = dirname( realpath( $includeFile ) );

    $baseDirs = explode( PATH_SEPARATOR, ini_get( 'open_basedir' ) );
    foreach ( $baseDirs as $dir )
    {
     if ( strstr( $includePath, $dir ) && is_readable( $includeFile ) )
     {
      include $includeFile;
     }
    }
}

But feel free to improve upon this if you see a shortcut.

Polygraf
Yes, but that does tell me if a file is includable, since you can sometimes do that even with files that are outside the basedir, right?
Bart van Heukelom
The way the basedir restriction works (from my understanding) is that all files above each basedir should be at least accessible, so you would need to check if the file you're trying to include is within your basedirs, once that's done you can use is_readable without a fatal error. I'm just on my way out of the office, I can post a proper example later on if you need further help.
Polygraf
+1  A: 

You could 'try' this ;)

<?php

function exceptions_error_handler($severity, $message, $filename, $lineno) {
    throw new ErrorException($message, 0, $severity, $filename, $lineno);
}
set_error_handler('exceptions_error_handler');
try {
    include 'somefile.php';
    $included = true;
} catch (Exception $e) {
    // Code to run if it didn't work out
    $included = false;
}
echo 'File has ' . ($included ? '' : 'not ') . 'been included.';
?>

If it doesn't work, $included will be set to true, and then to false in the catch. If it did work, $included remains true.

James Hall
Nice try :p, but a false include does not throw an exception but a classic error.
Bart van Heukelom
Ahh yes. I once used an error handler that threw PHP errors into exceptions. function exceptions_error_handler($severity, $message, $filename, $lineno) { throw new ErrorException($message, 0, $severity, $filename, $lineno);}set_error_handler('exceptions_error_handler');No idea if that's a good idea though.
James Hall
Infact, the framework I use throws all standard PHP errors as exceptions.
James Hall
My framework (to which this question applies) does that as well. I thought that the error wouldn't be catchable, but of course, it is.
Bart van Heukelom
A: 

You could try using stat to achieve the same effect as is_readable which I hear is very buggy when base dir is set.

Neel
The buggy behaviour of is_readable has been fixed as of PHP 5.2. For older versions it is indeed preferable to use stat
Polygraf