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!” というテキストは表示されないはずです。
調査・実装
この 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 化したい。