[[../]] *任意のページごとの閲覧・編集制限 -- [[Ynak]] [#v9339fac] ※旧「BASIC認証で任意のページごとに閲覧制限や編集制限をかける方法~1.4対応版」。名前が長すぎたので修正しました。--[[Ynak]] #contents **やりたいこと [#n42484d9] 任意のページごとに閲覧制限や編集制限をかけたい。 具体的には +××ページは全員が閲覧できるが、内容を編集できるのは○○だけ。 +△△ページは□□だけが閲覧・編集できる。 +○△ページは○○と□□が閲覧できるが、編集は○○だけ。 というようなことをやりたい。 **現状 [#adb35022] -PukiWiki1.3.4では、[[../任意のページごとの閲覧・編集制限]]の改造により対応した。 -PukiWiki1.4rc2では、[[PukiWiki/1.4/BasicAuth]]で紹介された方法が実装されているが、最終目標には足りない。 **方針 [#q932cfc2] PukiWiki1.3.4と同様の方法で実装する。 **仕様 [#k68a7826] pukiwiki.ini.phpで |ユーザID|パスワード| |正規表現によるページ名のパターン|閲覧できるユーザID(カンマ区切り)| |正規表現によるページ名のパターン|編集できるユーザID(カンマ区切り)| を定義することで、ちょっとUNIXライクな読み書き権限の設定ができる。 更に、1.4対応版では以下に対応した。 -単語検索で、閲覧制限のかかったページ内容を検索対象にする・しないを選択できる。 --現在ログイン中のユーザに閲覧許可されたページの内容は検索対象となり、許可されないページの内容は無視される。 --ページ名は閲覧制限の対象外であるため、常に検索対象となる。 -includeプラグインで、閲覧制限のかかったページのincludeを行った場合は、現在ログイン中のユーザに閲覧許可されたページはincludeされ、許可されないページの内容はincludeされない。 -calendar_viewerプラグインで、(以下同文)。 **改造方法((diff形式じゃなくてすみません。)) [#z09a482c] PukiWiki1.4rc2をベースに改造する方法は以下の通り。 ***ja.lng [#zc8f5ab3] 以下を追加する。 $_msg_auth = 'PukiWikiAuth'; $_title_cannotread = '$1 は閲覧できません'; ***en.lng [#l587107a] 以下を追加する。 $_msg_auth = 'PukiWikiAuth'; $_title_cannotread = '$1 is not readable'; ***func.php [#s255aec7] 以下をコメントアウトする。 -111行付近 edit_auth //// 編集時の認証 ★まるごとコメントアウト //function edit_auth($page) //{ // global $edit_auth,$edit_auth_users,$_msg_auth,$_title_cannotedit; // // if ($edit_auth and // (!isset($_SERVER['PHP_AUTH_USER']) or // !array_key_exists($_SERVER['PHP_AUTH_USER'],$edit_auth_users) or // $edit_auth_users[$_SERVER['PHP_AUTH_USER']] != $_SERVER['PHP_AUTH_PW'])) // { // header('WWW-Authenticate: Basic realm="'.$_msg_auth.'"'); // header('HTTP/1.0 401 Unauthorized'); // // press cancel. // $body = $title = str_replace('$1',htmlspecialchars(strip_bracket($page)),$_title_cannotedit); // $page = str_replace('$1',make_search($page),$_title_cannotedit); // // catbody($title,$page,$body); // exit; // } //} 以下のように修正する。 -86行付近 check_editable // ★まんべんなく変更してるのでまるごと置換した方がよいかも。 // 編集不可能なページを編集しようとしたとき function check_editable($page, $auth_flag, $exit_flag) { global $script,$_title_cannotedit,$_msg_unfreeze; if (edit_auth($page, $auth_flag) and is_editable($page)) { return true; } if ($exit_flag) { $body = $title = str_replace('$1',htmlspecialchars(strip_bracket($page)),$_title_cannotedit); if(is_freeze($page)) { $body .= "(<a href=\"$script?cmd=unfreeze&page=". rawurlencode($page)."\">$_msg_unfreeze</a>)"; } // Modified by Ynak -- fix bugs $page = str_replace('$1',make_search($page),$_title_cannotedit); catbody($title,$page,$body); exit; } return false; } -167行付近 // 検索 function do_search($word,$type='AND',$non_format=FALSE) { global $script,$vars,$whatsnew,$non_list,$search_non_list; global $_msg_andresult,$_msg_orresult,$_msg_notfoundresult; global $search_auth; // ★これを追加 $database = array(); $retval = array(); $b_type = ($type == 'AND'); // AND:TRUE OR:FALSE $keys = preg_split('/\s+/',preg_quote($word,'/'),-1,PREG_SPLIT_NO_EMPTY); $_pages = get_existpages(); $pages = array(); foreach ($_pages as $page) { if ($page == $whatsnew or (!$search_non_list and preg_match("/$non_list/",$page))) { continue; } // ★このif~else文を追加 // 検索対象ページの制限をかけるかどうか (ページ名は制限外) if ($search_auth and !check_readable($page,false,false)) { $source = get_source(); // 検索対象ページ内容を空に。 } else { $source = get_source($page); } if (!$non_format) { array_unshift($source,$page); // ページ名も検索対象に } 以下をまるごと追加する。 -一番最後とか // 編集認証 // 第2,第3引数を変更する用途は今のところないが、閲覧との対象性を持たせた。 function edit_auth($page, $auth_flag) { global $_title_cannotedit,$edit_auth,$auth_users,$_msg_auth,$edit_auth_pages; // 編集認証フラグをチェック (システム全体として編集認証するかどうか) if (!$edit_auth) { return true; } // 認証が必要なページかどうかをチェック $edit_auth_users = ""; reset($edit_auth_pages); while (list($key, $val) = each($edit_auth_pages)) { if (preg_match($key, $page)) { $edit_auth_users = $val; break; } } if ($edit_auth_users == "") { return true; } // 認証を行う if ((!isset($_SERVER['PHP_AUTH_USER']) or !preg_match("/".$_SERVER['PHP_AUTH_USER']."/", $edit_auth_users) or !array_key_exists($_SERVER['PHP_AUTH_USER'], $auth_users) or $auth_users[$_SERVER['PHP_AUTH_USER']] != $_SERVER['PHP_AUTH_PW'])) { if ($auth_flag) { header('WWW-Authenticate: Basic realm="'.$_msg_auth.'"'); header('HTTP/1.0 401 Unauthorized'); } return false; } return true; } // 閲覧不可能なページを閲覧しようとしたとき (?) // ※あまり必要性を感じないが、editの場合と対称性を持たせるために導入。 function check_readable($page, $auth_flag, $exit_flag) { global $_title_cannotread; if (read_auth($page, $auth_flag)) { return true; } if ($exit_flag) { $body = $title = str_replace('$1',htmlspecialchars(strip_bracket($page)), $_title_cannotread); $page = str_replace('$1',make_search($page),$_title_cannotread); catbody($title, $page, $body); exit; } return false; } // 閲覧認証 function read_auth($page, $auth_flag) { global $read_auth,$auth_users,$_msg_auth,$read_auth_pages; // 閲覧認証フラグをチェック if (!$read_auth) { return true; } // 認証が必要なページかどうかをチェック $read_auth_users = ""; reset($read_auth_pages); while (list($key, $val) = each($read_auth_pages)) { if (preg_match($key, $page)) { $read_auth_users = $val; break; } } if ($read_auth_users == "") { return true; } // 現在のログイン状態で認証チェック if ((!isset($_SERVER['PHP_AUTH_USER']) or !preg_match("/".$_SERVER['PHP_AUTH_USER']."/", $read_auth_users) or !array_key_exists($_SERVER['PHP_AUTH_USER'], $auth_users) or $auth_users[$_SERVER['PHP_AUTH_USER']] != $_SERVER['PHP_AUTH_PW'])) { if ($auth_flag) { header('WWW-Authenticate: Basic realm="'.$_msg_auth.'"'); header('HTTP/1.0 401 Unauthorized'); } return false; } return true; } ***plugin/read.ini.php [#j9ecdfd0] 以下のように修正する。 -13行付近 // WikiName、BracketNameが示すページを表示 if (is_page($get['page'])) { check_readable($get['page'],true,true); // ★これを追加 ***plugin/edit.ini.php [#p47b1f5d] 以下のように修正する。 -13行付近 // check_editable($vars['page']); // ★コメントアウト check_editable($vars['page'], true, true); // ★追加 ***plugin/diff.ini.php [#x32cfbaa] 以下のように修正する。 -11行付近 global $_msg_notfound,$_msg_goto,$_msg_addline,$_msg_delline,$_title_diff; check_readable($get['page'],true,true); // ★追加 ***plugin/backup.ini.php [#lf545e64] 以下のように修正する。 -16行付近 if (!$do_backup) { return; } check_readable($get['page'], true, true); // ★追加 ***plugin/calendar_viewer.ini.php [#bf9dc5ab] 以下のように修正する。 -180行付近 $vars["page"] = $page; // ★このif~else文を追加 // 現状で閲覧許可がある場合だけ表示する if (check_readable($page,false,false)) { $body = convert_html(get_source($page)); } else { $body = $page." は閲覧制限がかかっているためcalendar_viewerによる参照はできません"; } $r_page = rawurlencode($page); ***plugin/include.ini.php [#f2431a83] 以下のように修正する。 -37行付近 $_page = $vars['page']; $get['page'] = $post['page'] = $vars['page'] = $page; // $body = convert_html(get_source($page)); // ★これをコメントアウトして // ★この下のif~elseを追加する // includeのときは、認証画面をいちいち出さず、後始末もこちらでつける if (check_readable($page, false, false)) { $body = convert_html(get_source($page)); } else { $body = $page." は閲覧制限がかかっているためincludeできません"; } ***plugin/そのほか [#n2b34772] -calendar_edit.ini.php -calendar_read.ini.php 無効化するのが望ましい?((よくわからなかったので自信なし。)) ***pukiwiki.ini.php [#ta903a47] 以下のように設定を追加する。 下記は設定例のため、設定内容は適切に変更すること。 ////////////////////////////////////////////////// // 閲覧・編集制限の設定 // 認証のアカウント // ユーザ名とパスワードを記入。 $auth_users = array( 'foo' => 'foo_passwd', 'bar' => 'bar_passwd', 'hoge' => 'hoge_passwd', ); // 編集時に認証が必要か $edit_auth = 1; // 編集認証をかけるページ名のパターンを正規表現で設定する。 // マッチしたページに編集認証をかける。 // カンマ区切りで複数ユーザを書いても良い。 $edit_auth_pages = array( '/Barの公開日記/' => 'bar', '/ひきこもるほげ/' => 'hoge', '/(ネタバレ|ねたばれ)/' => 'foo', ); // 閲覧時に認証が必要か $read_auth = 1; // 閲覧認証をかけるページ名のパターンを正規表現で設定する。 // マッチしたページに編集認証をかける。 // カンマ区切りで複数ユーザを書いても良い。 $read_auth_pages = array( '/ひきこもるほげ/' => 'hoge', '/(ネタバレ|ねたばれ)/' => 'foo,bar,hoge', ); // 検索時に認証が必要か // 0: 閲覧が許可されていないページ内容も検索対象とする // 1: 検索時のログインユーザに許可されたページのみ検索対象とする // ※どちらの場合も、ページ名は公開情報なので検索対象となる。 $search_auth = 0; 上の例では -「Barの公開日記」は、誰でも閲覧できて、barだけが編集できる。 -「ひきこもるほげ」ページは、hogeだけが閲覧・編集できる。 -「映画紹介~ネタバレ注意」ページは、foo, bar, hogeの三人だけが閲覧できて、かつ、編集はfooだけが可能。 のような設定となる。 かなり強引にUNIXっぽく表現すると、こうなる。 アクセス権 ユーザID グループ ページ名 -rw----r-- bar なし Barの公開日記 -rw------- hoge なし HogeOnly -rw-r----- foo hoges 映画紹介~ネタバレ注意 ※グループhogesには、barとhogeが所属するとする。 **注意点 [#s0de784b] -PHPをさわったばかり人間が改造しているので、実装的に問題があるかも。 --添削希望。 -閲覧認証をかけたページは、編集認証も必須。 --でないと、「編集」リンクから内容が読めてしまったり、挙動が怪しくなったりする。((UNIXでも、rw-(閲覧認証&編集認証の同時設定)はOKだけど、 -w-(編集認証のみ)はいろいろと問題が発生するのと似てる。)) --編集可能ユーザは、閲覧可能ユーザのサブセットとなるように設定すること。 -edit_auth_pagesなどのvalue部分と、BASIC認証のユーザ名の比較をpreg_matchで行っているので、あるユーザIDのサブセットとなるようなユーザIDがあるとややこしくなる。 --例えば、'hogefoobar'というユーザIDがあって、このユーザだけが編集できるようなページを以下のように設定する状況を考える。 $edit_auth_pages = array( '/Secret/' => 'hogefoobar', ); --ここでもし、'hoge'、'foo'、'bar'というユーザIDが存在していれば、そのいずれかのユーザIDでBASIC認証を突破すれば、このSecretページにアクセスできてしまう。 --とりあえず、pukiwiki.ini.phpにユーザID設定をする人が気を付ければ良いので、気にしていませんが、良い回避法があれば修正してください。 *コメント [#r335f6c6] -できるだけ1.4の設計思想(?)を優先して、きれいにまとめてみたつもりです。 -- [[Ynak]] &new{2003-05-20 (火) 23:28:16}; #comment