URLカスタマイズの仕組み

メッセージ

PukiWiki の定番のカスタマイズとして、ページURLを変えるものがある。これを本体書き換え無しで行うための仕組みを導入する。

URL (path, query 部分) の例

「階層1/名前」というページの場合

※このページで利用されている 短縮URLプラグイン (s.inc.php) は本体標準添付プラグインではありません。 このURLカスタマイズを利用したい場合に個別に導入してください。

カスタマイズ例:

カスタマイズ説明ページURL例アドレス欄表示備考
(1) 標準'?' の後にページ名https://pukiwiki.osdn.jp/_samples/1/?%E9%9A%8E%E5%B1%A41/%E5%90%8D%E5%89%8D/_samples/1/?階層1/名前
(2) 末尾 .html'?' の後にページ名。末尾が .htmlhttps://pukiwiki.osdn.jp/_samples/2/?%E9%9A%8E%E5%B1%A41/%E5%90%8D%E5%89%8D.html/_samples/2/?階層1/名前.html
(3) path風に変更'?' がなく、サーバー上のファイル名のような見た目https://pukiwiki.osdn.jp/_samples/3/%E9%9A%8E%E5%B1%A41/%E5%90%8D%E5%89%8D/_samples/3/階層1/名前
(6) 短縮URLベース長いURLのページを短縮URLプラグインによる短いURLで表現https://pukiwiki.osdn.jp/_samples/6/?&a66dc2fa8e/_samples/6/?&a66dc2fa8e
(7) 短縮URLリダイレクト短縮URLプラグインにより、短縮URL→実URLにリダイレクトhttps://pukiwiki.osdn.jp/_samples/7/?%E9%9A%8E%E5%B1%A41/%E5%90%8D%E5%89%8D
(リダイレクト前 短縮URL) https://pukiwiki.osdn.jp/_samples/7/?&a66dc2fa8e
/_samples/7/?階層1/名前
(8) 短縮URL優先短縮URLプラグインにより、ページ名URL→短縮URLにリダイレクトhttps://pukiwiki.osdn.jp/_samples/8/?&a66dc2fa8e
(リダイレクト前 通常URL) https://pukiwiki.osdn.jp/_samples/8/?%E9%9A%8E%E5%B1%A41/%E5%90%8D%E5%89%8D
/_samples/8/?&a66dc2fa8e
(9) 短縮URLベース2長いURLのページを短縮URLプラグインによる短いURLで表現
(「英数小文字10文字」はすべて短縮URLとみなす)
https://pukiwiki.osdn.jp/_samples/9/?a66dc2fa8e/_samples/9/?a66dc2fa8e

実動作サンプル

(1) 通常

(2) 末尾 (ページ名).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 に見せる

ページ名の前に '?' がつかず、ページがそのままサーバー上のファイルのように見えるURL

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 = new VirtualPathPageURIHandler();

.htaccess

このカスタマイズはPHPだけでは実現できず、Webサーバー側でパスをクエリ文字列に変換する必要がある。 Apacheでの指定は以下のようになる。

RewriteEngine On
RewriteCond %{REQUEST_URI} !(^/_samples/3/$)
RewriteCond %{REQUEST_URI} !(^/_samples/3/image/)
RewriteCond %{REQUEST_URI} !(^/_samples/3/skin/)
RewriteCond %{REQUEST_FILENAME} !(\.php$)
RewriteRule ^(.+)$ /_samples/3/?$1 [L]

意味: path が /, /image/..., /skin/... 以外の場合は /?{path} というリクエストに変換する。

この設定の場合、"image/" と "skin/" で始まるページ名、末尾が ".php" となるページ名は作成できない。

/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>
<script type="text/javascript" src="/_samples/3/skin/search2.js" defer></script>
 <a href="<?php echo $link['top'] ?>"><img id="logo" src="/_samples/3/<?php echo IMAGE_DIR . $image['logo'] ?>" width="80" height="80" alt="[PukiWiki]" title="[PukiWiki]" /></a>
        echo '<a href="' . $link[$key] . '">' .
               '<img src="/_samples/3/' . IMAGE_DIR . $image[$key] . '" width="' . $x . '" height="' . $y . '" ' .
                       'alt="' . $lang[$key] . '" title="' . $lang[$key] . '" />' .
               '</a>';

/pukiwiki.ini.php:

Base URLを固定で指定する。

$script = 'https://pukiwiki.osdn.jp/_sample/3/'

(6) 短縮URLプラグイン (s.inc.php) による常時短縮URLのカスタマイズ

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 = new ShortUrlPageURIHandler();

注意: ページURLを取得するのにファイル生成またはファイル存在チェックを伴うため、ページ数が数万となるような大規模サイトでは一覧などでパフォーマンスの低下が発生します。

(7) 短縮URLプラグイン (s.inc.php) によるリダイレクトのカスタマイズ

主に通常ページ名URLを使い、短縮URLでのリンクも可能にする設定。 (短縮URLプラグインの元々の動作)

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 = new ShortUrlRedirectPageURIHandler();

タイトル下に以下のコードを挿入する。 (official:Plugins/s.inc.php より)

<?php if ($is_page) { ?>
 <span class="small">
 <?php exist_plugin('s'); echo plugin_s_convert_get_short_link(); ?>
 </span>
<?php } ?>

(8) 短縮URLプラグイン (s.inc.php) 短縮URL優先利用カスタマイズ

pukiwiki.ini.php:

// Page-URI mapping handler ( See https:// pukiwiki.osdn.jp/?PukiWiki/PageURI )
class ShortUrlPrimaryPageURIHandler 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;
		}
		$is_get = $_SERVER['REQUEST_METHOD'] === 'GET';
		if ($is_get) {
			if (strpos('&', $query_string) !== NULL) {
				$dec_page = urldecode($query_string);
				$page_id = plugin_s_get_page_id($dec_page);
				if ($page_id) {
					$short_url = get_page_uri($dec_page, PKWK_URI_ROOT);
					header("HTTP/1.1 302 Found");
					header("Location: $short_url");
					exit;
				}
			}
		}
		return parent::get_page_from_query_string($query_string);
	}
}
$page_uri_handler = new ShortUrlPrimaryPageURIHandler();

(9) 短縮URLプラグイン (s.inc.php) による常時短縮URL パターン2

"?" の後に "&" 等の記号なしに短縮URL用の page_id を続ける形。 URLはシンプルになるが、指定されているのがページ名なのか短縮URLのpage_idなのかを機械的に判定できない。

例: "/?aaaaaaaaaa" というURLの場合に「"aaaaaaaa"というページ名」なのか「"aaaaaaaaaa"という短縮URLのpage_id」なのかわからない。どちらの可能性もある。

このカスタマイズ例では、英数小文字が10文字続いた場合には常に短縮URLのpage_idとして扱う。

「英数小文字10文字」はすべて短縮URLとみなし、この形の名前のページの作成は不可とする。

pukiwiki.ini.php:

class ShortUrl2PageURIHandler 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-z]{10})$#', $query_string, $m)) {
			$page = plugin_s_get_page_from_page_id($m[1]);
			if ($page) {
				return $page;
			} else {
				// Not found
				http_response_code(404);
				die_message('Not found');
				exit;
			}
		}
		return parent::get_page_from_query_string($query_string);
	}
}
$page_uri_handler = new ShortUrl2PageURIHandler();

URLカスタマイズの2パターン

表示に関わる

参照

対象

設計

クラス 
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;
}

対応していないプラグインへの対応

各ページへのリンクURL取得手段として PukiWiki 1.5.2 から導入された get_page_uri($page) を利用していないプラグインはカスタムURL対応になりません。

ページURLに get_page_uri($page) を利用するよう書き換えてください。

カスタマイズ内容

(URL生成) 各ページのURL は get_base_uri() + 「ページを表すURL片」で表現される。 (例: "?FrontPage", "?BugTrack/2525") ページ名を引数にしてこの「ページを表すURL片」の生成する関数を登録できるようにする。

(ページの表示) 「ページを表すURL片」を受け取って、表示(または別のプラグインアクション)を行う関数を登録できるようにする。

既存ロジック不明なところ

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 しようとするとエラーになる。どういう条件でここに入るのか不明




トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2022-04-23 (土) 16:32:43
Site admin: PukiWiki Development Team

PukiWiki 1.5.4+ © 2001-2022 PukiWiki Development Team. Powered by PHP 8.2.12. HTML convert time: 0.329 sec.

SourceForge