<?php
// ================= 文件下载目录 =================
// 用法：把要分享的文件放进本目录（downloads/），访问 /downloads/ 即可浏览和下载。
// 支持子文件夹，路径用斜杠分隔。
// 安全：只能访问本目录内的文件，无法下载到 index.php 等目录外文件。
// ===============================================

$root = __DIR__;
$rootReal = realpath($root);
if($rootReal === false) $rootReal = $root;

// 安全取子路径（防目录穿越）
function safeSub($s){
  $s = str_replace('\\', '/', trim($s));
  $s = trim($s, '/');
  $s = preg_replace('#(^|/)\.\.(/|$)#', '', $s); // 去掉 ../
  $s = trim($s, '/');
  return $s;
}

// 判断路径是否在 root 内（严谨边界校验，防止 /downloads 与 /downloads2 前缀混淆）
function isInside($path, $root){
  $path = str_replace('\\', '/', $path);
  $root = rtrim(str_replace('\\', '/', $root), '/');
  if($path === $root) return true;
  return strpos($path, $root . '/') === 0;
}

$sub = safeSub(isset($_GET['p']) ? $_GET['p'] : '');

// 当前目录真实路径
$cur = $rootReal . ($sub !== '' ? '/' . $sub : '');
$curReal = realpath($cur);
if($curReal === false || !isInside($curReal, $rootReal) || !is_dir($curReal)){
  header('HTTP/1.1 404 Not Found');
  echo '<meta charset="utf-8">目录不存在';
  exit;
}

// ===== 下载文件 =====
if(isset($_GET['f'])){
  $f = safeSub($_GET['f']);
  $file = realpath($rootReal . '/' . $f);
  if($file !== false && is_file($file) && isInside($file, $rootReal)){
    $name = basename($file);
    // 中文文件名用 RFC 5987 编码，避免乱码
    $encoded = rawurlencode($name);
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="'.$encoded.'"; filename*=UTF-8\'\''.$encoded);
    header('Content-Length: '.filesize($file));
    header('X-Content-Type-Options: nosniff');
    readfile($file);
    exit;
  }
  header('HTTP/1.1 404 Not Found');
  echo '<meta charset="utf-8">文件不存在';
  exit;
}

// ===== 列出目录 =====
$items = array();
$dh = opendir($curReal);
if($dh){
  while(($e = readdir($dh)) !== false){
    if($e === '.' || $e === '..') continue;
    $full = $curReal . '/' . $e;
    $rel  = ($sub !== '' ? $sub . '/' : '') . $e;
    $items[] = array(
      'name' => $e,
      'rel'  => $rel,
      'dir'  => is_dir($full),
      'size' => is_file($full) ? filesize($full) : 0,
    );
  }
  closedir($dh);
}
// 文件夹在前，按名称排序
usort($items, function($a, $b){
  if($a['dir'] !== $b['dir']) return $a['dir'] ? -1 : 1;
  return strcasecmp($a['name'], $b['name']);
});

// 面包屑
$crumbs = array(array('name' => '文件下载', 'p' => ''));
if($sub !== ''){
  $parts = explode('/', $sub);
  $acc = '';
  foreach($parts as $p){
    if($p === '') continue;
    $acc = ($acc === '' ? '' : $acc . '/') . $p;
    $crumbs[] = array('name' => $p, 'p' => $acc);
  }
}

function fmtSize($n){
  if($n >= 1073741824) return round($n/1073741824, 2).' GB';
  if($n >= 1048576) return round($n/1048576, 2).' MB';
  if($n >= 1024) return round($n/1024, 2).' KB';
  return $n.' B';
}
?>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>文件下载</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;background:#f0f2f5;color:rgba(0,0,0,.88)}
.wrap{max-width:860px;margin:0 auto;padding:24px 16px}
h1{font-size:20px;margin-bottom:8px}
.crumbs{font-size:14px;color:rgba(0,0,0,.45);margin-bottom:20px;word-break:break-all}
.crumbs a{color:#1677ff;text-decoration:none}
.crumbs a:hover{text-decoration:underline}
.crumbs span{color:rgba(0,0,0,.3);margin:0 4px}
.card{background:#fff;border-radius:8px;border:1px solid #f0f0f0;overflow:hidden;box-shadow:0 1px 2px rgba(0,0,0,.03)}
.item{display:flex;align-items:center;gap:12px;padding:13px 18px;border-bottom:1px solid #f0f0f0;text-decoration:none;color:rgba(0,0,0,.88)}
.item:last-child{border-bottom:none}
.item:hover{background:#fafafa}
.icon{flex-shrink:0;font-size:18px;width:24px;text-align:center}
.name{flex:1;word-break:break-all;font-size:14px}
.dir .name{color:#1677ff;font-weight:500}
.size{flex-shrink:0;font-size:13px;color:rgba(0,0,0,.45)}
.empty{padding:50px;text-align:center;color:rgba(0,0,0,.45);font-size:14px}
.hint{margin-top:16px;font-size:13px;color:rgba(0,0,0,.45);line-height:1.8}
@media(max-width:480px){
  .item{padding:12px 14px}
  .size{display:none}
}
</style>
</head>
<body>
<div class="wrap">
  <h1>文件下载</h1>
  <div class="crumbs">
    <?php foreach($crumbs as $i=>$c): ?>
      <?php if($i>0) echo '<span>/</span>'; ?>
      <?php if($i === count($crumbs)-1): ?>
        <?php echo htmlspecialchars($c['name']); ?>
      <?php else: ?>
        <a href="?p=<?php echo urlencode($c['p']); ?>"><?php echo htmlspecialchars($c['name']); ?></a>
      <?php endif; ?>
    <?php endforeach; ?>
  </div>

  <div class="card">
    <?php if(count($items) === 0): ?>
      <div class="empty">这个文件夹是空的，把文件放进来就能下载了</div>
    <?php endif; ?>
    <?php foreach($items as $it): ?>
      <?php if($it['dir']): ?>
        <a class="item dir" href="?p=<?php echo urlencode($it['rel']); ?>">
          <span class="icon">📁</span><span class="name"><?php echo htmlspecialchars($it['name']); ?>/</span>
        </a>
      <?php else: ?>
        <a class="item" href="?f=<?php echo urlencode($it['rel']); ?>">
          <span class="icon">📄</span><span class="name"><?php echo htmlspecialchars($it['name']); ?></span>
          <span class="size"><?php echo fmtSize($it['size']); ?></span>
        </a>
      <?php endif; ?>
    <?php endforeach; ?>
  </div>

  <div class="hint">
    用法：把要分享的文件放进 <b>downloads</b> 文件夹（支持子文件夹），访问本页面即可浏览和下载。<br>
    点击文件夹进入下一层，点击文件直接下载。
  </div>
</div>
</body>
</html>
