<?php
/**
 * STEP 查看器 - 模型读取接口（PHP 版）
 * 校验令牌 → .enc 解密 / .stp 原样 → 流式返回
 */
$SECRET = '7175a8598ff7fa1c182f57f0c750e4f8';
// 与 upload.php 保持一致的私有目录配置：模型放 Web 目录外，web 里根本没有文件可下载
$PRIVATE_DIR = '/volume1/stepviewer_private';

function json_out($code, $obj) {
    http_response_code($code);
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($obj, JSON_UNESCAPED_UNICODE);
    exit;
}

$f = $_GET['f'] ?? '';
$t = $_GET['t'] ?? '';
$e = (int)($_GET['e'] ?? 0);
if (!$f || !$t || !preg_match('/\.(stp|step|enc)$/i', $f)) json_out(400, ['error' => 'bad params']);

$sig = substr(hash_hmac('sha256', $f . '|' . $e, $SECRET), 0, 16);
if (!hash_equals($sig, $t) || time() > $e) json_out(403, ['error' => 'invalid or expired token']);

$root = realpath(__DIR__ . '/..');
if ($PRIVATE_DIR !== '') {
    // 私有目录优先（嵌入链接写纯文件名即可）；目录不存在时退回站内路径，
    // 让留在 web 目录里的样例模型按原路径继续可用（这些文件本来就允许直链，
    // 退回不新增暴露面）。要保护的文件必须移出 web 目录放进私有目录。
    $full = realpath($PRIVATE_DIR . '/' . basename($f));
    $ok = $full && strpos($full, realpath($PRIVATE_DIR)) === 0 && is_file($full);
    if (!$ok) {
        $full = realpath($root . '/' . $f);
        $ok = $full && strpos($full, $root) === 0 && is_file($full);
    }
} else {
    $full = realpath($root . '/' . $f);
    $ok = $full && strpos($full, $root) === 0 && is_file($full);
}
if (!$ok || !$full) json_out(404, ['error' => 'not found']);

$data = file_get_contents($full);
if (preg_match('/\.enc$/i', $f)) {
    $nonce = substr($data, 0, 16);
    $key = hash('sha256', $SECRET . $nonce, true);
    $body = substr($data, 16);
    $out = '';
    for ($i = 0; $i < strlen($body); $i++) {
        $out .= $body[$i] ^ $key[$i % strlen($key)];
    }
    $data = $out;
}

// 传输层 gzip：新格式文件解密后即以 gzip 魔数开头，原样传输；
// 旧格式明文文件在线压缩。浏览器 fetch 自动解压（无需前端改动）
$send = $data;
if (substr($send, 0, 2) === "\x1f\x8b") {
    header('Content-Encoding: gzip');
} elseif (!ini_get('zlib.output_compression') && strlen($data) > 1024) {
    $gz = gzencode($data, 6);
    if ($gz !== false) { $send = $gz; header('Content-Encoding: gzip'); }
}
header('Content-Type: application/octet-stream');
header('Content-Length: ' . strlen($send));
header('Cache-Control: no-store');
echo $send;
