DokuWiki コードブロックのダウンロードリンクに mime-type を指定する

DokuWiki にはそのままダウンロード可能なコンテンツを記述する機能があります。コードのプレゼンテーションとダウンロードリンクを同時に提供できるため、解説したコードをそのまま実装でき、圧倒的に手間が省けます。JavaScript のコードを書いて、そのまま外部から参照させる、ということができます。

ですが、出力はすべて text/plain で行われるため CSS や JavaScript のダウンロードリンクをソースに組み込みブラウザでインライン展開すると、mime-type が違うため怒られてしまいます。このため、ソースの種類にあった mime-type を返す修正を行ってみます。

また、Content-Disposition の指定が常に attachment になっているため、コードブロックの html コンテンツを iframe のコンテンツにしたり、ブラウザでそのまま表示したりできません。これも html の場合は inline を返す修正を試みます。

以下は CSS と JSON のダウンロードリンクサンプル。

test.css
div.displayNone {
  display: none;
}
test.json
[
  { "id": 1, "name": "abc1" },
  { "id": 2, "name": "abc2" },
  { "id": 3, "name": "abc3" }
]

これで、以下のリンクが得られますが、HTML の中でロードすると素のままでは mime-type が text/plain でロードされます。

もし、上記の CSS が text/css でロードされれば、CSS が効いて以下の2つのテキスト

  • “This should be visible!”
  • “This should be invisible!”

のうち、“This should be invisible!” というテキストは表示されないはずです。

This should be visible !
This should be invisible !

この codeblock のダウンロード処理を探すと、inc/parser/code.php で値を返していることが判ります。ここでは、どのリソースも text/plain で返されているため、css が解釈されていません。

<file> タグ内の言語指定に従った mime-type を返す実装を行います。こうすることで、コンテンツとして記述した CSS を、実際のソースとして指定可能となり、コピペ無して再利用できます。

    /**
     * Send the wanted code block to the browser
     *
     * When the correct block was found it exits the script.
     *
     * @param string $text
     * @param string $language
     * @param string $filename
     */
    public function code($text, $language = null, $filename = '') {
        global $INPUT;
        if(!$language) $language = 'txt';
        $language = preg_replace(PREG_PATTERN_VALID_LANGUAGE, '', $language);
        if(!$filename) $filename = 'snippet.'.$language;
        $filename = \dokuwiki\Utf8\PhpString::basename($filename);
        $filename = \dokuwiki\Utf8\Clean::stripspecials($filename, '_');

        // send CRLF to Windows clients
        if(strpos($INPUT->server->str('HTTP_USER_AGENT'), 'Windows') !== false) {
            $text = str_replace("\n", "\r\n", $text);
        }

        if($this->_codeblock == $INPUT->str('codeblock')) {
            //header("Content-Type: text/plain; charset=utf-8");  // コメントアウト
            header($this->getContentType($language));             // 追加
            //header("Content-Disposition: attachment; filename=$filename");  // コメントアウト
            header($this->getContentDisposition($language, $filename));       // 追加
            header("X-Robots-Tag: noindex");
            echo trim($text, "\r\n");
            exit;
        }

        $this->_codeblock++;
    }

    /* この関数を追加 */
    public function getContentType($lang) {
        if ($lang === 'html4strict') {
            return "Content-Type: text/html; charset=utf-8";
        } elseif ($lang === 'stylesheet' || $lang === 'css') {
            return "Content-Type: text/css; charset=utf-8";
        } elseif ($lang === 'javascript' || $lang === 'js') {
            return "Content-Type: text/javascript; charset=utf-8";
        } elseif ($lang === 'json') {
            return "Content-Type: application/json; charset=utf-8";
        } else {
            return "Content-Type: text/plain; charset=utf-8";
        }
    }

    /* この関数を追加 */
    public function getContentDisposition($lang, $filename) {
        if ($lang === 'html4strict') {
            return "Content-Disposition: inline";
        } else {
            return "Content-Disposition: attachment; filename=$filename";
        }
    }

DokuWiki のソースに手を加えなくていいよう、Plugin 化したい。

  • dokuwiki/downloadable_code_block_with_mimetype.txt
  • 最終更新: 2021/03/21 22:07
  • by admin