S2OJ/web/app/models/UOJBlogEditor.php

227 lines
6.0 KiB
PHP
Raw Normal View History

2016-07-18 16:39:37 +00:00
<?php
class UOJBlogEditor {
public $type = 'blog';
public $name;
public $blog_url;
public $save;
2022-11-06 02:26:21 +00:00
public $cur_data = [];
public $post_data = [];
public $show_editor = true;
public $show_tags = true;
2023-01-30 12:27:53 +00:00
2022-11-06 02:26:21 +00:00
public $label_text = [
2016-07-18 16:39:37 +00:00
'title' => '标题',
'tags' => '标签(多个标签用逗号隔开)',
'content' => '内容',
'view blog' => '查看博客',
'blog visibility' => '博客可见性',
'private' => '未公开',
'public' => '公开'
2022-11-06 02:26:21 +00:00
];
2023-01-30 12:27:53 +00:00
2016-07-18 16:39:37 +00:00
public $validator = array();
2023-01-30 12:27:53 +00:00
2016-07-18 16:39:37 +00:00
function __construct() {
global $REQUIRE_LIB;
$REQUIRE_LIB['blog-editor'] = '';
2023-01-30 12:27:53 +00:00
2022-11-06 02:26:21 +00:00
$this->validator = [
2023-01-30 12:27:53 +00:00
'title' => function (&$title) {
2016-07-18 16:39:37 +00:00
if ($title == '') {
return '标题不能为空';
}
if (strlen($title) > 100) {
return '标题不能超过 100 个字节';
}
if (HTML::escape($title) === '') {
return '无效编码';
}
return '';
},
2023-01-30 12:27:53 +00:00
'content_md' => function (&$content_md) {
2016-07-18 16:39:37 +00:00
if (strlen($content_md) > 1000000) {
return '内容过长';
}
return '';
},
2023-01-30 12:27:53 +00:00
'tags' => function (&$tags) {
2016-07-18 16:39:37 +00:00
$tags = str_replace('', ',', $tags);
$tags_raw = explode(',', $tags);
if (count($tags_raw) > 10) {
return '标签个数不能超过10';
}
$tags = array();
foreach ($tags_raw as $tag) {
$tag = trim($tag);
if (strlen($tag) == 0) {
continue;
}
if (strlen($tag) > 30) {
2023-01-30 12:27:53 +00:00
return '标签 “' . HTML::escape($tag) . '” 太长';
2016-07-18 16:39:37 +00:00
}
if (in_array($tag, $tags, true)) {
2023-01-30 12:27:53 +00:00
return '标签 “' . HTML::escape($tag) . '” 重复出现';
2016-07-18 16:39:37 +00:00
}
$tags[] = $tag;
}
return '';
}
2022-11-06 02:26:21 +00:00
];
2016-07-18 16:39:37 +00:00
}
2023-01-30 12:27:53 +00:00
2016-07-18 16:39:37 +00:00
public function validate($name) {
if (!isset($_POST["{$this->name}_{$name}"])) {
return '不能为空';
}
$this->post_data[$name] = $_POST["{$this->name}_{$name}"];
$val = $this->validator[$name];
return $val($this->post_data[$name]);
}
private function receivePostData() {
$errors = array();
$keys = array('title');
if ($this->show_tags) {
$keys[] = 'tags';
}
if ($this->show_editor) {
$keys[] = 'content_md';
}
foreach ($keys as $name) {
2016-07-18 16:39:37 +00:00
$cur_err = $this->validate($name);
if ($cur_err) {
$errors[$name] = $cur_err;
}
}
if ($errors) {
die(json_encode($errors));
}
crsf_defend();
2023-01-30 12:27:53 +00:00
2016-07-18 16:39:37 +00:00
$this->post_data['is_hidden'] = isset($_POST["{$this->name}_is_hidden"]) ? 1 : 0;
2023-01-30 12:27:53 +00:00
$purifier = HTML::purifier();
$parsedown = HTML::parsedown();
2023-01-30 12:27:53 +00:00
2016-07-18 16:39:37 +00:00
$this->post_data['title'] = HTML::escape($this->post_data['title']);
2023-01-30 12:27:53 +00:00
if ($this->show_editor) {
if ($this->type == 'blog') {
2022-10-18 00:53:57 +00:00
$this->post_data['content'] = $parsedown->text($this->post_data['content_md']);
2016-07-18 16:39:37 +00:00
if (preg_match('/^.*<!--.*readmore.*-->.*$/m', $this->post_data['content'], $matches, PREG_OFFSET_CAPTURE)) {
$content_less = substr($this->post_data['content'], 0, $matches[0][1]);
$content_more = substr($this->post_data['content'], $matches[0][1] + strlen($matches[0][0]));
2023-01-30 12:27:53 +00:00
$this->post_data['content'] = $purifier->purify($content_less) . '<!-- readmore -->' . $purifier->purify($content_more);
} else {
$this->post_data['content'] = $purifier->purify($this->post_data['content']);
}
} elseif ($this->type == 'slide') {
$content_array = yaml_parse($this->post_data['content_md']);
if ($content_array === false || !is_array($content_array)) {
die(json_encode(array('content_md' => '不合法的 YAML 格式')));
}
2023-01-30 12:27:53 +00:00
$marked = function ($md) use ($parsedown, $purifier) {
2022-10-09 23:35:48 +00:00
$dom = new DOMDocument;
$dom->loadHTML(mb_convert_encoding($parsedown->text($md), 'HTML-ENTITIES', 'UTF-8'));
$elements = $dom->getElementsByTagName('li');
2023-01-30 12:27:53 +00:00
2022-10-09 23:35:48 +00:00
foreach ($elements as $element) {
2023-01-30 12:27:53 +00:00
$element->setAttribute(
'class',
$element->getAttribute('class') . ' fragment'
);
}
2022-10-09 23:35:48 +00:00
return $purifier->purify($dom->saveHTML());
};
2023-01-30 12:27:53 +00:00
$config = array();
$this->post_data['content'] = '';
foreach ($content_array as $slide_name => $slide_content) {
if (is_array($slide_content) && is_array($slide_content['config'])) {
foreach (array('theme') as $config_key) {
if (is_string($slide_content['config'][$config_key]) && strlen($slide_content['config'][$config_key]) <= 30) {
$config[$config_key] = $slide_content['config'][$config_key];
}
2016-07-18 16:39:37 +00:00
}
continue;
2016-07-18 16:39:37 +00:00
}
2023-01-30 12:27:53 +00:00
$this->post_data['content'] .= '<section>';
2023-01-30 12:27:53 +00:00
if (is_string($slide_content)) {
$this->post_data['content'] .= $marked($slide_content);
} elseif (is_array($slide_content)) {
if (is_array($slide_content['children'])) {
foreach ($slide_content['children'] as $cslide_name => $cslide_content) {
$this->post_data['content'] .= '<section>';
$this->post_data['content'] .= $marked($cslide_content);
$this->post_data['content'] .= '</section>';
}
2016-07-18 16:39:37 +00:00
}
}
$this->post_data['content'] .= "</section>\n";
2016-07-18 16:39:37 +00:00
}
$this->post_data['content'] = json_encode($config) . "\n" . $this->post_data['content'];
2016-07-18 16:39:37 +00:00
}
}
}
2023-01-30 12:27:53 +00:00
2016-07-18 16:39:37 +00:00
public function handleSave() {
$save = $this->save;
$this->receivePostData();
$ret = $save($this->post_data);
if (!$ret) {
$ret = array();
}
2023-01-30 12:27:53 +00:00
2016-07-18 16:39:37 +00:00
if (isset($_POST['need_preview'])) {
ob_start();
if ($this->type == 'blog') {
2023-01-30 12:27:53 +00:00
$req_lib = [
'mathjax' => '',
2023-02-08 13:42:53 +00:00
'hljs' => '',
2023-01-30 12:27:53 +00:00
];
2023-02-08 13:42:53 +00:00
echoUOJPageHeader('博客预览', [
'ShowPageHeader' => false,
'REQUIRE_LIB' => $req_lib,
2023-02-28 09:32:22 +00:00
'PageBodyClass' => 'py-3',
2023-02-08 13:42:53 +00:00
]);
2022-09-18 12:47:21 +00:00
echo '<article class="markdown-body">';
2016-07-18 16:39:37 +00:00
echo $this->post_data['content'];
echo '</article>';
2023-02-08 13:42:53 +00:00
echoUOJPageFooter(['ShowPageFooter' => false]);
2020-06-25 12:41:16 +00:00
} elseif ($this->type == 'slide') {
2016-07-18 16:39:37 +00:00
uojIncludeView('slide', array_merge(
UOJContext::pageConfig(),
2022-11-06 02:26:21 +00:00
[
2016-07-18 16:39:37 +00:00
'PageTitle' => '幻灯片预览',
'content' => $this->post_data['content']
2022-11-06 02:26:21 +00:00
]
2016-07-18 16:39:37 +00:00
));
}
$ret['html'] = ob_get_contents();
ob_end_clean();
}
2023-01-30 12:27:53 +00:00
2016-07-18 16:39:37 +00:00
die(json_encode($ret));
}
2023-01-30 12:27:53 +00:00
2016-07-18 16:39:37 +00:00
public function runAtServer() {
if (isset($_POST["save-{$this->name}"])) {
$this->handleSave();
}
}
public function printHTML() {
global $REQUIRE_LIB;
2023-01-30 12:27:53 +00:00
2022-11-06 02:26:21 +00:00
uojIncludeView('blog-editor', ['editor' => $this, 'REQUIRE_LIB' => $REQUIRE_LIB]);
2016-07-18 16:39:37 +00:00
}
}