<?php
// Robust PHP File Browser - improved version

ini_set('display_errors', 1);
error_reporting(E_ALL);

// Base directory (where index.php is located)
$baseDir = realpath(__DIR__);
if ($baseDir === false) {
    die("Fatal: cannot determine base directory.");
}

// Helper to normalize path (always with directory separator)
function join_path(...$parts) {
    return preg_replace('#/+#','/', str_replace('\\','/', implode('/', $parts)));
}

// requested path relative to base (URL encoded)
$requested = isset($_GET['path']) ? $_GET['path'] : '';
$requested = trim($requested, "/\\"); // remove leading/trailing slashes

// compute absolute target path safely
if ($requested === '') {
    $target = $baseDir;
} else {
    $candidate = join_path($baseDir, $requested);
    $candidateReal = realpath($candidate);
    // If realpath fails or candidate is outside baseDir, fallback to baseDir
    if ($candidateReal === false || strpos($candidateReal, $baseDir) !== 0) {
        $target = $baseDir;
    } else {
        $target = $candidateReal;
    }
}

// If target is a file (someone requested a file path without download param),
// set target to its directory so we can list siblings
if (!is_dir($target)) {
    $target = dirname($target);
}

// scandir
$files = @scandir($target);
if ($files === false) {
    $error = "Unable to read directory: " . htmlspecialchars($target);
    $files = [];
} else {
    $error = null;
}

// Download handling
if (isset($_GET['download'])) {
    $downloadRel = $_GET['download'];
    $downloadRel = trim($downloadRel, "/\\");
    $filePath = realpath(join_path($baseDir, $downloadRel));
    if ($filePath && is_file($filePath) && strpos($filePath, $baseDir) === 0) {
        // Send file
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="' . basename($filePath) . '"');
        header('Content-Length: ' . filesize($filePath));
        readfile($filePath);
        exit;
    } else {
        $error = "File not found or access denied.";
    }
}

// Helpers for links
function relPath($abs, $base) {
    $rel = str_replace($base, '', $abs);
    $rel = ltrim(str_replace('\\','/',$rel), '/');
    return $rel;
}

$currentRel = relPath($target, $baseDir);
if ($currentRel === '') $currentRel = '/';
?>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>File Browser - <?php echo htmlspecialchars($currentRel); ?></title>
<style>
    body { font-family: Arial, Helvetica, sans-serif; padding: 20px; }
    table { width:100%; border-collapse: collapse; margin-top: 12px; }
    th, td { padding:8px; border:1px solid #ddd; text-align:left; }
    tr:hover { background:#f7f7f7; }
    a { color:#0366d6; text-decoration:none; }
    .meta { color:#666; font-size:90%; }
    .error { background:#ffe6e6; padding:8px; border:1px solid #f5c2c2; color:#900; }
</style>
</head>
<body>
    <h2>📂 File Browser</h2>
    <p class="meta"><strong>Base:</strong> <?php echo htmlspecialchars($baseDir); ?> &nbsp; | &nbsp; <strong>Current:</strong> <?php echo htmlspecialchars($currentRel); ?></p>

    <?php if ($error): ?>
        <div class="error"><?php echo htmlspecialchars($error); ?></div>
    <?php endif; ?>

    <table>
        <thead>
            <tr><th>Name</th><th>Type</th><th>Size</th><th>Modified</th></tr>
        </thead>
        <tbody>
            <?php if ($target !== $baseDir): 
                $parent = dirname($target);
                $parentRel = relPath($parent, $baseDir);
                ?>
                <tr>
                    <td><a href="?path=<?php echo rawurlencode($parentRel); ?>">⬅️ .. (parent)</a></td>
                    <td>Directory</td>
                    <td>-</td>
                    <td>-</td>
                </tr>
            <?php endif; ?>

            <?php
            // Sort: directories first then files
            usort($files, function($a,$b) use($target){
                if ($a === '.' || $a === '..') return -1;
                if ($b === '.' || $b === '..') return 1;
                $pa = $target . DIRECTORY_SEPARATOR . $a;
                $pb = $target . DIRECTORY_SEPARATOR . $b;
                if (is_dir($pa) && !is_dir($pb)) return -1;
                if (!is_dir($pa) && is_dir($pb)) return 1;
                return strcasecmp($a,$b);
            });

            foreach ($files as $file):
                if ($file === '.' || $file === '..') continue;
                $full = $target . DIRECTORY_SEPARATOR . $file;
                $relative = relPath($full, $baseDir);
                $displayRel = $relative === '' ? $file : $relative;
            ?>
            <tr>
                <td>
                    <?php if (is_dir($full)): ?>
                        📂 <a href="?path=<?php echo rawurlencode($relative); ?>"><?php echo htmlspecialchars($file); ?></a>
                    <?php else: ?>
                        📄 <a href="?download=<?php echo rawurlencode($relative); ?>"><?php echo htmlspecialchars($file); ?></a>
                    <?php endif; ?>
                </td>
                <td><?php echo is_dir($full) ? 'Directory' : 'File'; ?></td>
                <td><?php echo is_file($full) ? number_format(filesize($full)) . ' bytes' : '-'; ?></td>
                <td><?php echo date('Y-m-d H:i:s', filemtime($full)); ?></td>
            </tr>
            <?php endforeach; ?>
        </tbody>
    </table>

    <p class="meta">If the list is empty, make sure the webserver user (Apache) has read permission on this folder.</p>
</body>
</html>
