0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Perl を使って YukiWiki のデータを JSON フォーマットでエクスポートする

Last updated at Posted at 2019-11-28

概要

  • YukiWiki の YukiWikiDB モジュールで保存しているデータを JSON フォーマットでエクスポートする
  • Perl のスクリプトでエクスポートする

YukiWiki

YukiWiki は Wiki エンジンのひとつ。
Perl で書かれていた。
現在は開発が終了している。

YukiWiki

YukiWiki (結城ウィキ)は参加者が自由にページを追加・削除・編集できる不思議なWebページ群です。

YukiWiki

2018-03-07: YukiWikiの運用ならびにスクリプトの公開を終了します。

最新版は2006年に公開されたもの。

YukiWiki

2006-07-07 YukiWiki 2.1.3 (ykwk213.zip) 最新版

最新バージョンにも脆弱性があり、対策方法としては「YukiWiki を使用しない」となっている。

JVN#36343375: YukiWiki における複数の脆弱性

対策方法
YukiWiki を使用しない
YukiWiki の開発は終了しています。YukiWiki の使用を停止してください。

YukiWikiDB モジュール

YukiWiki で使われているデータベースエンジンのひとつ。
Perl の tie 関数に対応している。

YukiWiki 2.0.5 (2002年8月22日公開版 ykwk205.zip) に同梱されている YukiWikiDB.pm ファイルの中身をここに載せておく。

最新版 YukiWiki 2.1.3 (2006年7月7日公開版) ではもう少し長いコードになっているが、この 2.0.5 (2002年8月22日公開版) では基本的な処理内容がほぼ同じでシンプルな実装になっていてわかりやすいためこちらを載せておく。

ライセンスは「Perlと同じ配布条件」とのこと。

package Yuki::YukiWikiDB;

my $debug = 1;

# Constructor
sub new {
    return shift->TIEHASH(@_);
}

# tying
sub TIEHASH {
    my ($class, $dbname) = @_;
    my $self = {
        dir => $dbname,
        keys => [],
    };
    if (not -d $self->{dir}) {
        if (!mkdir($self->{dir}, 0777)) {
            print "mkdir(" . $self->{dir} . ") fail\n" if ($debug);
            return undef;
        }
    }
    return bless($self, $class);
}

# Store
sub STORE {
    my ($self, $key, $val) = @_;
    my $file = &make_filename($self, $key);
    if (open(FILE,"> $file")) {
        binmode(FILE);
        print FILE $val;
        close(FILE);
        return $self->{$key} = $val;
    } else {
        print "$file create error.";
    }
}

# Fetch
sub FETCH {
    my ($self, $key) = @_;
    my $file = &make_filename($self, $key);
    if (open(FILE, $file)) {
        local $/;
        $self->{$key} = <FILE>;
        close(FILE);
    }
    return $self->{$key};
}

# Exists
sub EXISTS {
    my ($self, $key) = @_;
    my $file = &make_filename($self, $key);
    return -e($file);
}

# Delete
sub DELETE {
    my ($self, $key) = @_;
    my $file = &make_filename($self, $key);
    unlink $file;
    return delete $self->{$key};
}

sub FIRSTKEY {
    my ($self) = @_;
    opendir(DIR, $self->{dir}) or die $self->{dir};
    @{$self->{keys}} = grep /\.txt$/, readdir(DIR);
    foreach my $name (@{$self->{keys}}) {
        $name =~ s/\.txt$//;
        $name =~ s/[0-9A-F][0-9A-F]/pack("C", hex($&))/eg;
    }
    return shift @{$self->{keys}};
}

sub NEXTKEY {
    my ($self) = @_;
    return shift @{$self->{keys}};
}

sub make_filename {
    my ($self, $key) = @_;
    my $enkey = '';
    foreach my $ch (split(//, $key)) {
        $enkey .= sprintf("%02X", ord($ch));
    }
    return $self->{dir} . "/$enkey.txt";
}

1;

JSON モジュール

JSON データを解析・出力することができる Perl モジュール。
今回はこのモジュールを使用して JSON フォーマットでエクスポートする。

JSON - JSON (JavaScript Object Notation) encoder/decoder - metacpan.org

YukiWikiDB データを JSON フォーマットで出力する Perl スクリプト

動作確認環境

  • macOS Catalina
  • Perl 5.30.0
  • YukiWiki で設定している文字エンコーディング: EUC-JP
  • YukiWikiDB モジュール 2.0.5
  • JSON モジュール 4.02

ソースコード

use strict;
use lib './yukiwiki'; # Yuki/YukiWikiDB.pm のあるディレクトリ
use utf8;
use Encode;
use JSON; # cpan JSON コマンドで事前にインストールしておく
use Yuki::YukiWikiDB;

my $modifier_dir_data = './yukiwiki'; # YukiWiki 一式を設置したディレクトリ
my $dataname = "$modifier_dir_data/wiki"; # 本文データのディレクトリ
my $infoname = "$modifier_dir_data/info"; # メタデータのディレクトリ

my %database; # 本文データのデータベース
my %infobase; # メタデータのデータベース

# ここに出力するデータを詰めていく
my $data = {};

# データベースをオープン
tie(%database, 'Yuki::YukiWikiDB', $dataname);
tie(%infobase, 'Yuki::YukiWikiDB', $infoname);

# データベースをひととおりたどる
foreach my $page (keys %database) {

  # WikiName を取得
  my $name = $page;
  $name = Encode::decode('EUC-JP', $name);

  # タイトルを取得
  my $subject = $database{$page};
  $subject =~ s/\r?\n.*//s;
  $subject = Encode::decode('EUC-JP', $subject);

  # 本文を取得
  my $content = $database{$page};
  $content = Encode::decode('EUC-JP', $content);

  # 出力したいデータを詰めていく
  $data->{$name} ||= {};
  $data->{$name}{'Name'} = $name;
  $data->{$name}{'Subject'} = $subject;
  $data->{$name}{'Content'} = $content;

  # メタデータ (IsFrozen, LastModified など) を詰めていく
  my %info = map { split(/=/, $_, 2) } split(/\n/, $infobase{$page});
  foreach my $infokey (keys %info) {
    $data->{$name}{$infokey} = Encode::decode('EUC-JP', $info{$infokey});
  }
}

# データベースをクローズ
untie(%database);
untie(%infobase);

# JSON フォーマットで出力する
# canonical: キー順でソート
# pretty: 人が読みやすい形式に
# utf8: UTF-8 で文字エンコーディング
my $json = JSON->new->canonical->pretty->utf8->encode($data);
print $json;

JSON 出力例

改行はCR+LF (環境によって異なるかもしれない)。
ページを凍結している場合は IsFrozen に 1 がセットされる。
LastModified はローカルタイムの日時。

{
   "100" : {
      "Content" : "100とは\r\n10の10倍です。\r\n",
      "IsFrozen" : "1",
      "LastModified" : "Mon Sep 18 16:22:09 2006",
      "Name" : "100",
      "Subject" : "100とは"
   },
   "HogePage" : {
      "Content" : "サンプルページ\r\n\r\nHello, world.\r\n<>&\"'\r\nああああ。\r\n",
      "IsFrozen" : "0",
      "LastModified" : "Wed Nov 27 23:44:55 2019",
      "Name" : "HogePage",
      "Subject" : "サンプルページ"
   },
(以下略)

Name の項目は日本語でも問題なく出力できている。

   "あいうえお" : {
      "Content" : "日本語名ページテスト\r\nほげほげ\r\n[[SamplePage]]\r\n",
      "IsFrozen" : "1",
      "LastModified" : "Mon Jul 17 09:12:34 2006",
      "Name" : "あいうえお",
      "Subject" : "日本語名ページテスト"
   },

参考資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?