diff --git a/.gitignore b/.gitignore index 8178be2..9a1b986 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,7 @@ public/upload/* /public/.well-known /public/.user.ini .well-known -/runtime \ No newline at end of file +/runtime +/.sisyphus +/.trae +/token-usage-output.txt \ No newline at end of file diff --git a/app/api/controller/Articles.php b/app/api/controller/Articles.php index e454520..3baefd7 100644 --- a/app/api/controller/Articles.php +++ b/app/api/controller/Articles.php @@ -8,7 +8,10 @@ use app\BaseController; use app\model\Post; use app\model\PostCategory; use app\model\PostTag; -use League\CommonMark\CommonMarkConverter; +use League\CommonMark\Environment\Environment; +use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension; +use League\CommonMark\Extension\Table\TableExtension; +use League\CommonMark\MarkdownConverter; use think\Request; class Articles extends BaseController @@ -95,6 +98,9 @@ class Articles extends BaseController unset($post_data['tags']); } + // 禁止客户端设置的时间字段 + unset($post_data['create_time'], $post_data['update_time']); + $post_data['uid'] = uniqid(); $post_data['source'] = 'api'; $post_data['create_time'] = time(); @@ -110,16 +116,46 @@ class Articles extends BaseController $post_data['content_type'] = 'html'; } + // 校验 publish_time 格式(必须是 Y-m-d H:i:s) + if (isset($post_data['publish_time']) && !empty($post_data['publish_time'])) { + if (!preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/', $post_data['publish_time'])) { + return json_message('publish_time 格式错误,应为 Y-m-d H:i:s,如 2024-01-15 14:30:00'); + } + } + // content_type 白名单校验 $allowed_content_types = ['html', 'markdown']; if (!in_array($post_data['content_type'], $allowed_content_types)) { return json_message('无效的content_type', 500); } - // Markdown→HTML 自动转换 + // Markdown→HTML 自动转换(启用表格扩展) if ($post_data['content_type'] === 'markdown' && !empty($post_data['content'])) { - $converter = new CommonMarkConverter(['html_input' => 'strip', 'allow_unsafe_links' => false]); - $post_data['content_html'] = $converter->convert($post_data['content']); + $environment = Environment::createCommonMarkEnvironment(); + $environment->addExtension(new TableExtension()); + $converter = new MarkdownConverter($environment); + $post_data['content_html'] = $converter->convert($post_data['content'])->getContent(); + } + + // 提供字段默认值,避免数据库严格模式报错 + $default_fields = [ + 'jump_to_btn_title' => '', + 'jump_to_url' => '', + 'jump_to_url_status' => 0, + 'poster' => '', + 'desc' => '', + 'author_name' => '', + 'hits' => 0, + 'is_top' => 0, + 'sort' => 0, + 'files' => '', + 'pictures' => '', + 'tpl_name' => '', + ]; + foreach ($default_fields as $field => $default) { + if (!isset($post_data[$field])) { + $post_data[$field] = $default; + } } $model_post = Post::create($post_data); @@ -169,6 +205,16 @@ class Articles extends BaseController $post_data = $request->post(); unset($post_data['id']); + // 禁止客户端设置的时间字段 + unset($post_data['create_time'], $post_data['update_time']); + + // 校验 publish_time 格式(必须是 Y-m-d H:i:s) + if (isset($post_data['publish_time']) && !empty($post_data['publish_time'])) { + if (!preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/', $post_data['publish_time'])) { + return json_message('publish_time 格式错误,应为 Y-m-d H:i:s,如 2024-01-15 14:30:00'); + } + } + // categorys diff update if (isset($post_data['categorys'])) { $categorys = $post_data['categorys']; @@ -217,10 +263,33 @@ class Articles extends BaseController } } - // Markdown→HTML 自动转换 + // Markdown→HTML 自动转换(启用表格扩展) if (isset($post_data['content_type']) && $post_data['content_type'] === 'markdown' && !empty($post_data['content'])) { - $converter = new CommonMarkConverter(['html_input' => 'strip', 'allow_unsafe_links' => false]); - $post_data['content_html'] = $converter->convert($post_data['content']); + $environment = Environment::createCommonMarkEnvironment(); + $environment->addExtension(new TableExtension()); + $converter = new MarkdownConverter($environment); + $post_data['content_html'] = $converter->convert($post_data['content'])->getContent(); + } + + // 提供字段默认值,避免数据库严格模式报错 + $default_fields = [ + 'jump_to_btn_title' => '', + 'jump_to_url' => '', + 'jump_to_url_status' => 0, + 'poster' => '', + 'desc' => '', + 'author_name' => '', + 'hits' => 0, + 'is_top' => 0, + 'sort' => 0, + 'files' => '', + 'pictures' => '', + 'tpl_name' => '', + ]; + foreach ($default_fields as $field => $default) { + if (!isset($post_data[$field])) { + $post_data[$field] = $default; + } } $model_post->save($post_data); diff --git a/view/index/api_doc/index.html b/view/index/api_doc/index.html index a18e6f5..a0ceb03 100644 --- a/view/index/api_doc/index.html +++ b/view/index/api_doc/index.html @@ -270,11 +270,13 @@ X-API-Key: {api_key} posterstring否封面图 URL typestring否文章类型,默认 "1" statusint否状态,默认 0(草稿) - content_typestring否内容类型: "html"(默认) 或 "markdown" + content_typestring否内容类型: "html"(默认) 或 "markdown"
当为 "markdown" 时,系统会自动将 content 转换为 HTML 存储到 content_html 字段 categorysarray否分类 ID 数组,如 [1, 2] tagsarray否标签 ID 数组,如 [1, 2] + publish_timestring否发布时间,格式为 Y-m-d H:i:s,如 2024-01-15 14:30:00 +

注:create_timeupdate_time 由系统自动生成,客户端无需设置也无法修改。

请求示例(HTML)

curl -X POST \ @@ -337,11 +339,13 @@ X-API-Key: {api_key}
descstring否文章摘要 posterstring否封面图 URL statusint否状态 - content_typestring否内容类型: "html"(默认) 或 "markdown" + content_typestring否内容类型: "html"(默认) 或 "markdown"
当为 "markdown" 时,系统会自动将 content 转换为 HTML 存储到 content_html 字段 categorysarray否分类 ID 数组(全量覆盖) tagsarray否标签 ID 数组(全量覆盖) + publish_timestring否发布时间,格式为 Y-m-d H:i:s,如 2024-01-15 14:30:00 +

注:create_timeupdate_time 由系统自动生成,客户端无需设置也无法修改。

请求示例

curl -X POST \