php-markdownでバニラPHPなコードブロック処理

2021/07/20

今回はピュアなPHPで実装する必要があったので 「php-markdown」を使ったMarkDown 処理を試してみました。

php-markdown

Composer でインストール

Composermichelf/php-markdown をインストールします。

% composer require michelf/php-markdown

コードブロックの対応は MarkdownExtra を使う

単純にマークダウンを使うときは、Markdown で大丈夫ですが、コードブロックの pre, code タグに対応していません。

use Michelf\Markdown;

コードブロックに対応するには、MarkdownExtra を利用します。

use Michelf\MarkdownExtra;

MarkDown を HTML に変換する

MarkDown を HTML に変換するのはこれだけです。

$markdown = new MarkdownExtra();
$content = $markdown->transform($content);

ただ、 prism.js にも対応させたいので code_class_prefixlanguage- をつけておきます。関数とかにまとめるとこんな感じです。

function markdownToHtml($content){
    $markdown = new MarkdownExtra();
    $markdown->code_class_prefix = 'language-';
    return $markdown->transform($content);
}

//マークダウン文章
$markdown = "
    ``` php
    function hoge($value)
    {
        return $value;
    }
    ```
";

//HTMLに変換
$html = markdownToHtml($markdown);

MarkdownExtra の pre, code 処理

これはマニュアルに載ってないので MarkdownExtra のソースコードを調べてみました。 $matches は文章に正規表現をかけた配列で、クラス名は index=2 にマッチします。あとは、 $code_class_prefix をくっつけてますね。

        protected function _doFencedCodeBlocks_callback($matches) {
        $classname =& $matches[2];
        $attrs     =& $matches[3];
        $codeblock = $matches[4];

        if ($this->code_block_content_func) {
            $codeblock = call_user_func($this->code_block_content_func, $codeblock, $classname);
        } else {
            $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
        }

        $codeblock = preg_replace_callback('/^\n+/',
            array($this, '_doFencedCodeBlocks_newlines'), $codeblock);

        $classes = array();
        if ($classname !== "") {
            if ($classname[0] === '.') {
                $classname = substr($classname, 1);
            }
            $classes[] = $this->code_class_prefix . $classname;
        }
        $attr_str = $this->doExtraAttributes($this->code_attr_on_pre ? "pre" : "code", $attrs, null, $classes);
        $pre_attr_str  = $this->code_attr_on_pre ? $attr_str : '';
        $code_attr_str = $this->code_attr_on_pre ? '' : $attr_str;
        $codeblock  = "<pre$pre_attr_str><code$code_attr_str>$codeblock</code></pre>";

        return "\n\n".$this->hashBlock($codeblock)."\n\n";
    }