スパム対策として書込み時にID/PWを要求されますが、ローマ字で ほげ/ホゲ で書き込めるようになります。

VIMでPukiWikiの閲覧、編集を可能にする。

対象となるPukiWikiのバージョンは 1.4.x で euc-jp で運用している必要があります。

インストール方法

  1. vim.php を index.php と同じところに置く。
  2. vim.inc.php を plugin ディレクトリーへ置く。
  3. 以上! 後は、 vim.php の URL を vim から :e で開くだけです。
    Ex.
      :e http://vim.mydns.jp/vim.php

書き込む際にはKoRoNさんが作成されたvimスクリプトが必要。ダウンロードは こちら

KoRoNさんに感謝します。

2005/03/20
書き込み用スクリプト pukiwiki_edit.vim を 最新版の PHP スクリプトに合わせて改良してあります。 ソースコードはこのページの下に貼り付けてあります。

読み書きにはwgetが必須です。読込みにはVimのnetrw.vimプラグインが内部でwgetを利用しています。書込みにはwgetのPOST機能を使用していますので、wgetのバージョンは1.9.1以降である必要があります。参考情報

変更履歴

2005/03/20

  • 全部書き直し。
  • ファイル名の変更 dump4vim.inc.php -> vim.inc.php
  • 以前は 表示用ページ -> 編集用ページ となっていたのを表示したらそのまま編集できるように変更。
  • ページが凍結されていたり、毎回動的に表示するようなページの modeline には noma を付加する。
  • modeline に noma が有る時に :se ma して編集されても pukiwiki_edit.vim で modeline をみてエラーを吐くようにした。
  • 書込む時に pukiwiki_edit.vim で (yes/no) 確認するように変更。
  • 書き込んだ後はレスポンスで置き換えるように pukiwiki_edit.vim を変更。
  • PHPスクリプトで本文が何行目から始まるのかを1行目の1文字目(modeline の前)に吐き出すように変更。
  • 上記変更に伴い、pukiwiki_edit.vim で書き込む時に本文をエンコードする位置をmodelineの前から取得するように変更。
  • 当サイトに依存した部分(tipsやfaqのダンプ)を簡単に無効に出来るように変更。
  • 日本語のページの閲覧、編集が出来るように改造。
  • ページの検索機能を実装。
  • ページの新規作成機能を実装。
  • 最終更新日が確認できるページを実装。

これでとりあえず、何とか常用出来るレベルになったかなぁ…



2005/03/16

  • とりあえず、現状何とか動く物を公開。


ソースコード

pukiwiki_edit.vim

Last Change: 2005-03-20 19:00:40 (日)

" vim:set ts=8 sts=2 sw=2 tw=0 fdm=marker:
"
" pukiwiki_edit.vim - PukiWiki edit plugin.
"
" Last Change: 15-Mar-2005.
" Written By:  MURAOKA Taro <koron@tka.att.ne.jp>

if exists('plugin_pukiwiki_edit_disable')
  finish
endif

let g:pukiwiki_edit_encoding = "euc-jp"

augroup PukiwikiEdit
  autocmd!
  autocmd BufWriteCmd http://*/vim.php* call s:BufWriteCmd()
augroup END

function! s:BufWriteCmd()
  if &modified != 0
    let modeline = getline(1)
    if modeline =~ 'noma'
      echohl WarningMsg
      echo "PukiWiki: Cannot make changes, 'modifiable' is off"
      set nomodified
      return 0
    endif
    let last_confirm = input('really write it? (yes/no)')
    if last_confirm =~ '^\cy'
      call s:EncodePukiwiki()
      let tmp_body = tempname()
      silent! execute "%write! " . tmp_body
      let cmd = "wget -qO - --post-file=" . tmp_body . " " . expand('%')
      let result = system(cmd)
      let result = iconv(result, g:pukiwiki_edit_encoding, &encoding)
      execute "normal! ggdGi" . result
      call delete(tmp_body)
    endif
    set nomodified
  endif
endfunction

function! s:EncodePukiwiki()
  let body_pos = getline(1)[col(1)]
  execute "normal! " . body_pos . "G"
  silent! .,$s/[%&+]/\=s:EncodeChar(submatch(0))/g
endfunction

function! s:EncodeChar(ch)
  let n = char2nr(a:ch[0])
  let r = ""
  while 1
    let r = "0123456789ABCDEF"[n % 16] . r
    let n = n / 16
    if n == 0
      break
    endif
  endwhile
  return '%'.(strlen(r) < 2 ? '0' : '').r
endfunction

vim.php

Last Change: 2005-03-20 19:00:40 (日)

<?php
$_GET['cmd'] = $_POST['cmd'] = 'vim';
require_once('index.php');
?>

vim.inc.php

Last Change: 2005-03-20 19:00:40 (日)

<?php // vim: set ts=4 sw=4 sts=4 fdm=marker noet:
error_reporting(E_ALL);
// {{{1 plugin_vim_init() 設定

function plugin_vim_init()
{
	global $vim;

	$vim = array(
		// vim用の FrontPage を指定する、存在しない場合には
		// ブラウザ用の pukiwiki.ini.php の $defaultpage が表示される。
		'defaultpage' => 'FrontPage4Vim',

		// :syntax on の場合、サイトで扱っているテーマに合わせて変更する。
		// VimWikiの場合には扱っているテーマがVimに関することなのでhelpに
		// してあります。指定しないとft=phpになるので適当に調整してください。
		'filetype'    => 'help',

		// vimが文字コードの判定に失敗しないようにする為の物です。
		'encode_hint' => '燕の往来',

		// どこからが本文なのかを表す文字
		'boundary'    => '----------------------------------------------------------------------',

		// 書き込む際に boundary を除去するための正規表現
		'strip_boundary_regex' => '/^-+/',

		// 編集出来ないページに表示する文字
		'msg_not_editable' => '===== Not Editable =====',

		// http://vim.mydns.jp/ のサイト構成に依存した機能を使うか。
		// PukiWiki の Tracker プラグインを使ったページをダンプする機能
		// vim.php/cmd/dump/*
		// 1: 使う 0: 使わない
		'is_vimwiki'  => 1
	);
}

// {{{1 plugin_vim_action() メイン

function plugin_vim_action()
{
	global $defaultpage, $page_title, $script, $vars;
	global $vim;

	if( basename( $script ) != 'vim.php' )
	{
		return array(
			'msg' => 'vim.php からアクセスして下さい。',
			'body' => 'このプラグインは vim.php 専用です。<br />
				vim.php からアクセスして下さい。');
	}

	$path_info = '';
	if( ! empty( $_SERVER['PATH_INFO'] ) )
		$path_info = $_SERVER['PATH_INFO'];

	$path_info = substr( $path_info, 1);

	// 出力する物は全てこの $response に入れる。
	$response = array();

	// {{{2 POST
	if( $_SERVER['REQUEST_METHOD'] == 'POST' )
	{
		if( empty( $vars['exec'] ) )
		{
			$vars['exec'] = '';
		}
		switch( $vars['exec'] )
		{
			case 'write':
				$response = plugin_vim_exec_write( $response );
				break;
			case 'new':
				$response = plugin_vim_exec_new( $response );
				break;
			case 'search':
				$response = plugin_vim_exec_search( $response );
				break;
			default:
				$response['is_editable'] = false;
				$response['header'][] = "|{$page_title}| {$script}\n"; // トップページのURL
				$response['header'][] = "|{$path_info}| {$script}/{$path_info}\n"; // リロード用
				$response['body'] = "\n不正なコマンドを受取りました。\n\n{$script}";
				break;
		}

		plugin_vim_show_page( $response );
		exit;
	}

	// {{{2 GET
	// {{{3 cmd/hoge 用の処理
	if( preg_match('/^cmd\/.*$/', $path_info) )
	{
		$response['header'][] = "|{$page_title}| {$script}\n"; // トップページのURL
		$response['header'][] = "|{$path_info}| {$script}/{$path_info}\n"; // リロード用
		$cmd = split('/', $path_info);
		switch( $cmd[1] )
		{
			case 'cmdlist':
				$response = plugin_vim_cmd_cmdlist( $response );
				break;
			case 'pagelist':
				$response = plugin_vim_cmd_pagelist( $response );
				break;
			case 'resent':
				$response = plugin_vim_cmd_resent( $response );
				break;
			case 'new':
				$response = plugin_vim_cmd_new( $response );
				break;
			case 'search':
				$response = plugin_vim_cmd_search( $response );
				break;
			default:
				// XXX VimWikiのサイト構成に依存した機能 vim.php/cmd/dump/*
				if( $vim['is_vimwiki'] && $cmd[1] == 'dump'
					&& ! empty( $cmd[2] ) && ( $cmd[2] == 'tips' || $cmd[2] == 'faq'
						|| $cmd[2] == 'RegexQA' || $cmd[2] == 'scripts' ) )
				{
					$response = plugin_vim_cmd_dump( $response, $cmd[2] );
					break;
				}
				else
				{
					$response['is_editable'] = false;
					$response['body'] = "\n不正なコマンドを受取りました。\n\n{$script}";
					break;
				}
		}

		plugin_vim_show_page( $response );
		exit;

	}

	// {{{3 単一ページの表示
	// vim用defaultpageが無かったらPukiWikiブラウザ用のを表示
	if( empty( $path_info ) )
	{
		if( is_page( $vim['defaultpage'] ) )
		{
			$path_info = $vim['defaultpage'];
		}
		else
		{
			$path_info = $defaultpage;
		}
	}

	// 日本語対応 fixme もっと良い方法が有ったら教えて下さい。
	if( ! is_page( $path_info ) )
	{
		$dec_page = decode( $path_info );
		if( is_page( $dec_page ) )
		{
			$path_info = $dec_page;
		}
	}

	$source = join('', get_source( $path_info ) );

	$response['is_editable'] = false;
	$response['header'][] = "|{$page_title}| {$script}\n"; // トップページのURL
	$enc_page = plugin_vim_get_enc_page( $path_info );
	$response['header'][] = "|{$path_info}| {$script}/{$enc_page}\n"; // リロード用
	$response['header'][] = "|cmdlist| {$script}/cmd/cmdlist\n"; // コマンド一覧

	if( is_editable( $path_info ) )
	{
		$response['is_editable'] = true;
		$digest = md5( $source );
		$response['header'][] = "&encode_hint=ぷ&exec=write&page={$path_info}&digest={$digest}&msg=\n";
		$response['header'][] = "{$vim['boundary']}\n";
	}

	$response['body'] = trim( $source );

	plugin_vim_show_page( $response );
	exit;
}

// {{{1 plugin_vim_exec_write() 書込み
// この関数の元ネタは plugin/edit.inc.php#plugin_edit_write()
function plugin_vim_exec_write( $response )
{
	global $vars, $script, $page_title, $vim;

	$page = isset($vars['page']) ? $vars['page'] : '';

	$vars['msg'] = trim( $vars['msg'] );
	$vars['msg'] = preg_replace( $vim['strip_boundary_regex'], '', $vars['msg'] );
	// 手書きの#freezeを削除
	$vars['msg'] = preg_replace( '/^#freeze\s*$/im', '', $vars['msg'] );
	$postdata = $postdata_input = $vars['msg'];

	$oldpagesrc = join('', get_source($page));
	$oldpagemd5 = md5($oldpagesrc);

	if ( ! isset($vars['digest']) || $vars['digest'] != $oldpagemd5)
	{
		// 更新の衝突が発生。
		$response['body'] = "\n更新の衝突が発生しました。\n貴方が書き込んだ内容が失われました。";
	}
	else
	{
		// 書き込み
		if ($postdata)
		{
			if( ! is_editable( $page ) )
			{
				$response['body'] = "\nページ名 ''{$page}'' は書き込みできません。";
			}
			else
			{
				page_write($page, $postdata, false); // しばらくは常にage
				$response['body'] = "\n更新完了。";
			}
		}
		else
		{
			// ページの削除
			$response['body'] = "\nVIMからのページの削除は禁止にしています。";
		}
	}

	$enc_page = plugin_vim_get_enc_page( $page );
	$response['is_editable'] = false;
	$response['body'] .= "\n\n{$script}/{$enc_page}";
	$response['header'][] = "|{$page_title}| {$script}\n"; // トップページのURL
	$response['header'][] = "|{$page}| {$script}/{$enc_page}\n"; // リロード用

	return $response;
}

// {{{1 plugin_vim_exec_new() 新規作成用

function plugin_vim_exec_new( $response )
{
	global $vars, $script, $page_title, $vim;

	$vars['pagename'] = trim( $vars["\npagename"] );
	$response['is_editable'] = true;
	$response['header'][] = "|{$page_title}| {$script}\n"; // トップページのURL

	$source = join('', get_source( $vars['pagename'] ) );
	$enc_page = plugin_vim_get_enc_page( $vars['pagename'] );
	$response['header'][] = "|{$vars['pagename']}| {$script}/{$enc_page}\n"; // リロード用
	$response['header'][] = "|cmdlist| {$script}/cmd/cmdlist\n"; // コマンド一覧
	$digest = md5( $source );
	$response['header'][] = "&encode_hint=ぷ&exec=write&page={$vars['pagename']}&digest={$digest}&msg=\n";
	$response['header'][] = "{$vim['boundary']}\n";
	$response['body'] = "";

	return $response;
}

// {{{1 plugin_vim_exec_search() 検索結果を表示

function plugin_vim_exec_search( $response )
{
	global $vars, $script, $page_title;

	$vars['word'] = trim($vars["\nword"]);
	$response['is_editable'] = false;

	$response['header'][] = "|{$page_title}| {$script}\n"; // トップページのURL
	$response['header'][] = "|search| {$script}/cmd/search\n";

	$all_page_name = get_existpages();
	$total_page = count( $all_page_name );

	$result = do_search( $vars["word"], 'AND', true );
	sort( $result );
	$hit_count = count( $result );

	$response['body'] = "\nキーワード '{$vars['word']}' を含むページは\n";
	$response['body'] .= "{$total_page} ページ中 {$hit_count} ページ見つかりました。\n\n";

	foreach( $result as $page )
	{
		$enc_page = plugin_vim_get_enc_page( $page );
		$response['body'] .= "{$page}\n{$script}/{$enc_page}\n\n";
	}

	return $response;
}

// {{{1 plugin_vim_cmd_dump() VimWiki 用一覧表示 tips 一覧とか

function plugin_vim_cmd_dump( $response, $target )
{
	global $script, $page_title;

	$response['is_editable'] = false;

	$response['body'] = "";

	foreach( get_existpages() as $_page )
	{
		if( ! preg_match("/^{$target}\//", $_page ) )
			continue;

		$lines = get_source( $_page);

		$lines = array_slice( $lines, 2, -3 );

		$response['body'] .= "==============================================================================\n";
		$response['body'] .= "{"."{{1 *{$_page}";
		$lines[0] = "{$lines[0]}{$script}/{$_page}\n";

		foreach( $lines as $line )
		{
			if( preg_match('/^-ページ.*$/', $line ) )
				continue;

			if( preg_match('/^-バージョン.*$/', $line ) )
				continue;

			$line = preg_replace('/\[#[0-9a-z]{8}\]/', '', $line);

			$line = preg_replace('/ +$/', '', $line);

			$line = preg_replace('/\~$/', '', $line);

			$response['body'] .= $line;
		}
	}

	return $response;
}

// {{{1 plugin_vim_cmd_cmdlist() コマンドの一覧

function plugin_vim_cmd_cmdlist( $response )
{
	global $script;

	$response['is_editable'] = false;
	$response['body'] = "
ページ一覧
{$script}/cmd/pagelist

最新のXX件
{$script}/cmd/resent

検索
{$script}/cmd/search

新規作成
{$script}/cmd/new
";

	return $response;

}

// {{{1 plugin_vim_cmd_pagelist() ページの一覧

function plugin_vim_cmd_pagelist( $response )
{

	global $script;

	$response['is_editable'] = false;
	$response['body'] = "\n";
	$pages = get_existpages();
	sort( $pages );
	foreach( $pages as $page )
	{
		$enc_page = plugin_vim_get_enc_page( $page );
		$response['body'] .= "{$page}\n{$script}/{$enc_page}\n\n";
	}
	$response['body'] .= "\n";

	return $response;
}

// {{{1 plugin_vim_cmd_resent() 最終更新
// この関数の元ネタは plugin/recent.inc.php
function plugin_vim_cmd_resent( $response )
{
	global $script, $date_format;

	$f = CACHE_DIR . 'recent.dat';

	$response['is_editable'] = false;

	$lines = file( $f );

	$date = $response['body'] = '';
	foreach ($lines as $line) {
		list($time, $page) = explode("\t", rtrim($line));
		$_date = get_date($date_format, $time);
		if ($date != $_date) {
			$date = $_date;
			$response['body'] .= "===== $date =====\n";
		}
		$s_page = htmlspecialchars($page);
		$r_page = rawurlencode($page);
		$pg_passage = get_pg_passage($page, FALSE);
		$enc_page = plugin_vim_get_enc_page( $s_page );
		$response['body'] .= "{$s_page} {$pg_passage}\n{$script}/{$enc_page}\n\n";
	}

	return $response;
}

// {{{1 plugin_vim_cmd_new() 新規作成用

function plugin_vim_cmd_new( $response )
{
	$response['is_editable'] = true;

	$response['header'][] = "&exec=new&encode_hint=ぷ&\npagename=";
	$response['body'] = "";

	return $response;
}

// {{{1 plugin_vim_cmd_search() 検索用ページを表示する

function plugin_vim_cmd_search( $response )
{
	$response['is_editable'] = true;

	$response['header'][] = "&exec=search&encode_hint=ぷ&\nword=";
	$response['body'] = "";

	return $response;
}

// {{{1 plugin_vim_get_enc_page() 日本語ページ対策
// 非アスキー文字が含まれていたらエンコードして返す。
// 環境変数 PATH_INFO にマルチバイトが渡せない?から
// Windows の vim だと確実に化ける… orz
// vimは : を含むURLを開いてくれないからその場合もエンコードする
function plugin_vim_get_enc_page( $page )
{
	if( preg_match('/[^\t -~]|:/', $page) )
	{
		$page = encode( $page );
	}

	return $page;
}

// {{{1 plugin_vim_show_page() 表示 出力は全てここで行う。

function plugin_vim_show_page( $response )
{
	global $vim;

	// 書込み時にvimスクリプトが何処からエンコードすればよいのかを計算
	// pukiwiki_edit.vim は1行目の1文字目で判断するようにしてある。
	$body_pos = count( $response['header'] ) + 2;

	// vim 用 modeline を生成
	$modeline = "{$body_pos} vim: set ssl fdm=marker";
	$modeline .= " ft={$vim['filetype']}";

	if( ! $response['is_editable'] )
	{
		$modeline .= " noma ";
		$response['header'][] = "{$vim['msg_not_editable']}\n";
	}
	else
	{
		$modeline .= " ma ";
	}
	
	$modeline .= ": {$vim['encode_hint']}\n";

	// レスポンス書出し
	header("Content-type: text/plain");

	echo $modeline;

	foreach( $response['header'] as $header )
		echo $header;

	echo $response['body'];

	exit;
}

?>

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2014-10-14 (火) 01:13:17 (1320d)