<?php
// 경로/파일: /var/www/html/elfinder/php/connector.minimal.php
// RealNAS elFinder connector (SAFE)
// - 새 마운트 정책: /mnt/storage, /mnt/tmp, /mnt/usb|hdd|nvme + 하위
// - 과거 기능 보충: URL 자동 생성 + fallback 에러 + access 차단 유지

error_reporting(E_ALL & ~E_NOTICE);
header('X-REALNAS-CONNECTOR: v20251231');

// vendor/autoload.php / autoload.php 있으면 로드 (환경별 호환)
is_readable(__DIR__ . '/vendor/autoload.php') && require __DIR__ . '/vendor/autoload.php';
is_readable(__DIR__ . '/autoload.php') && require __DIR__ . '/autoload.php';

// elFinder core include (기본 배포판 호환)
require_once __DIR__ . '/elFinderConnector.class.php';
require_once __DIR__ . '/elFinder.class.php';
require_once __DIR__ . '/elFinderVolumeDriver.class.php';
require_once __DIR__ . '/elFinderVolumeLocalFileSystem.class.php';

elFinder::$netDrivers['ftp'] = 'FTP';

// -------------------------------------------------
// 접근 제어 (UI 차단)
// -------------------------------------------------
function access($attr, $path, $data, $volume, $isDir, $relpath) {
  $basename = basename($path);

  // 숨김(.xxx) 차단
  if ($basename !== '' && $basename[0] === '.') {
    return !($attr === 'read' || $attr === 'write');
  }

  // lost+found 차단
  if ($basename === 'lost+found') {
    return !($attr === 'read' || $attr === 'write');
  }

  return null;
}

// -------------------------------------------------
// util
// -------------------------------------------------
function norm_path($p) {
  $p = trim((string)$p);
  $p = str_replace("\0", '', $p);
  $p = rtrim($p, "/");
  return $p === '' ? '/' : $p;
}

function detect_scheme() {
  if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
    $p = explode(',', $_SERVER['HTTP_X_FORWARDED_PROTO'])[0];
    $p = trim($p);
    if ($p === 'http' || $p === 'https') return $p;
  }
  if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') return 'https';
  return 'http';
}

function detect_host() {
  if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
    $h = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST'])[0];
    return trim($h);
  }
  if (!empty($_SERVER['HTTP_HOST'])) return $_SERVER['HTTP_HOST'];
  if (!empty($_SERVER['SERVER_NAME'])) return $_SERVER['SERVER_NAME'];
  return 'localhost';
}

function script_base_url() {
  $scheme = detect_scheme();
  $host   = detect_host();
  $script = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : '';

  // /files/php/connector.minimal.php -> /files
  $basePath = preg_replace('#/php/[^/]+\.php$#', '', $script);
  $basePath = rtrim($basePath, '/');

  $host = trim($host);
  $host = preg_replace('/\s+/', '', $host);

  return $scheme . '://' . $host . $basePath;
}

function safe_web_path($s) {
  $s = trim((string)$s);
  $s = trim($s, "/");
  $s = str_replace(array('..', '\\', '/'), '', $s);
  $s = preg_replace('/\s+/', '-', $s);
  $s = preg_replace('/[^a-zA-Z0-9._-]/', '', $s);
  return $s;
}

function load_config($path) {
  if (!is_readable($path)) return null;
  $raw = @file_get_contents($path);
  if ($raw === false) return null;
  $json = @json_decode($raw, true);
  if (!is_array($json)) return null;
  return $json;
}

// -------------------------------------------------
// ✅ 마운트 체크
// - 베이스(/mnt/usb,/mnt/hdd,/mnt/nvme)는 컨테이너 폴더라 mountpoint 아니어도 허용
// - 나머지는 실제 마운트된 것만 노출
// -------------------------------------------------
function is_mounted_path($p) {
  $p = norm_path($p);
  if ($p === '/' || $p === '') return false;

  $cmd = 'findmnt -T ' . escapeshellarg($p) . ' >/dev/null 2>&1';
  $rc  = 1;
  @exec($cmd, $out, $rc);
  return ($rc === 0);
}

function is_base_container($p) {
  $p = norm_path($p);
  return in_array($p, array('/mnt/usb', '/mnt/hdd', '/mnt/nvme'), true);
}

// -------------------------------------------------
// ✅ 허용 루트 정책 (Python과 동일)
// 허용:
//  - /mnt/storage
//  - /mnt/tmp
//  - /mnt/usb, /mnt/usb/*
//  - /mnt/hdd, /mnt/hdd/*
//  - /mnt/nvme, /mnt/nvme/*
// -------------------------------------------------
function is_allowed_root($p) {
  $p = norm_path($p);

  // 절대 금지: OS 루트
  if ($p === '/') return false;

  if ($p === '/mnt/storage') return true;
  if ($p === '/mnt/tmp') return true;

  if ($p === '/mnt/usb'  || strpos($p, '/mnt/usb/')  === 0) return true;
  if ($p === '/mnt/hdd'  || strpos($p, '/mnt/hdd/')  === 0) return true;
  if ($p === '/mnt/nvme' || strpos($p, '/mnt/nvme/') === 0) return true;

  return false;
}

function archive_opts() {
  return array(
    'create'  => array('application/zip'),
    'extract' => array('application/zip'),
  );
}

function build_local_root($alias, $path, $url) {
  $path  = norm_path($path);
  $alias = trim((string)$alias);

  if ($path === '/' || !is_allowed_root($path)) return null;

  $root = array(
    'driver'        => 'LocalFileSystem',
    'path'          => $path . '/',
    'alias'         => $alias !== '' ? $alias : basename($path),
    'accessControl' => 'access',
    'uploadAllow'   => array('all'),
    'uploadDeny'    => array('all'),
    'uploadOrder'   => array('deny', 'allow'),
    'archive'       => archive_opts(),
    'attributes'    => array(
      array('pattern' => '/^\./', 'read' => false, 'write' => false, 'hidden' => true, 'locked' => true),
      array('pattern' => '/^lost\+found$/', 'read' => false, 'write' => false, 'hidden' => true, 'locked' => true),
    ),
  );

  $url = trim((string)$url);
  if ($url !== '') $root['URL'] = rtrim($url, '/') . '/';

  return $root;
}

function pick_conf_path() {
  $p1 = '/etc/realnas/elfinder.json';
  if (is_readable($p1)) return $p1;

  $p2 = '/opt/realcom-nas/config/elfinder.json';
  if (is_readable($p2)) return $p2;

  return $p1;
}

// -------------------------------------------------
// 설정
// -------------------------------------------------
define('AUTO_URL', true);

// -------------------------------------------------
// roots 구성
// -------------------------------------------------
$CONF_PATH = pick_conf_path();
$conf = load_config($CONF_PATH);

$roots   = array();
$baseUrl = script_base_url();

if (is_array($conf) && isset($conf['roots']) && is_array($conf['roots']) && count($conf['roots']) > 0) {
  foreach ($conf['roots'] as $r) {
    if (!is_array($r)) continue;

    $alias = isset($r['alias']) ? trim((string)$r['alias']) : '';
    $path  = isset($r['path'])  ? trim((string)$r['path'])  : '';
    $url   = isset($r['url'])   ? trim((string)$r['url'])   : '';
    $webp  = isset($r['web_path']) ? trim((string)$r['web_path']) : '';

    if ($path === '') continue;

    $np = norm_path($path);

    // 허용 루트 아니면 스킵
    if (!is_allowed_root($np)) continue;

    // 반드시 존재하는 디렉토리만
    if (!is_dir($np) || !is_readable($np)) continue;

    // ✅ 마운트 정책:
    // - 컨테이너(/mnt/usb,/mnt/hdd,/mnt/nvme)는 mountpoint 아니어도 허용
    // - 나머지는 실제 마운트된 것만 노출
    if (!is_base_container($np)) {
      if (!is_mounted_path($np)) continue;
    }

    // URL 자동생성 (있으면 보충)
    if ($url === '' && AUTO_URL) {
      if ($webp === '') $webp = ($alias !== '') ? $alias : basename($np);
      $webp = safe_web_path($webp);
      if ($webp !== '') $url = $baseUrl . '/' . $webp;
    }

    $root = build_local_root($alias, $np, $url);
    if (is_array($root)) $roots[] = $root;
  }
}

// -------------------------------------------------
// ✅ fallback
// - roots가 0이면: 마운트된 것 중 하나라도 잡아줌 (에러 원인 바로 보이게)
// -------------------------------------------------
if (count($roots) === 0) {
  // 컨테이너는 mount 체크 제외 (디렉토리만 존재하면 OK)
  $cands = array('/mnt/usb', '/mnt/hdd', '/mnt/nvme', '/mnt/storage', '/mnt/tmp');

  $fallback = '';
  foreach ($cands as $c) {
    if (!is_allowed_root($c)) continue;
    if (!is_dir($c) || !is_readable($c)) continue;

    if (!is_base_container($c)) {
      if (!is_mounted_path($c)) continue;
    }

    $fallback = $c;
    break;
  }

  if ($fallback === '' || !is_allowed_root($fallback)) {
    header('Content-Type: application/json; charset=utf-8');
    http_response_code(500);
    echo json_encode(array(
      'error'     => 'No valid elFinder roots. Check mounts and elfinder.json roots.',
      'hint'      => 'Allowed: /mnt/storage, /mnt/tmp, /mnt/usb(/sub), /mnt/hdd(/sub), /mnt/nvme(/sub). Base dirs are allowed even if not mounted.',
      'conf_path' => $CONF_PATH,
    ), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
    exit;
  }

  $root = build_local_root('DATA', $fallback, '');
  if (is_array($root)) $roots[] = $root;
}

// -------------------------------------------------
// elFinder 실행
// -------------------------------------------------
$opts = array('roots' => $roots);
$connector = new elFinderConnector(new elFinder($opts));
$connector->run();
