ls2 プラグインで、常にget_source() を呼んでいる / include処理の改善

  • ページ: BugTrack
  • 投稿者: 名無しさん
  • 優先順位: 普通
  • 状態: 完了
  • カテゴリー: プラグイン
  • 投稿日: 2007-10-24 (水) 00:53:20
  • バージョン: 1.4.7
  • リリース予定バージョン: 1.5.2

修正

  • cvs:lib/file.php (1.90-1.92) -- file_head() のデフォルトを行数無制限に
  • cvs:plugin/ls.inc.php (1.10-1.11) -- まとめ直し。従来は空のファイルを読んだときにNoticeを出すことがあったが、もう起きない。
    list($comment) = get_source($page); // list() に空の array() が渡るとNotice
  • cvs:plugin/ls2.inc.php (1.26-1.29) -- まだこれから

PukiWiki 1.5.0 のタイミングで、以上の修正を含まないソースコードにロールバックしています。 1.5.1 にも入っていなかったので改めて修正を行いました。

メッセージ

ls2 プラグインには、ページの内容をスキャンする必要のある、title とinclude のオプションがあります。

しかし、これらのオプションを使わない時にもget_source() を呼んでいるため、無駄が多くなっています。
この無駄を省くことで、上のオプションを使わない時の速度をls プラグインと同等に なるようにしましょう。

cvs:plugin/ls2.inc.php (1.25) をベースに

 function plugin_ls2_get_headings($page, & $params, $level, $include = FALSE)
 {
 (中略)  
 	$ret .= '<a id="list_' . $params["page_$page"] . '" href="' . $href .
 		'" title="' . $title . '">' . $s_page . '</a>';
 	array_push($params['result'], $ret);
 
-	$anchor = PLUGIN_LS2_ANCHOR_ORIGIN;
-	$matches = array();
-	foreach (get_source($page) as $line) {
-		if ($params['title'] && preg_match('/^(\*{1,3})/', $line, $matches)) {
-			$id    = make_heading($line);
-			$level = strlen($matches[1]);
-			$id    = PLUGIN_LS2_ANCHOR_PREFIX . $anchor++;
-			plugin_ls2_list_push($params, $level + strlen($level));
-			array_push($params['result'],
-				'<li><a href="' . $href . $id . '">' . $line . '</a>');
-		} else if ($params['include'] &&
-			preg_match('/^#include\((.+)\)/', $line, $matches) &&
-			is_page($matches[1]))
-		{
-			plugin_ls2_get_headings($matches[1], $params, $level + 1, TRUE);
-		}
-	}
+	if ($params['title'] || $params['include']) {
+		$anchor = PLUGIN_LS2_ANCHOR_ORIGIN;
+		$matches = array();
+		foreach (get_source($page) as $line) {
+			if ($params['title'] && preg_match('/^(\*{1,3})/', $line, $matches)) {
+				make_heading($line);
+				$level = strlen($matches[1]);
+				$id    = PLUGIN_LS2_ANCHOR_PREFIX . $anchor++;
+				plugin_ls2_list_push($params, $level + 1);
+				array_push($params['result'],
+					'<li><a href="' . $href . $id . '">' . $line . '</a>');
+			} else if ($params['include'] &&
+				preg_match('/^#include\((.+)\)/', $line, $matches) &&
+				is_page($matches[1]))
+			{
+				plugin_ls2_get_headings($matches[1], $params, $level + 1, TRUE);
+			}
+		}
+	}
 }

  • パッチをありがとうございます。そのままイケルと思ったものの、patchコマンドに怒られたのは秘密です。titleとincludeを同時に指定した時の挙動が無くなってしまうように見えますので、勘違いでなければご一考を :) -- henoheno 2007-10-25 (木) 23:37:23
    • 勘違いじゃないです、おもいっきり考慮から抜けてました。
      メッセージの案を、素直にif で括るだけ、に変えました。 -- 2007-10-26 (金) 00:09:31
  • 修正案を少しいじる。 -- 2007-10-26 (金) 02:14:29
    • 同時指定の時のことが抜け落ちていた件 -- 2007-10-26 (金) 00:09:31
    • $level + strlen($level) の部分、$level には1~3 が入っているので、ここの結果は2~4 になるはず、なので微修正。include したページがinclude していた場合の動作も変わらないはず(今の動作テスト)。 -- 2007-10-26 (金) 02:14:29
    • make_heading($line) を呼び出すだけで、$line に修正がかかる*1 & $id には固定anchor がなくてもいいような処理をすぐ後でしている、ので微修正*2。 -- 2007-10-26 (金) 02:14:29
  • 「ls2 プラグインで、常にget_source() を呼んでいる」の修正を行いました ( commit:9efb23d18b ) -- umorigu 2017-10-28 (土) 01:08:47
  • titleやincludeが指定されたときの、リストのインデントレベルの修正を行いました ( commit:68928cfb62 ) -- umorigu 2017-10-28 (土) 01:09:02


特定の条件で無限ループする

同じページを複数回参照したときに抜け出す条件が、if ($params['title'] && $is_done) となっていて、titleを指定せずにincludeを指定した場合に、ソースを読みに行って無限ループする可能性があります。

そこで、すでにページを読み取ったかだけで判定するようにしてみました。あと、あらかじめ$params["page_$page"] を初期化しないようにして、isset だけで表示したかどうかを判定できるように手順を変えてみました。

  • cvs:plugin/ls2.inc.php (1.29)
     	if ($params['reverse']) $pages = array_reverse($pages);
     
    -	foreach ($pages as $page) {
    -		$params['page_ ' . $page] = 0;
    -	}
    -
     	$params['result'] = $params['saved'] = array();
     	foreach ($pages as $page) {
     		plugin_ls2_get_headings($page, $params, 1);
     	}
     
     	return join("\n", $params['result']) . join("\n", $params['saved']);
     }
     
     function plugin_ls2_get_headings($page, & $params, $level, $include = FALSE)
     {
     	static $_ls2_anchor = 0;
     
    -	// ページが未表示のとき
    -	$is_done = (isset($params["page_$page"]) && $params["page_$page"] > 0);
    -	if (! $is_done) $params["page_$page"] = ++$_ls2_anchor;
    
     	$r_page = rawurlencode($page);
     	$s_page = htmlspecialchars($page);
     	$title  = $s_page . ' ' . get_pg_passage($page, FALSE);
     	$href   = get_script_uri() . '?cmd=read&amp;page=' . $r_page;
    
     	plugin_ls2_list_push($params, $level);
     	$ret = $include ? '<li>include ' : '<li>';
     
    -	if ($params['title'] && $is_done) {
    +	if ($isset($params["page_$page"]) {
    		$ret .= '<a href="' . $href . '" title="' . $title . '">' . $s_page . '</a> ';
    		$ret .= '<a href="#list_' . $params["page_$page"] . '"><sup>&uarr;</sup></a>';
    		array_push($params['result'], $ret);
    		return;
    	}
     
    +	// ページが未表示のとき
    +	$params["page_$page"] = ++$_ls2_anchor;
     	$ret .= '<a id="list_' . $params["page_$page"] . '" href="' . $href .
     		'" title="' . $title . '">' . $s_page . '</a>';
  • plugin_ls2_show_lists() で、条件を基に検索した結果に重複がないのなら、include を指定するとき以外は、$params["page_$page"] やid 無しでもいいかもしれませんが・・・*3 -- 2008-02-07 (木) 22:18:25
  • includeだけをしていた時の無限ループの解消と、ページ単位でincludeされているページは必ず1階層分を表示するようにしました ( commit:f17bc09a81 ) -- umorigu 2017-10-28 (土) 01:05:45


get_source() がFALSE を返してきた時の対策

BugTrack/2449 に移動しました


ソース読み取り時のマルチライン対応(仮)

BugTrack/2450 に移動しました

include の相対パスページ指定及びオプション指定への対応

... また、include を見つけた場合に、notitleなどのパラメータが含まれている場合や、相対パスを考慮していないので、存在しないページと判定されスキップされる場合があります。

  • include の判定の部分ですが、preg_match('/^#include\((.+)\)/', となっていて、確実に1文字以上あるはずなのでcsv_explode() を使って切り分けてます。 それと、マルチラインの終了チェック時以外は、処理速度向上のために各行で1文字目をチェックするようにしています。 -- 2008-02-07 (木) 22:18:25
  • #includeの相対パス名対応、"..." で囲まれた名前対応、notitle等のオプションへの対応、を行いました commit:a7bc497858 -- umorigu 2017-10-30 (月) 00:35:12


総合コメント

  • その他、ls2はデータ構造(気になるのは $params["page_$page"])を見直したり、全体の流れに沿って直す等、色々余地がありそうですね。 -- henoheno 2007-10-25 (木) 23:46:47
    • ls.inc.php とまとめて見直さないと片付かない気配。 -- henoheno 2007-10-27 (土) 19:24:01
    • cvs:lib/file.php (1.90-1.92) -- file_head()
    • cvs:plugin/ls.inc.php (1.10-1.11) -- 恐らくls2とコードをマージする位までやらないと、終わったとは言えない (今までの「コード発散スタイル」への反省にならない)
    • cvs:plugin/ls2.inc.php (1.26-1.29) -- まだこれから
    • その他、同様の性質の物として、list/filelistも視野に入れないといけなそうですね。 -- henoheno 2007-10-29 (月) 22:56:59
  • 「ls2 プラグインで、常にget_source() を呼んでいる」について、対応しました ( commit:9efb23d18b661 ) このBugTrackは他の修正も含んでいる?? -- umorigu 2017-10-27 (金) 07:07:17
  • タイトルを変更しました「ls2 プラグインで、常にget_source() を呼んでいる」→「ls2 プラグインで、常にget_source() を呼んでいる / include処理の改善」 -- umorigu 2017-10-28 (土) 01:03:51


作業中のバグなど

  • cvs:plugin/ls2.inc.php (1.28)
    • ls2 プラグインは、2005年には更新がなかったはずなんですが。見間違いかな?(BugTrack2/61 ネタ) -- 2007-10-28 (日) 00:17:21
    • 失敬! cvs:plugin/ls2.inc.php (1.29) -- henoheno 2007-10-28 (日) 01:17:39
  • cvs:lib/file.php (1.91) を入れるとページの更新ができなくなりました。 -- hirokasa 2007-10-28 (日) 13:39:25
    • 正確には、recent.dat の更新処理でこけているようです。(ページへの変更そのものは、きちんと保存されている)
      1.90 ではforeach(file_head($file, $maxshow + PKWK_MAXSHOW_ALLOWANCE, FALSE) as $line) と呼んでいた物が、1.91 では(file_head($file, $maxshow + PKWK_MAXSHOW_ALLOWANCE) as $line) となっていて、簡易ロックをするように変更している。
      このため、タイムスタンプを更新しようとするときに、ロックしようとして順番待ち→でも、今ロックしているのはfile_head() を呼び出した関数→永久に終わらない、となってしまっている気がします。
      lib/file.php (1.91) への修正案
      	// Open
      	pkwk_touch_file($file);
      	$fp = fopen($file, 'r+') or
      		die_message('Cannot open ' . 'CACHE_DIR/' . PKWK_MAXSHOW_CACHE);
      	set_file_buffer($fp, 0);
      	flock($fp, LOCK_EX);
      
      	// Read (keep the order of the lines)
      	$recent_pages = $matches = array();
      -	foreach(file_head($file, $maxshow + PKWK_MAXSHOW_ALLOWANCE) as $line) {
      +	foreach(file_head($file, $maxshow + PKWK_MAXSHOW_ALLOWANCE, FALSE) as $line) {
      		if (preg_match('/^([0-9]+)\t(.+)/', $line, $matches)) {
      AutoLink がON の時はput_lastmodified() へ逃げるので、このトラブルは発生しないでしょう。 -- 2007-10-28 (日) 17:16:04
    • コメントありがとうございます。これは r1.91 で、file_head() の第三引数と第四引数を取り間違えた上、不要だと勘違いして削ってしまったのが原因です。元に戻ったはずです。自分でも書き込みのときにApacheが固まるようになって、「何だかApacheの調子が悪いなぁ・・・」と思っていたところでした(ぇぇ自分が悪い) -- henoheno 2007-10-28 (日) 21:45:42
    • lib/file.php (1.92)への修正ありがとうございます。apacheの設定を見直す良い機会になりました。 -- hirokasa 2007-10-29 (月) 00:03:19

*1 参照渡ししているから
*2 make_heading() の返り値を$id に入れて無いだけですけど
*3 複数回ls2 が呼ばれてもid が重ならないように、static $_ls2_anchor = 0; は外せませんが

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2017-10-30 (月) 00:38:00
Site admin: PukiWiki Development Team

PukiWiki 1.5.2+ © 2001-2019 PukiWiki Development Team. Powered by PHP 5.6.40-0+deb8u7. HTML convert time: 0.266 sec.

OSDN