Files
Leantime/dev/library.php
wangruiguo d647428529
Some checks failed
Security Audit / Composer Security Audit (push) Has been cancelled
Security Audit / NPM Security Audit (push) Has been cancelled
Security Audit / CodeQL Analysis (push) Has been cancelled
OneBot: Leantime 改造版源码(BOM/Univer 表格/AI 接管/品牌替换等)
2026-09-03 18:49:20 +08:00

68 lines
2.7 KiB
PHP
Raw 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
/**
* 2D/3D 数模库 - 元数据接口(首页库表用)
* GET 无参 → 返回 library.json 的全部记录(静态 JSON 也行,这里统一走接口)
* POST {"records":[...]} → 清洗后整体保存(客户端把编辑后的数组传回)
*
* 只允许本站页面调用(Sec-Fetch-Site 优先、Referer 兜底,与 api/token.php 同一策略)。
* 注意这只是防顺手篡改的弱校验:库表只存名称/备注等元数据,不含文件内容。
*/
header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store');
$fetchSite = $_SERVER['HTTP_SEC_FETCH_SITE'] ?? '';
$referer = $_SERVER['HTTP_REFERER'] ?? '';
$host = $_SERVER['HTTP_HOST'] ?? '';
if ($fetchSite !== '') {
if ($fetchSite !== 'same-origin' && $fetchSite !== 'same-site') json_out(403, ['error' => 'forbidden']);
} elseif (!$host || strpos($referer, $host) === false) {
json_out(403, ['error' => 'forbidden']);
}
function json_out($code, $obj) {
http_response_code($code);
echo json_encode($obj, JSON_UNESCAPED_UNICODE);
exit;
}
$file = __DIR__ . '/library.json';
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
if (is_file($file)) { readfile($file); exit; }
json_out(200, ['records' => []]);
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') json_out(405, ['error' => 'method not allowed']);
$in = json_decode((string)file_get_contents('php://input'), true);
if (!is_array($in) || !isset($in['records']) || !is_array($in['records'])) {
json_out(400, ['error' => 'bad body']);
}
// 清洗:path 是链接核心(拒绝 ..、限制字符与长度),name/note 纯文本截断
$records = [];
$seen = [];
foreach ($in['records'] as $r) {
if (!is_array($r)) continue;
$path = is_string($r['path'] ?? null) ? trim($r['path']) : '';
$name = is_string($r['name'] ?? null) ? trim($r['name']) : '';
$note = is_string($r['note'] ?? null) ? trim($r['note']) : '';
$type = ($r['type'] ?? '') === '2d' ? '2d' : '3d';
if ($path === '' || strpos($path, '..') !== false || strlen($path) > 300) continue;
if (!preg_match('/^[\x20-\x7e\x{4e00}-\x{9fff}\/\\\\]+$/u', $path)) continue;
if (isset($seen[$path])) continue;
$seen[$path] = true;
$records[] = [
'path' => $path,
'name' => mb_substr($name, 0, 100),
'type' => $type,
'note' => mb_substr($note, 0, 200),
'time' => is_numeric($r['time'] ?? null) ? (int)$r['time'] : time(),
];
}
// 带锁写文件,防止两个查看器上传时并发写坏
$json = json_encode(['records' => $records], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
if (file_put_contents($file, $json, LOCK_EX) === false) json_out(500, ['error' => 'write failed']);
json_out(200, ['ok' => true, 'count' => count($records)]);