public function parse($markdown) { if (!is_string($markdown)) { throw new InvalidArgumentException('markdown', 'type_invalid'); } if (!mb_check_encoding($markdown, 'UTF-8')) { throw new InvalidArgumentException('markdown', 'encoding_invalid'); } // 目的:我们希望用户输入在 code block 以外的尖括号当成普通字符对待,而不是 HTML 标签被处理 // 替换所有尖括号(成对出现时会被当成标签而忽略) $markdown = str_replace('<', '<', $markdown); $markdown = str_replace('>', '>', $markdown); $html = Marked::render($markdown, ['gfm' => true, 'tables' => true, 'breaks' => true, 'sanitize' => false, 'langPrefix' => 'prettyprint lang-']); // 恢复 <code> 中的特殊符号(它们被 escape 了两次,第二次是 markdown 引擎) $pBegin = 0; while (false !== ($pBegin = stripos($html, '<code>', $pBegin))) { $pEnd = strpos($html, '</code>', $pBegin + 6); if ($pEnd === false) { break; } $inner = substr($html, $pBegin + 6, $pEnd - $pBegin - 6); $inner = str_replace('&lt;', '<', $inner); $inner = str_replace('&gt;', '>', $inner); $html = substr_replace($html, $inner, $pBegin + 6, $pEnd - $pBegin - 6); $pBegin += strlen($inner) + 6; } // 由 HTML Purifier 进一步过滤内容确保输入安全 $html = $this->purifier->purify($html); return $html; }
public static function edit($title, $md, $url, $time = null, $category = null, $tags = [], $state = self::STATE_OPEN, $id = null) { if ($id !== null && mb_strlen((string) $id) !== 24) { throw new \Exception('Invalid argument: id'); } if ($time == null) { $time = time(); } $html = \Breezewish\Marked\Marked::render($md, ['langPrefix' => 'prettyprint lang-', 'breaks' => true]); if (P_HTML_FILTER) { $html = \BWBlog\Escaper::purify($html); } // page doesn't need short introductions if ($state != self::STATE_PAGE) { // process introduction foreach (['<!-- more -->', '<!--more -->', '<!-- more-->', '<!--more-->'] as $meta) { $pos = mb_stripos($html, $meta, 0, 'UTF-8'); if ($pos !== false) { break; } } if ($pos !== false) { $intro = \BWBlog\Utils::closeTags(mb_substr($html, 0, $pos)); $more = true; } else { $intro = $html; $more = false; } } else { $more = false; $intro = ''; } // page uses direct url if ($state != self::STATE_PAGE) { $rest_url = \BWBlog\Utils::trimRestURI(str_replace('\\', '/', date('Y/m/d/', $time) . $url)); } else { $rest_url = \BWBlog\Utils::trimRestURI(str_replace('\\', '/', 'page/' . $url)); } $doc = ['title' => $title, 'content' => ['markdown' => $md, 'html' => $html, 'introhtml' => $intro, 'more' => $more], 'time' => ['main' => $time], 'url' => $url, 'rest_url' => $rest_url, 'category' => $category, 'lcategory' => strtolower($category), 'tags' => $tags, 'ltags' => array_map('strtolower', array_map('trim', $tags)), 'state' => (int) $state]; global $db; if ($id === null) { // create $doc['time']['create'] = time(); $db->selectCollection(MONGO_PREFIX . 'posts')->insert($doc); return $doc['_id']; } else { // update $doc['time']['edit'] = time(); $result = $db->selectCollection(MONGO_PREFIX . 'posts')->findAndModify(['_id' => new \MongoId((string) $id)], ['$set' => $doc], ['_id' => 1], ['upsert' => true, 'new' => true]); return $result['_id']; } }