'method not allowed']); $len = (int)($_SERVER['CONTENT_LENGTH'] ?? 0); if ($len <= 0) json_out(400, ['error' => 'empty body']); if ($len > $MAX_SIZE) json_out(413, ['error' => 'file too large (max 500MB)']); $raw = urldecode($_SERVER['HTTP_X_FILENAME'] ?? 'model.step'); $base = basename($raw); $safe = preg_replace('/[^\w.\-\x{4e00}-\x{9fff}]/u', '_', $base); if (!$safe || !preg_match('/\.(step|stp)$/i', $safe)) $safe .= '.stp'; $stem = pathinfo($safe, PATHINFO_FILENAME); $ext = pathinfo($safe, PATHINFO_EXTENSION); $name = $stem . '_' . substr(bin2hex(random_bytes(4)), 0, 8) . '.' . $ext; $data = file_get_contents('php://input'); if ($data === false || strlen($data) !== $len) json_out(400, ['error' => 'incomplete upload']); // 客户端可选 gzip 压缩上传(STEP 文本约可压到 1/6,节省带宽) if (($_SERVER['HTTP_X_ENCODING'] ?? '') === 'gzip') { $dec = gzdecode($data); if ($dec === false) json_out(400, ['error' => 'bad gzip body']); if (strlen($dec) > $MAX_SIZE) json_out(413, ['error' => 'file too large (max 500MB)']); $data = $dec; } // 存储层也压缩:先 gzip 再加密,磁盘占用约 1/6(读取端靠 gzip 魔数自动识别) $rawSize = strlen($data); $data = gzencode($data, 6); if ($data === false) json_out(500, ['error' => 'gzip failed']); $dir = $PRIVATE_DIR !== '' ? $PRIVATE_DIR : (__DIR__ . '/../uploads'); if (!is_dir($dir)) @mkdir($dir, 0755, true); if (!is_dir($dir)) json_out(500, ['error' => 'upload dir not writable']); $nonce = random_bytes(16); $key = hash('sha256', $SECRET . $nonce, true); $enc = ''; for ($i = 0; $i < strlen($data); $i++) { $enc .= $data[$i] ^ $key[$i % strlen($key)]; } file_put_contents($dir . '/' . $name . '.enc', $nonce . $enc); // 私有目录模式下返回裸文件名:嵌入链接就是 ?file=xxx.enc,读取端按 basename 在私有目录找 $entryPath = ($PRIVATE_DIR !== '' ? '' : 'uploads/') . $name . '.enc'; // 记入首页数模库(入口目录的 library.json,2D/3D 共享);库写失败不影响上传本身 try { add_to_library($entryPath, $safe, '3d'); } catch (Throwable $e) { /* 忽略 */ } json_out(200, ['path' => $entryPath, 'size' => $rawSize]); /** * 把刚上传的文件追加进首页数模库(../../library.json): * 同路径已有记录就刷新名称和时间,否则插到最前。 */ function add_to_library($path, $name, $type) { $libFile = dirname(__DIR__, 2) . '/library.json'; $records = []; if (is_file($libFile)) { $old = json_decode((string)file_get_contents($libFile), true); if (is_array($old) && isset($old['records']) && is_array($old['records'])) $records = $old['records']; } $found = false; foreach ($records as $i => $rec) { if (isset($rec['path']) && $rec['path'] === $path) { $records[$i]['name'] = $name; $records[$i]['time'] = time(); $found = true; break; } } if (!$found) { array_unshift($records, ['path' => $path, 'name' => $name, 'type' => $type, 'note' => '', 'time' => time()]); } @file_put_contents($libFile, json_encode(['records' => $records], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), LOCK_EX); }