- 追加された行はこの色です。
- 削除された行はこの色です。
#author("2021-12-05T15:13:31+09:00","","")
#author("2021-12-05T21:35:58+09:00","","")
* URLカスタマイズの仕組み [#t65b6b10]
- ページ: [[BugTrack]]
- 投稿者: [[umorigu]]
- 優先順位: 低
- 状態: 着手
- 状態: 完了
- カテゴリー: 本体新機能
- 投稿日: 2021-11-27 (土) 18:12:19
- バージョン: 1.5.3
- リリース予定バージョン: 1.5.4
#contents
** メッセージ [#p2d503a3]
PukiWiki の定番のカスタマイズとして、ページURLを変えるものがある。これを本体書き換え無しで行うための仕組みを導入する。
URL (path, query 部分) の例
「階層1/名前」というページの場合
- /?%E9%9A%8E%E5%B1%A41/%E5%90%8D%E5%89%8D (標準)
-- 最近のブラウザではアドレス欄でURL decodeされて 「/?階層1/名前」という表示になることが多い
- /%E9%9A%8E%E5%B1%A41/%E5%90%8D%E5%89%8D (Path (サーバー上のファイル) として扱う)
- /%E9%9A%8E%E5%B1%A41/%E5%90%8D%E5%89%8D.html (さらに拡張子を.html にする)
- /?&a66dc2fa8e (短縮URLプラグイン [[official:自作プラグイン/s.inc.php]] での例示
-- 短縮URLは通常URLにリダイレクトするパターンと、直接表示するパターンの2つ
- /a66dc2fa8e (短縮URLをさらにpath風に見せる)
- /123.html (pgid プラグイン利用?)
** 実動作サンプル [#d41e13c1]
** 実動作サンプル [#samples]
*** (1) 通常 [#nf0c7789]
- https:// pukiwiki.osdn.jp/_samples/1/
-- https:// pukiwiki.osdn.jp/_samples/1/?%E9%9A%8E%E5%B1%A41/%E5%90%8D%E5%89%8D
--- アドレス欄 「/?階層1/名前」
*** (2) 末尾 (ページ名).html [#d77d4243]
- https:// pukiwiki.osdn.jp/_samples/2/
-- https:// pukiwiki.osdn.jp/_samples/2/?%E9%9A%8E%E5%B1%A41/%E5%90%8D%E5%89%8D.html
--- アドレス欄 「/?階層1/名前.html」
pukiwiki.ini.php
// Page-URI mapping handler ( See https:// pukiwiki.osdn.jp/?PukiWiki/PageURI )
class HtmlSuffixPageURIHandler extends PukiWikiStandardPageURIHandler {
function get_page_uri_virtual_query($page) {
return '?' . pagename_urlencode($page) . '.html';
}
function get_page_from_query_string($query_string) {
$param1st = preg_replace("#^([^&]*)&.*$#", "$1", $query_string);
if ($param1st == '') {
return null; // default page
}
if (strpos($param1st, '=') !== FALSE) {
// Found '/?key=value' (NG chars)
return FALSE; // Error page
}
$base = preg_replace('#\.html$#', '', $param1st);
if ($param1st === $base) {
return FALSE; // Error
}
$page = urldecode($base);
$page2 = input_filter($page);
if ($page !== $page2) {
return FALSE; // Error page
}
return $page2;
}
}
$page_uri_handler = new HtmlSuffixPageURIHandler();
*** (3) ページ名を path に見せる [#u315499d]
ページ名の前に '?' がつかず、ページがそのままサーバー上のファイルのように見えるURL
- https:// pukiwiki.osdn.jp/_samples/3/
-- https:// pukiwiki.osdn.jp/_samples/3/%E9%9A%8E%E5%B1%A41/%E5%90%8D%E5%89%8D
--- アドレス欄 「/階層1/名前」
pukiwiki.ini.php:
image ディレクトリ
define('IMAGE_DIR', '/_samples/3/image/');
トップページの絶対URL
$script = 'https:// pukiwiki.osdn.jp/_samples/3/';
パスのカスタマイズ ('?' をつけない)
各ページで相対パスでなくルート相対パスを利用するために pkwk_base_uri_type_stack_push(PKWK_URI_ROOT); を実行しておく。
// Page-URI mapping handler ( See https:// pukiwiki.osdn.jp/?PukiWiki/PageURI )
class VirtualPathPageURIHandler extends PukiWikiStandardPageURIHandler {
function get_page_uri_virtual_query($page) {
return pagename_urlencode($page);
}
}
pkwk_base_uri_type_stack_push(PKWK_URI_ROOT);
// $page_uri_handler = null; // default
$page_uri_handler = new VirtualPathPageURIHandler();
.htaccess
このカスタマイズはPHPだけでは実現できず、Webサーバー側でパスをクエリ文字列に変換する必要がある。 Apacheでの指定は以下のようになる。
RewriteEngine On
RewriteCond %{REQUEST_URI} !(^/$)
RewriteCond %{REQUEST_URI} !(^/image/)
RewriteCond %{REQUEST_URI} !(^/skin/)
RewriteCond %{REQUEST_FILENAME} !(\.php$)
RewriteRule ^(.+)$ /_samples/3/?$1
意味: path が /, /image/..., /skin/... 以外の場合は /?{path} というリクエストに変換する
/skin/pukiwiki.skin.php
スキンファイルもいくつか、参照ファイルをルート相対パスで指定する必要がある。 (ここでは一部のみ抜粋)
<link rel="stylesheet" type="text/css" href="/_samples/3/<?php echo SKIN_DIR ?>pukiwiki.css" />
<script type="text/javascript" src="/_samples/3/skin/main.js" defer></script>
*** (6) 短縮URLプラグイン ([[s.inc.php>official:自作プラグイン/s.inc.php]]) による常時短縮URLのカスタマイズ [#dee2c813]
- https:// pukiwiki.osdn.jp/_samples/6/
-- https:// pukiwiki.osdn.jp/_samples/6/?&a66dc2fa8e
--- (リダイレクト無し)
--- アドレス欄 「/?&a66dc2fa8e」
pukiwiki.ini.php:
// Page-URI mapping handler ( See https:// pukiwiki.osdn.jp/?PukiWiki/PageURI )
class ShortUrlPageURIHandler extends PukiWikiStandardPageURIHandler {
function get_page_uri_virtual_query($page) {
exist_plugin('s'); // Load s.inc.php
$page_id = plugin_s_get_page_id($page);
if ($page_id) {
return '?&' . $page_id;
}
return '?' . pagename_urlencode($page);
}
function get_page_from_query_string($query_string) {
exist_plugin('s'); // Load s.inc.php
$m = array();
if (preg_match('#^\&([0-9a-f]{10})$#', $query_string, $m)) {
$page = plugin_s_get_page_from_page_id($m[1]);
return $page;
}
return parent::get_page_from_query_string($query_string);
}
}
// $page_uri_handler = null; // default
$page_uri_handler = new ShortUrlPageURIHandler();
注意: ページURLを取得するのに(初回のみ)ファイル生成とファイル存在チェックを伴うため、ページ数が数万を超えるような大規模サイトでは一覧などでパフォーマンスの低下が発生します。
*** (7) 短縮URLプラグイン ([[s.inc.php>official:自作プラグイン/s.inc.php]]) によるリダイレクトのカスタマイズ [#b55ec583]
- https:// pukiwiki.osdn.jp/_samples/7/
-- https:// pukiwiki.osdn.jp/_samples/7/?&a66dc2fa8e
--- https:// pukiwiki.osdn.jp/_samples/7/?%E9%9A%8E%E5%B1%A41/%E5%90%8D%E5%89%8D にリダイレクト
/?&a66dc2fa8e
--- アドレス欄 「/?階層1/名前」
pukiwiki.ini.php:
// Page-URI mapping handler ( See https:// pukiwiki.osdn.jp/?PukiWiki/PageURI )
class ShortUrlRedirectPageURIHandler extends PukiWikiStandardPageURIHandler {
function filter_raw_query_string($query_string) {
$m = array();
if (preg_match('#^\&([0-9a-f]{10})$#', $query_string, $m)) {
return 'cmd=s&k=' . $m[1];
}
return $query_string;
}
}
// $page_uri_handler = null; // default
$page_uri_handler = new ShortUrlRedirectPageURIHandler();
** URLカスタマイズの2パターン [#f92aa1c1]
表示に関わる
- (a) PHPのみで実現できるもの
-- "?" を使って、PHPファイルとクエリパラメータを分けているもの
- (b) Apache/nginxなど、WebサーバーでのURLマッピング操作が必要なもの
-- "?" を使わず、PHPファイルのURLと本来クエリパラメータとして渡す部分を両方 path として見せているもの
** 参照 [#q540935c]
- [[BugTrack/2213]] get_page_uri($page) 関数
- [[official:自作プラグイン/s.inc.php]]
** 対象 [#d873298b]
- ページの表示 (readプラグインのaction)
- read以外のactionのURLは対象外 (標準のまま)
** 設計 [#f5b72059]
- 各ページのURLを作成しているのは get_page_uri($page) である。get_page_uri() 内の1か所を変更するだけですべてのURLが書き換わる (のが理想)
- 各種プラグインも get_page_uri($page) によって各ページのURLを生成すること
-- get_page_uri() ができたのが PukiWiki 1.5.2 (2019年3月リリース) なのでこれ以前に作られたプラグインはそもそも対応していない
クラス
class PukiWikiStandardPageURIHandler {
// QueryStringの変換
function filter_raw_query_string($query_string);
// ページ名からURIのページ表現部分を生成
function get_page_uri_fragment($page);
// クエリストリングからページ名を取得
function get_page_from_query_string($query_string);
}
lib/init.php:397
// cmdもpluginも指定されていない場合は、QUERY_STRINGをページ名かInterWikiNameであるとみなす
if (! isset($vars['cmd']) && ! isset($vars['plugin'])) {
$get['cmd'] = $post['cmd'] = $vars['cmd'] = 'read';
$arg = preg_replace("#^([^&]*)&.*$#", "$1", $arg);
if ($arg == '') $arg = $defaultpage;
if (strpos($arg, '=') !== false) $arg = $defaultpage; // Found '/?key=value'
$arg = urldecode($arg);
$arg = strip_bracket($arg);
$arg = input_filter($arg);
$get['page'] = $post['page'] = $vars['page'] = $arg;
}
** 対応していないプラグインへの対応 [#unsuppoeted_plugins]
各ページへのリンクURL取得手段として PukiWiki 1.5.2 から導入された get_page_uri($page) を利用していないプラグインはカスタムURL対応になりません。
ページURLに get_page_uri($page) を利用するよう書き換えてください。
** カスタマイズ内容 [#hc888a0e]
(URL生成)
各ページのURL は get_base_uri() + 「ページを表すURL片」で表現される。 (例: "?FrontPage", "?BugTrack/2525")
ページ名を引数にしてこの「ページを表すURL片」の生成する関数を登録できるようにする。
(ページの表示)
「ページを表すURL片」を受け取って、表示(または別のプラグインアクション)を行う関数を登録できるようにする。
** 既存ロジック不明なところ [#ze114a2e]
make_link.php
クラス Link_interwikiname - function set()
$url = get_interwiki_url($name, $this->param);
$this->url = ($url === FALSE) ?
get_base_uri() . '?' . pagename_urlencode('[[' . $name . ':' . $this->param . ']]') :
htmlsc($url);
? に続けて [[ name : param ]] を設定しているがこの記述で read しようとするとエラーになる。どういう条件でここに入るのか不明
--------
- 試作してみました。 commit:75279a82c7 commit:9f9868f113 まだ取り込まず、試行錯誤の段階です -- [[umorigu]] &new{2021-11-28 (日) 20:22:55};
- 試作してみました。まだ取り込まず、試行錯誤の段階です -- [[umorigu]] &new{2021-11-28 (日) 20:22:55};
- 対応しました。 1.5.4 のリリースに含めます。 commit:1dd1bb561c, commit:fc0f35942a, commit:0ca033f598 -- [[umorigu]] &new{2021-12-05 (日) 18:53:20};
#comment