Files
Leantime/dev/DWGViewer/api/model.php

81 lines
3.2 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* DWG/DXF 查看器 - 图纸读取接口
* 校验令牌 → .enc 解密 / 原文件原样 → 流式返回。
* SECRET 必须与 token.php、upload.php 一致。
*/
$SECRET = 'be323d1b90bd2fda624083d4d1d716b7';
// 与 upload.php 保持一致的私有目录配置:图纸放 Web 目录外web 里根本没有文件可下载
$PRIVATE_DIR = '/volume1/dwgviewer_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('/\.(dwg|dxf|enc)$/i', $f)) json_out(400, ['error' => 'bad params']);
if (strpos($f, '..') !== false) json_out(400, ['error' => 'bad path']);
$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) json_out(404, ['error' => 'not found']);
$data = file_get_contents($full);
$origName = basename($f);
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)];
}
// 加密体头部藏着原文件名(落盘名是随机的,链接里看不出是哪张图)
if (strlen($out) > 2) {
$nl = unpack('n', substr($out, 0, 2))[1];
if ($nl > 0 && $nl <= 255 && strlen($out) > 2 + $nl) {
$origName = substr($out, 2, $nl);
$out = substr($out, 2 + $nl);
}
}
$data = $out;
}
header('X-Filename: ' . rawurlencode($origName));
header('Access-Control-Expose-Headers: X-Filename');
// 上传时已经 gzip 过,解密后就是 gzip 流,直接标 Content-Encoding 让浏览器解;
// 明文文件(如 dxf在线压一次DXF 文本能压到 1/8 左右
$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');
header('Content-Disposition: inline');
echo $send;