From 0213db84da2f8084a86821001453131342cd9b00 Mon Sep 17 00:00:00 2001 From: Tiaotiao <65841827@qq.com> Date: Mon, 27 Apr 2026 12:21:41 +0800 Subject: [PATCH 1/8] Add follow API endpoint for user actions --- api/follow.php | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 api/follow.php diff --git a/api/follow.php b/api/follow.php new file mode 100644 index 0000000..81e627d --- /dev/null +++ b/api/follow.php @@ -0,0 +1,52 @@ + false, 'Message' => 'Not logged in']); + exit; +} + +$token = $_SESSION['token']; +$authCode = $_SESSION['authCode']; + +$targetId = $_GET['id'] ?? ''; +$action = isset($_GET['action']) ? (int)$_GET['action'] : 1; // 1=关注, 0=取消 + +if (empty($targetId)) { + echo json_encode(['Success' => false, 'Message' => 'Missing user id']); + exit; +} + +$url = 'http://nlm-api-cn.turtlesim.com/Users/Follow'; +$body = json_encode([ + 'TargetID' => $targetId, + 'Action' => $action +]); +$headers = [ + 'Content-Type: application/json', + 'x-API-Token: ' . $token, + 'x-API-AuthCode: ' . $authCode, +]; + +$ch = curl_init($url); +curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => true, + CURLOPT_POST => true, + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => $body, + CURLOPT_TIMEOUT => 10, +]); + +$response = curl_exec($ch); +$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); +$bodyResp = substr($response, $headerSize); +$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); +curl_close($ch); + +$data = json_decode($bodyResp, true); +$success = ($httpCode == 200 && isset($data['Status']) && $data['Status'] == 200); + +echo json_encode(['Success' => $success]); +?> From e178c75dcf932d688c1452807fb9734d32fb82b4 Mon Sep 17 00:00:00 2001 From: Tiaotiao <65841827@qq.com> Date: Mon, 27 Apr 2026 12:22:33 +0800 Subject: [PATCH 2/8] Add get_comments.php for fetching comments --- api/get_comments.php | 57 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 api/get_comments.php diff --git a/api/get_comments.php b/api/get_comments.php new file mode 100644 index 0000000..02e6818 --- /dev/null +++ b/api/get_comments.php @@ -0,0 +1,57 @@ + false, 'Message' => 'Not logged in']); + exit; +} + +$token = $_SESSION['token']; +$authCode = $_SESSION['authCode']; + +$targetId = $_GET['id'] ?? ''; +$targetType = $_GET['type'] ?? 'User'; +$skip = (int)($_GET['skip'] ?? 0); +$take = (int)($_GET['take'] ?? 20); + +if (empty($targetId)) { + echo json_encode(['Success' => false, 'Message' => 'Missing target id']); + exit; +} + +$url = 'http://nlm-api-cn.turtlesim.com/Messages/GetComments'; +$body = json_encode([ + 'TargetID' => $targetId, + 'TargetType' => $targetType, + 'Skip' => $skip, + 'Take' => $take +]); + +$headers = [ + 'Content-Type: application/json', + 'x-API-Token: ' . $token, + 'x-API-AuthCode: ' . $authCode, +]; + +$ch = curl_init($url); +curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => true, + CURLOPT_POST => true, + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => $body, + CURLOPT_TIMEOUT => 10, +]); + +$response = curl_exec($ch); +$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); +$bodyResp = substr($response, $headerSize); +$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); +curl_close($ch); + +$data = json_decode($bodyResp, true); +$success = ($httpCode == 200 && isset($data['Status']) && $data['Status'] == 200); + +echo json_encode(['Success' => $success, 'Data' => $data['Data'] ?? null, 'Message' => $data['Message'] ?? '']); +?> From cf19e26a90c61af1969402e9831993dff821eba2 Mon Sep 17 00:00:00 2001 From: Tiaotiao <65841827@qq.com> Date: Mon, 27 Apr 2026 12:57:17 +0800 Subject: [PATCH 3/8] =?UTF-8?q?=E5=88=9B=E5=BB=BA=20get=5Frelations.php?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/get_relations.php | 57 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 api/get_relations.php diff --git a/api/get_relations.php b/api/get_relations.php new file mode 100644 index 0000000..466a18c --- /dev/null +++ b/api/get_relations.php @@ -0,0 +1,57 @@ + false, 'Message' => 'Not logged in']); + exit; +} + +$token = $_SESSION['token']; +$authCode = $_SESSION['authCode']; + +$userId = $_GET['id'] ?? ''; +$displayType = (int)($_GET['displayType'] ?? 1); // 1=Follower, 2=Following +$skip = (int)($_GET['skip'] ?? 0); +$take = (int)($_GET['take'] ?? 20); + +if (empty($userId)) { + echo json_encode(['Success' => false, 'Message' => 'Missing user id']); + exit; +} + +$url = 'http://nlm-api-cn.turtlesim.com/Users/GetRelations'; +$body = json_encode([ + 'UserID' => $userId, + 'DisplayType' => $displayType, + 'Skip' => $skip, + 'Take' => $take +]); + +$headers = [ + 'Content-Type: application/json', + 'x-API-Token: ' . $token, + 'x-API-AuthCode: ' . $authCode, +]; + +$ch = curl_init($url); +curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => true, + CURLOPT_POST => true, + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => $body, + CURLOPT_TIMEOUT => 10, +]); + +$response = curl_exec($ch); +$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); +$bodyResp = substr($response, $headerSize); +$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); +curl_close($ch); + +$data = json_decode($bodyResp, true); +$success = ($httpCode == 200 && isset($data['Status']) && $data['Status'] == 200); + +echo json_encode(['Success' => $success, 'Data' => $data['Data'] ?? null, 'Message' => $data['Message'] ?? '']); +?> \ No newline at end of file From 59a5cb41d3e49096916d6fac1ba424fc66adc4a3 Mon Sep 17 00:00:00 2001 From: Tiaotiao <65841827@qq.com> Date: Mon, 27 Apr 2026 12:58:13 +0800 Subject: [PATCH 4/8] =?UTF-8?q?=E5=88=9B=E5=BB=BA=20visit.php?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/visit.php | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 api/visit.php diff --git a/api/visit.php b/api/visit.php new file mode 100644 index 0000000..15abe1b --- /dev/null +++ b/api/visit.php @@ -0,0 +1,49 @@ + false]); + exit; +} + +$token = $_SESSION['token']; +$authCode = $_SESSION['authCode']; + +$contentId = $_GET['id'] ?? ''; +$category = $_GET['category'] ?? ''; + +if (empty($contentId) || empty($category)) { + echo json_encode(['Success' => false]); + exit; +} + +$baseUrl = 'http://nlm-api-cn.turtlesim.com/'; +$url = $baseUrl . 'Contents/VisitExperiment'; + +$requestData = [ + 'SummaryID' => $contentId, + 'Category' => $category +]; + +$headers = [ + "Content-Type: application/json", + "x-API-Token: " . $token, + "x-API-AuthCode: " . $authCode, +]; + +$ch = curl_init($url); +curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => true, + CURLOPT_POST => true, + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => json_encode($requestData), + CURLOPT_TIMEOUT => 5, +]); + +curl_exec($ch); +curl_close($ch); + +echo json_encode(['Success' => true]); +?> \ No newline at end of file From b3fb7c1b1781f0987e493756e4f16817c517f95d Mon Sep 17 00:00:00 2001 From: Tiaotiao <65841827@qq.com> Date: Mon, 27 Apr 2026 12:58:49 +0800 Subject: [PATCH 5/8] =?UTF-8?q?=E5=88=9B=E5=BB=BA=20star.php?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/star.php | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 api/star.php diff --git a/api/star.php b/api/star.php new file mode 100644 index 0000000..ce44740 --- /dev/null +++ b/api/star.php @@ -0,0 +1,65 @@ + false, 'Message' => 'Not logged in']); + exit; +} + +$token = $_SESSION['token']; +$authCode = $_SESSION['authCode']; + +$contentId = $_GET['id'] ?? ''; +$category = $_GET['category'] ?? ''; +$action = $_GET['action'] ?? ''; +$status = isset($_GET['status']) ? (bool)$_GET['status'] : true; + +if (empty($contentId) || empty($category) || !in_array($action, ['star', 'support'])) { + echo json_encode(['Success' => false, 'Message' => 'Invalid parameters']); + exit; +} + +$baseUrl = 'http://nlm-api-cn.turtlesim.com/'; +$url = $baseUrl . 'Contents/StarContent'; + +$starType = $action === 'star' ? 0 : 1; // 0=Star, 1=Support + +$requestData = [ + 'ContentID' => $contentId, + 'Category' => $category, + 'Type' => $starType, + 'Status' => $status +]; + +$headers = [ + "Content-Type: application/json", + "x-API-Token: " . $token, + "x-API-AuthCode: " . $authCode, +]; + +$ch = curl_init($url); +curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => true, + CURLOPT_POST => true, + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => json_encode($requestData), + CURLOPT_TIMEOUT => 10, +]); + +$response = curl_exec($ch); +$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); +$body = substr($response, $headerSize); +$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); +curl_close($ch); + +$data = json_decode($body, true); +$success = ($httpCode == 200 && isset($data['Status']) && $data['Status'] == 200); + +echo json_encode([ + 'Success' => $success, + 'Data' => $data +]); +?> \ No newline at end of file From 7e2acbef955ee5f89d0ab246c95cd5d766a32e62 Mon Sep 17 00:00:00 2001 From: Tiaotiao <65841827@qq.com> Date: Mon, 27 Apr 2026 12:59:38 +0800 Subject: [PATCH 6/8] =?UTF-8?q?=E5=88=9B=E5=BB=BA=20post=5Fcomment.php?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/post_comment.php | 60 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 api/post_comment.php diff --git a/api/post_comment.php b/api/post_comment.php new file mode 100644 index 0000000..5ad4a89 --- /dev/null +++ b/api/post_comment.php @@ -0,0 +1,60 @@ + false, 'Message' => 'Not logged in']); + exit; +} + +$token = $_SESSION['token']; +$authCode = $_SESSION['authCode']; + +// 获取 POST 请求体 +$input = json_decode(file_get_contents('php://input'), true); +$targetId = $input['TargetID'] ?? ''; +$targetType = $input['TargetType'] ?? 'User'; +$content = $input['Content'] ?? ''; +$replyId = $input['ReplyID'] ?? ''; + +if (empty($targetId) || empty($content)) { + echo json_encode(['Success' => false, 'Message' => 'Missing required fields']); + exit; +} + +$url = 'http://nlm-api-cn.turtlesim.com/Messages/PostComment'; +$body = json_encode([ + 'TargetID' => $targetId, + 'TargetType' => $targetType, + 'Content' => $content, + 'ReplyID' => $replyId, + 'Language' => 'Chinese' +]); + +$headers = [ + 'Content-Type: application/json', + 'x-API-Token: ' . $token, + 'x-API-AuthCode: ' . $authCode, +]; + +$ch = curl_init($url); +curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => true, + CURLOPT_POST => true, + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => $body, + CURLOPT_TIMEOUT => 10, +]); + +$response = curl_exec($ch); +$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); +$bodyResp = substr($response, $headerSize); +$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); +curl_close($ch); + +$data = json_decode($bodyResp, true); +$success = ($httpCode == 200 && isset($data['Status']) && $data['Status'] == 200); + +echo json_encode(['Success' => $success, 'Data' => $data['Data'] ?? null, 'Message' => $data['Message'] ?? '']); +?> \ No newline at end of file From bf559b1652f304442a981f74830620bd250ba540 Mon Sep 17 00:00:00 2001 From: Tiaotiao <65841827@qq.com> Date: Mon, 27 Apr 2026 13:00:28 +0800 Subject: [PATCH 7/8] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20med.php?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- med.php | 981 +++++++++++++++++++++----------------------------------- 1 file changed, 370 insertions(+), 611 deletions(-) diff --git a/med.php b/med.php index a846cf4..cf38c52 100644 --- a/med.php +++ b/med.php @@ -11,12 +11,12 @@ if (isset($_SESSION['responseBody'])) { $dt = is_string($_SESSION['responseBody']) ? json_decode($_SESSION['responseBody'], true) : $_SESSION['responseBody']; } else { - $redirectUrl = '/getv.php?r=' . urlencode('med.php?category=' . $category . '&id=' . $contentId . '&type=' . $type); - header('Location: ' . $redirectUrl); - exit; + $redirectUrl = '/getv.php?r=' . urlencode('med.php?category=' . $category . '&id=' . $contentId . '&type=' . $type); + header('Location: ' . $redirectUrl); + exit; } -// 获取作品详情的函数 +// 获取作品详情 function getContentSummary($contentId, $category, $token, $authCode) { $baseUrl = 'http://nlm-api-cn.turtlesim.com/'; $url = $baseUrl . 'Contents/GetSummary'; @@ -48,7 +48,6 @@ function getContentSummary($contentId, $category, $token, $authCode) { ]); $response = curl_exec($ch); - if ($response === false) { curl_close($ch); return null; @@ -57,13 +56,90 @@ function getContentSummary($contentId, $category, $token, $authCode) { $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $body = substr($response, $headerSize); - curl_close($ch); $responseData = json_decode($body, true); return json_last_error() === JSON_ERROR_NONE ? $responseData : null; } +// 获取改编列表 +function getDerivatives($contentId, $category, $token, $authCode) { + $baseUrl = 'http://nlm-api-cn.turtlesim.com/'; + $url = $baseUrl . 'Contents/GetDerivatives'; + + $requestData = [ + 'ContentID' => $contentId, + 'Category' => $category, + 'Language' => 'Chinese', + 'WithSummary' => true + ]; + + $headers = [ + "Content-Type: application/json", + "Accept: application/json", + "Accept-Language: zh-CN", + "x-API-Token: " . $token, + "x-API-AuthCode: " . $authCode, + ]; + + $ch = curl_init($url); + curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => true, + CURLOPT_POST => true, + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => json_encode($requestData), + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_TIMEOUT => 15, + ]); + + $response = curl_exec($ch); + $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); + $body = substr($response, $headerSize); + curl_close($ch); + + $data = json_decode($body, true); + return json_last_error() === JSON_ERROR_NONE ? $data : null; +} + +// 检查是否已收藏(Star) +function isContentStarred($contentId, $category, $token, $authCode) { + $baseUrl = 'http://nlm-api-cn.turtlesim.com/'; + $url = $baseUrl . 'Contents/IsStarred'; + + $requestData = [ + 'ContentID' => $contentId, + 'Category' => $category, + ]; + + $headers = [ + "Content-Type: application/json", + "x-API-Token: " . $token, + "x-API-AuthCode: " . $authCode, + ]; + + $ch = curl_init($url); + curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => true, + CURLOPT_POST => true, + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => json_encode($requestData), + CURLOPT_TIMEOUT => 10, + ]); + + $response = curl_exec($ch); + $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); + $body = substr($response, $headerSize); + curl_close($ch); + + $data = json_decode($body, true); + if ($data && isset($data['Data']) && is_bool($data['Data'])) { + return $data['Data']; + } + return false; +} + // 获取作品详情 $contentData = null; if (!empty($contentId) && !empty($category)) { @@ -76,6 +152,19 @@ function getContentSummary($contentId, $category, $token, $authCode) { } $content = $contentData['Data'] ?? null; + +// 获取改编列表 +$remixes = []; +$isStarred = false; +if ($content && $contentId && $category) { + $derivativesData = getDerivatives($contentId, $category, $token, $authCode); + if ($derivativesData && isset($derivativesData['Data']['Experiments']['Children-Models'])) { + $remixes = $derivativesData['Data']['Experiments']['Children-Models']; + } + // 获取初始收藏状态 + $isStarred = isContentStarred($contentId, $category, $token, $authCode); +} + // 处理日期格式 function formatDate($timestamp) { return date('Y年m月d日', $timestamp / 1000); @@ -91,125 +180,66 @@ function formatDate($timestamp) { 'visual' => '可视化编程', 'knowledge' => '实验知识库' ]; - $pageTitle = $pageTitles[$type] ?? '作品详情'; + // 自定义标签解析器类 class CustomTagParser { - - /** - * 解析包含自定义标签的文本 - */ public static function parse(string $text): string { - if (empty($text)) { - return ''; - } - - // 先转义HTML特殊字符,防止XSS攻击 + if (empty($text)) return ''; $text = htmlspecialchars($text); - - // 先解析Markdown标题(在换行转换之前) $text = self::parseMarkdownHeadings($text); - - // 将换行符转换为
$text = nl2br($text); - // 解析自定义标签 $patterns = [ - // user标签 - 保持原有格式 '/<user=([a-f0-9]+)>(.*?)<\/user>/i', - // experiment标签 - 跳转链接 '/<experiment=([a-f0-9]+)>(.*?)<\/experiment>/i', - // discussion标签 - 跳转链接 '/<discussion=([a-f0-9]+)>(.*?)<\/discussion>/i', - // model标签 - 跳转链接 '/<model=([a-f0-9]+)>(.*?)<\/model>/i', - // external标签 - 外部链接 '/<external=([^&]+)>(.*?)<\/external>/i', - // size标签 '/<size=([^&]+)>(.*?)<\/size>/i', - // color标签 - 新增 '/<color=([^&]+)>(.*?)<\/color>/i', - // b标签 '/<b>(.*?)<\/b>/i', - // i标签 '/<i>(.*?)<\/i>/i', - // a标签 - 深蓝色标签 '/<a>(.*?)<\/a>/i' ]; $replacements = [ - // user标签 '$2', - // experiment标签 '$2', - // discussion标签 '$2', - // model标签 '$2', - // external标签 '$2', - // size标签 '$2', - // color标签 - 新增 '$2', - // b标签 '$1', - // i标签 '$1', - // a标签 '$1' ]; $text = preg_replace($patterns, $replacements, $text); - - // 解析简单的Markdown格式 $text = self::parseSimpleMarkdown($text); - return $text; } - /** - * 解析Markdown标题 - */ private static function parseMarkdownHeadings(string $text): string { - // 支持1-6级标题 - // 一级标题: # 标题 $text = preg_replace('/^# (.+)$/m', '$1', $text); - - // 二级标题: ## 标题 $text = preg_replace('/^## (.+)$/m', '$1', $text); - - // 三级标题: ### 标题 - $text = preg_replace('/^### (.+)$/m', '$1', $text); - - // 四级标题: #### 标题 + $text = preg_replace('/^### (.+)$/m', '$1', $text); $text = preg_replace('/^#### (.+)$/m', '$1', $text); - return $text; } - /** - * 解析简单的Markdown格式 - */ private static function parseSimpleMarkdown(string $text): string { - // 粗体 $text = preg_replace('/\*\*(.*?)\*\*/', '$1', $text); - - // 斜体 $text = preg_replace('/\*(.*?)\*/', '$1', $text); - - // 删除线 $text = preg_replace('/~~(.*?)~~/', '$1', $text); - - // 行内代码 $text = preg_replace('/`([^`]+)`/', '$1', $text); - return $text; } } ?> - + @@ -217,117 +247,93 @@ private static function parseSimpleMarkdown(string $text): string { <?= htmlspecialchars($content['LocalizedSubject']['Chinese'] ?? $pageTitle) ?> - Turtle Universe Web - + -
- +
- + +
+ +
+ + +
+
+
-
-
- -
 
+
+ +   -
+
+ +
+
+ +
+
+ 收藏 +
+
+ +
+
+ 分享 +
+
+ +
+
- +
-
简介
评论()
+
改编()
- - +

作品介绍

@@ -408,10 +430,16 @@ private static function parseSimpleMarkdown(string $text): string {
- - -
-
+ + + + +
@@ -422,440 +450,171 @@ private static function parseSimpleMarkdown(string $text): string {
+ - - const statItems = overlay.querySelectorAll('.stat-item'); - if (statItems.length > 1) { - const followersElement = statItems[1].querySelector('.text'); - if (followersElement) { - const text = followersElement.textContent; - const current = parseInt(text.replace(/[^\d]/g, '')) || 0; - const newCount = current + change; - followersElement.textContent = '粉丝' + newCount.toLocaleString(); - } - } -} - -function handleEscapeKey(e) { - if (e.key === 'Escape') { - const overlay = document.getElementById('userCardOverlay'); - if (overlay) { - overlay.remove(); - currentCard = null; - isOpeningCard = false; // 重置打开标志 - } + + - + \ No newline at end of file From 3d34d7b455b6cac9bb6c593526e33be18bda5f45 Mon Sep 17 00:00:00 2001 From: Tiaotiao <65841827@qq.com> Date: Mon, 27 Apr 2026 13:02:07 +0800 Subject: [PATCH 8/8] =?UTF-8?q?=E5=88=9B=E5=BB=BA=20user.php?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- user.php | 522 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 522 insertions(+) create mode 100644 user.php diff --git a/user.php b/user.php new file mode 100644 index 0000000..f39073d --- /dev/null +++ b/user.php @@ -0,0 +1,522 @@ + $userId]); + $headers = [ + 'Content-Type: application/json', + 'x-API-Token: ' . $token, + 'x-API-AuthCode: ' . $authCode, + ]; + + $ch = curl_init($url); + curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => true, + CURLOPT_POST => true, + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => $body, + CURLOPT_TIMEOUT => 15, + ]); + $response = curl_exec($ch); + $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); + $bodyResp = substr($response, $headerSize); + curl_close($ch); + + $data = json_decode($bodyResp, true); + return (json_last_error() === JSON_ERROR_NONE && isset($data['Data'])) ? $data['Data'] : null; +} + +/** + * 获取用户主页作品列表(调用 Contents/GetProfile) + */ +function getUserProfileProjects(string $userId, string $token, string $authCode): ?array +{ + $url = 'http://nlm-api-cn.turtlesim.com/Contents/GetProfile'; + $body = json_encode(['ID' => $userId]); + $headers = [ + 'Content-Type: application/json', + 'x-API-Token: ' . $token, + 'x-API-AuthCode: ' . $authCode, + ]; + + $ch = curl_init($url); + curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => true, + CURLOPT_POST => true, + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => $body, + CURLOPT_TIMEOUT => 15, + ]); + $response = curl_exec($ch); + $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); + $bodyResp = substr($response, $headerSize); + curl_close($ch); + + $data = json_decode($bodyResp, true); + return (json_last_error() === JSON_ERROR_NONE && isset($data['Data'])) ? $data['Data'] : null; +} + +// ---------- 获取数据 ---------- + +$userInfo = null; +$profile = null; + +if (!empty($targetId)) { + $userInfo = getUserInfo($targetId, $token, $authCode); + $profile = getUserProfileProjects($targetId, $token, $authCode); +} elseif (!empty($targetName)) { + // 通过昵称查找用户 + $url = 'http://nlm-api-cn.turtlesim.com/Users/GetUser'; + $body = json_encode(['Name' => $targetName]); + $headers = [ + 'Content-Type: application/json', + 'x-API-Token: ' . $token, + 'x-API-AuthCode: ' . $authCode, + ]; + $ch = curl_init($url); + curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => true, + CURLOPT_POST => true, + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => $body, + CURLOPT_TIMEOUT => 15, + ]); + $response = curl_exec($ch); + $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); + $bodyResp = substr($response, $headerSize); + curl_close($ch); + $data = json_decode($bodyResp, true); + if ($data && isset($data['Data'])) { + $userInfo = $data['Data']; + $targetId = $userInfo['User']['ID'] ?? ''; + if ($targetId) { + $profile = getUserProfileProjects($targetId, $token, $authCode); + } + } +} + +// 提取字段(依据 GetUser 实际响应) +$targetUser = $userInfo['User'] ?? null; +$statistic = $userInfo['Statistic'] ?? null; + +// 关注数、粉丝数来自 Statistic +$followingCount = $statistic['FollowingCount'] ?? 0; +$followerCount = $statistic['FollowerCount'] ?? 0; + +// 关系(Relation 为 int,1 表示已关注) +$isFollowed = ($userInfo['Relation'] ?? 0) == 1; + +// 封面作品(来自 Statistic.Cover) +$coverSummary = $statistic['Cover'] ?? null; + +// 作品分组(Profile 接口返回的 Experiments 字典) +$experiments = $profile['Experiments'] ?? []; + +// 模块名称映射 +$moduleOrder = [ + 'Featured-Models' => '精选实验', + 'Featured-Discussions' => '精选讨论', + 'Featured-Experiments' => '精选实验', + 'Popular-Models' => '热门实验', + 'Popular-Discussions' => '热门讨论', + 'Popular-Experiments' => '热门实验', + 'Latest-Models' => '最新实验', + 'Latest-Discussions' => '最新讨论', + 'Latest-Experiments' => '最新实验', +]; + +// 头像 URL +function buildAvatarUrl($userId, $avatarId) { + if ($avatarId > 0) { + $base = 'http://netlogo-cn.oss-cn-hongkong.aliyuncs.com/users/avatars/'; + return $base . substr($userId,0,4) . '/' . substr($userId,4,2) . '/' . substr($userId,6,2) . '/' . substr($userId,8,16) . '/' . $avatarId . '.jpg!full'; + } + return 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAiIGhlaWdodD0iODAiIHZpZXdCb3g9IjAgMCA4MCA4MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGNpcmNsZSBjeD0iNDAiIGN5PSI0MCIgcj0iNDAiIGZpbGw9IiNFMEUwRTAiLz4KPHBhdGggZD0iTTQwIDUwQzQ1LjUyIDUwIDUwIDQ1LjUyIDUwIDQwQzUwIDM0LjQ4IDQ1LjUyIDMwIDQwIDMwQzM0LjQ4IDMwIDMwIDM0LjQ4IDMwIDQwQzMwIDQ1LjUyIDM0LjQ4IDUwIDQwIDUwWiIgZmlsbD0iI0JEQkRCRCIvPgo8cGF0aCBkPSJNNTIgNjBIMjhDMjcuNDQ3NyA2MCAyNyA1OS41NTIzIDI3IDU5VjQ5QzI3IDQ4LjQ0NzcgMjcuNDQ3NyA0OCAyOCA0OEg1MkM1Mi41NTIzIDQ4IDUzIDQ4LjQ0NzcgNTMgNDlWNTlDNTMgNTkuNTUyMyA1Mi41NTIzIDYwIDUyIDYwWk0yOCA0OVY1OUg1MlY0OUgyOFoiIGZpbGw9IiNCREJEQkQiLz4KPC9zdmc+'; +} + +// 作品缩略图 URL +function buildThumbUrl($item) { + if (($item['Image'] ?? 0) > 0) { + $base = 'http://netlogo-cn.oss-cn-hongkong.aliyuncs.com/experiments/images/'; + $id = $item['ID']; + return $base . substr($id,0,4) . '/' . substr($id,4,2) . '/' . substr($id,6,2) . '/' . substr($id,8,16) . '/' . $item['Image'] . '.jpg!full'; + } + return 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjAiIGhlaWdodD0iNDUiIHZpZXdCb3g9IjAgMCA2MCA0NSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjYwIiBoZWlnaHQ9IjQ1IiBmaWxsPSIjRUNFQ0VDIi8+CjxwYXRoIGQ9Ik0zMCAyMk0zMiAxOEgzOEw0MCAyMkw0MiAxOEg0OEw0NSAyMkw0NyAxOEg1Mkw0NSAyNEgzNUwzMCAyMloiIGZpbGw9IiNCRUJFQkUiLz4KPC9zdmc+'; +} + +// 当前登录用户 ID (用于判断留言归属) +$currentUserId = $_SESSION['user_id'] ?? ''; +?> + + + + + + + <?= htmlspecialchars($targetUser['Nickname'] ?? '用户主页') ?> - Turtle Universe Web + + + + + +
+
+ +
+
+
+ +
+ + +
+
+ +
+ + +
+
+
+
+
作品
+
留言
+
粉丝
+
+ + +
+ + $list): + if (empty($list)) continue; + $title = $moduleOrder[$key] ?? $key; + ?> +
+
+ + 更多 > +
+
+ +
+ +
+
+
+ + + + +
+
+
+ +
+
+ + +
暂无作品
+ +
+ + + + + + +
+
+
+
+
+ + + + \ No newline at end of file