File Lister
PHP Code Examples
[Download]
<?php

// This lists the indicated file, in one of various styles.

include("leccode/util.inc");

// Expand tabs.  There has got to be standard version of this, but I can't 
// find it.
function expand($st)
{
	$ret = '';
	while($st != '') {
		$ch = $st[0];
		$st = substr($st,1);
		if($ch == '\t')
			$ret .= substr('        ', strlen($ret) % 8);
		else
			$ret .= $ch;
	}

	return $ret;
}

// Substitute password in pg_connect statement.
function depass($line)
{
	return preg_replace('/(pg_connect\s*\(' .
			    '[^(]*password\s*=\s*)([a-zA-Z0-9_\-+=@%&]*)/',
			    '$1XXXX', $line);
}

$fn = $_SERVER['PATH_INFO'];
if(! $fn)
	whap('No file specified', "You must specify a file to list");

// Check that the file name form 
while($fn[0] == '/') $fn = substr($fn,1);
if($fn[0] == '.' || strstr($fn, '..') || 
   strlen($fn) != strcspn($fn,'"\?*:@|<>`~'."'"))
	whap('Illegal File name', "The file name $fn is not allowed.");

// Get the permission file to see if we will allow this listing.
$blk = @fopen('.listperm', 'r');
if(!$blk)
	whap('No Permission File', 'The script is unable to open the  '.
	     'listing permission file.  This is a sever-side error.');

// Now see if there is an entry which allows the listing.
$grant = 0;
$localonly = 0;
while(! feof($blk)) {
	// Read a line and skip blanks and anything not starting with + or -.
	$bfn = trim(fgets($blk, 1024));
	if(strlen($bfn) == 0 || ($bfn[0] != '+' && 
				 $bfn[0] != '-' && $bfn[0] != '@')) 
		continue;

	// Extract the first character.
	$sign = $bfn[0];
	$bfn = substr($bfn, 1);
	if(strlen($bfn) < 1) continue;

	// See if we have a match.
	if($fn == $bfn || ($bfn[strlen($bfn)-1] == '/' && 
			   strpos($fn, $bfn) === 0)) {
		$grant = ($sign != '-');
		$localonly = ($sign == '@');
		break;
	}
}
fclose($blk);

if(!$grant)
	whap('Forbidden File', "The file $fn may not be listed.");
if($localonly) {
	list($first) = explode('.', $_SERVER["REMOTE_ADDR"]);
	if($first != '10') 
		whap('Local Only', "The file $fn is local access only.");
}

// The request can indicate the display type of a correct response.  OTW,
// text/plain.
$type = 'plain';
if($_REQUEST['type']) $type = $_REQUEST['type'];

// Okay, see if we can open the file itself.
$tolist = @fopen($fn, 'r');
if(!$tolist)
	whap("Can't Read File", "Cannot read $fn.");

// Output the file.
if($type == 'fancy') {
	// Formated html page.
	$shortfn = strchr($fn, '/');
	if(! $shortfn) $shortfn = $fn;
	else $shortfn = substr($shortfn, 1);

	// Document title.
	$title = $shortfn;
	if($_REQUEST['title']) $title = htmlspecialchars($_REQUEST['title']);

	// Download link.
	$link = $_SERVER['SCRIPT_NAME'] . "/$fn?type=bin";

	if($_REQUEST['uplink'])
		start($title, $_REQUEST['uptitle'] ? 
		      		$_REQUEST['uptitle'] : $_REQUEST['uplink'],
		      $_REQUEST['uplink']);
	else
		start($title);
	echo <<<END
<div style="width: 100%; text-align: center;">[<a 
href="$link"><span class="ltxt">Download</span></a>]
END;
	if($_REQUEST['run']) {
		// Get the run parms from the request.
		$args = urldecode($_REQUEST['run']);
		if($args == 'Y') $args = '';
		else if($args[0] != '/') {
		    $args = str_ireplace(array('<','>','onerror'), '', $args);
			$args = "?$args";
        }

		// Get the run URL.
		$rurl = preg_replace('#dump.php$#', $fn,
				     $_SERVER['SCRIPT_NAME']);

		echo " &nbsp; [<a href=\"$rurl$args\">".
			'<span class="ltxt">Execute</span></a>]';
	}
	echo "</div><tt><pre>";
	while(! feof($tolist))
		echo htmlspecialchars(expand(depass(fgets($tolist, 1024))));
	echo "</pre></tt>";
	trats();
} else if($type == 'bin') {
	// Binary download.
	header("Content-type: text/plain");
	header('Content-Disposition: attachment; filename="' . 
	       basename($fn) . '"');
	while(! feof($tolist))
		echo depass(fgets($tolist, 1024));
} else if($type == 'plain') {
	// Plain text.
	header("Content-type: text/plain");
	while(! feof($tolist))
		echo expand(depass(fgets($tolist, 1024)));

}
fclose($tolist);
?>