Parsedown PHP 版的 Markdown 解析器

发布于 2020-02-01 22:16:49 字数 8905 浏览 1956 评论 0

Parsedown 是一个用 PHP 编写的 Markdown 解析器,使用它可以将 Markdown 格式的内容快速转化成 HTML 格式的内容。

特点

  • 单文件:整个解析器只有一个文件,方便调用和安装配置
  • 超级快:处理 Markdown 非常的快,几乎感觉不到延迟
  • 可扩展性强
  • 代码托管于 Github,开源免费使用
  • 支持 Markdown 第三方扩展

安装

composer require erusev/parsedown

或者下载最新版本的源码,然后引入Parsedown.php文件。

简单用法

echo Parsedown::instance()->text('Hello _Parsedown_!'); 
# 输出:
# <p>Hello <em>Parsedown</em>!</p>

或者这样使用

$Parsedown = new Parsedown();
echo $Parsedown->text('Hello _Parsedown_!'); 
# 输出:
# <p>Hello <em>Parsedown</em>!</p>

设置参数

echo Parsedown::instance()
   ->setBreaksEnabled(true) # enables automatic line breaks
   ->text("1st line \n 2nd line"); 

# Output:
# <p>1st line <br /> 2nd line</p>
echo Parsedown::instance()
   ->setMarkupEscaped(true) # escapes markup (HTML)
   ->text("<div><strong>*Some text*</strong></div>");

# Output:
# <p><div><strong><em>Some text</em></strong></div></p>
echo Parsedown::instance()
   ->setUrlsLinked(false) # prevents automatic linking of URLs
   ->text("You can find Parsedown at http://parsedown.org");

# Output:
# <p>You can find Parsedown at http://parsedown.org</p>

Security

Parsedown is capable of escaping user-input within the HTML that it generates. Additionally Parsedown will apply sanitisation to additional scripting vectors (such as scripting link destinations) that are introduced by the markdown syntax itself.

To tell Parsedown that it is processing untrusted user-input, use the following:

$Parsedown->setSafeMode(true);

If instead, you wish to allow HTML within untrusted user-input, but still want output to be free from XSS it is recommended that you make use of a HTML sanitiser that allows HTML tags to be whitelisted, like HTML Purifier.

In both cases you should strongly consider employing defence-in-depth measures, like deploying a Content-Security-Policy (a browser security feature) so that your page is likely to be safe even if an attacker finds a vulnerability in one of the first lines of defence above.

Security of Parsedown Extensions

Safe mode does not necessarily yield safe results when using extensions to Parsedown. Extensions should be evaluated on their own to determine their specific safety against XSS.

Escaping HTML

WARNING: This method isn't safe from XSS!

If you wish to escape HTML in trusted input, you can use the following:

$Parsedown->setMarkupEscaped(true);

Beware that this still allows users to insert unsafe scripting vectors, such as links like [xss](javascript:alert%281%29).

自定义扩展

Disable Element

This example disables Header elements. That is, both Atx Header and Setext Header elements.

class Extension extends Parsedown{

    protected function blockHeader($Line) {
        return;
    }

    protected function blockSetextHeader($Line, array $Block = null) {
        return;
    }

}

You can use the same approach for other elements types. This includes inline element types. For example, to disable Image elements you should override inlineImage.

Note that to disable all headers you should also disable support for HTML. You can do that by setting the MarkupEscaped option to true.

Change Element Markup

This example prepends a base path to the src of Image elements.

class Extension extends Parsedown{

    private $baseImagePath = 'http://cdn.example.com/';

    protected function inlineImage($excerpt) {
        $image = parent::inlineImage($excerpt);

        if ( ! isset($image)) {
            return null;
        }

        $image['element']['attributes']['src'] = $this->baseImagePath . $image['element']['attributes']['src'];

        return $image;
    }

}

You can use the same approach for other element types.

Add Inline Element

This example adds a ColoredText element. You can find a description of this element at https://github.com/erusev/parsedown/issues/262.

class Extension extends Parsedown{

    function __construct(){
        $this->InlineTypes['{'][]= 'ColoredText';

        $this->inlineMarkerList .= '{';
    }

    protected function inlineColoredText($excerpt) {
        if (preg_match('/^{c:([#\w]\w+)}(.*?){\/c}/', $excerpt['text'], $matches)) {
            return array(

                // How many characters to advance the Parsedown's
                // cursor after being done processing this tag.
                'extent' => strlen($matches[0]), 
                'element' => array(
                    'name' => 'span',
                    'text' => $matches[2],
                    'attributes' => array(
                        'style' => 'color: ' . $matches[1],
                    ),
                ),

            );
        }
    }
}

You can use the same approach for other element types.

Add Multi-Line Element

This example extends the bold element (**) to work on multiple lines.

class Extension extends Parsedown{

    /**
     * The array index is the first character of the pattern to match.
     * It is not possible to define patterns longer than one character directly here, as only the first
     * character of the line will be checked. (eg. Setting $this->BlockTypes['{tag'] won't work.)
     *
     * The second array is a list of all functions that should be called when the character is found.
     *
     * Leave out the 'block' or 'inline' part of the function name, as it will be prepended automatically.
     */
    function __construct() {
        $this->BlockTypes['*'][] = 'BoldText'; 
    }

    protected function blockBoldText($line, $block) {
        if (preg_match('/^\*\*/', $line['text'], $matches)) {
            return array(
                'char' => $line['text'][0],
                'element' => array(
                    'name' => 'strong',
                    'text' => '',
                ),
            );
        }
    } 

    /**
     * Appending the word `continue` to the function name will cause this function to be
     * called to process any following lines, until $block['complete'] is set to be 'true'.
     */
    protected function blockBoldTextContinue($line, $block) {
        if (isset($block['complete'])) {
            return;
        }

        // A blank newline has occurred.
        if (isset($block['interrupted'])) {
            $block['element']['text'] .= "\n";
            unset($block['interrupted']);
        }

        // Check for end of the block. 
        if (preg_match('/\*\*/', $line['text'])) {
            $block['element']['text'] = substr($block['element']['text'], 1);

            // This will flag the block as 'complete':
            // 1. The 'continue' function will not be called again.
            // 2. The 'complete' function will be called instead.
            $block['complete'] = true;
            return $block;
        }
        
        $block['element']['text'] .= "\n" . $line['body'];
        
        return $block;
    }

    /**
     * Appending the word `complete` to the function name will cause this function to be
     * called when the block is marked as *complete* (see the previous method).
     */
    protected function blockBoldTextComplete($block) {
        return $block;
    }

}

相关链接

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84961 人气
更多

推荐作者

马化腾

文章 0 评论 0

thousandcents

文章 0 评论 0

辰『辰』

文章 0 评论 0

ailin001

文章 0 评论 0

冷情妓

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文