I am making a basic PHP source viewer for my blog's example code folder.
<?php
if (isset($_GET['file']))
{
header('Content-type: text/plain');
$filename = realpath($_GET['file']);
if (startsWith($filename, dirname(__FILE__)))
{
echo file_get_contents($filename);
}
}
function startsWith($haystack, $needle)
{
$length = strlen($needle);
return (substr($haystack, 0, $length) === $needle);
}
?>
Is what I have here sufficient that it will never allow a file outside the directory in which this script is located, or subdirectories of this script's directory, to be viewed? I'm guessing there's a better solution than startsWith too, for checking whether a path is a descendant of a particular directory?
It's going to be safe, yes. The
realpath
part is what you have to do, and you are doing it. This code does what it's supposed to just fine.As an aside, look into using strncmp instead of your custom startsWith function.
You maybe reduce the input to a filename (see finfo) and specify the directory to search in, if it's the same directory every time - so you don't need to check via
startsWith()
.If you only want to show PHP-sourcecode, try to enable *.phps-file-handling within your webserver. See: https://serverfault.com/questions/62410/apache-htaccess-phps
If I was to approach a project like this I would:
Use a combination of your solution & htaccess to mask the original filename as having:
http://example.com/viewsource.php?file=./project1/index.php
would be just too obvious and tempting to mess around with, using htaccess you could have:
http://example.com/source/project1/index.php
that points too
h1ddEnfIlEs/viewSource/index.php?file=$1&folder=$2
Then with the source viewer h1ddEnfIlEs/viewSourceScript/index.php