2007/05/10

[雑記]   だまされたのか?

at 18:52JST
…。

なかなか雨が降りそうになかったので手ぶらで喫茶店まで出てきたが。

夜になるにつれ降水確率が高くなる予報だったとは知らなかった。かさ…。

[雑記]   なんかたべてこよ

at 16:53JST
気分が重いけど、ちょっと作業したから、
自分にごほうびでケーキたべてこよ。

[技術系]   MTインポートによる移行向けに、旧URL→新ファイルパスのマップを作成するスクリプト

at 16:49JST
結論>MTにスクリプトから「出力ファイル名」指定でポストする方法 : ひろ式めもちょう
http://memo.hirosiki.jp/article/40820357.html

のつづき。

結局、
「他blog/他MTサイトからMTエクスポートログによって移行してくると、従来のURLを維持できない」
ので、エクスポート/インポート時に適当なスクリプトで
「旧URL→インポート後のファイルパス」
のマップを自動作成し、リダイレクトツールなどのためのデータにするのが好ましい。

ということで、そのためのツールを作った。自分用だけどメモしておかないとまたどこかに行っちゃうので公開。なお、スクリプトはなぜかWindows ActivePerlで動作させることを前提としている。

準備するもの:
a・旧サイトのMTエクスポートログ(mt.log)
b・旧サイトのスタティックHTMLファイル群(article/*.html)

まず、
a, bを展開したディレクトリ上で、static2mt.plを、
>static2mt.pl mt.log article/*.html > new_mt.log

のように動かす。すると、new_mt.logとして、

・各記事の属性部分に
 XORIGINALFILENAME: article/26381747.html
・各記事のBODYの先頭行の先頭に
 <!-- XORIGINALFILENAME: article/26381747.html -->

のように、マッチするスタティックHTMLファイルのファイルパスが挿入されたMTログファイルが新しくできる。

なお、マッチするファイルの認識には、スタティックHTMLファイル中に埋め込まれた
<rdf:RDF 
    :
<rdf:Description
    :
dc:date="2006-10-29T03:28:55+09:00"
/>
</rdf:RDF>
のようなRDF情報のdc:dateを使用している。RDFが埋め込まれていないHTMLファイルでは識別できない。

これでできあがったnew_mt.logを、移行先のMTにインポート。再構築してスタティックHTMLファイルを作成させる。

つまり、旧サイトのファイルパス情報がコメントタグ形式で埋め込まれたHTMLができる。

今度は、新しくできたスタティックHTMLファイル群に対して、mkurlmap.plを使って、
>mkurlmap.pl article/*/*.html > result.txt

などと操作する。

すると、result.txtには、
my %entriesMaps = ( 
'article/26573153.html' => 'article/200611/01-amazon_associates.html',
'article/26516570.html' => 'article/200610/31-seesaa_1.html',
'article/26610333.html' => 'article/200611/02-post_11.html',
        :

のようなハッシュテーブルが生成される。

あとはこれをCGIスクリプトに埋め込むなり、リダイレクトオンリーの静的HTMLファイル生成に使うなりすればいい。

なんつーことはないAd Hocなスクリプトなのだが、この手のツールが見あたらないのはなぜだらう。

[雑記]   出かけようと思ったら

at 15:26JST
東京の西のほうで大雨が降っているのをレーダーが感知した。

ちぇっ。

たまには傘差して出かけてみるかなあ。

[雑記]   ケータイにキズが!

at 11:49JST
がーん…。
表側の外装にスクラッチが入ってしまった。

考えてみると、このケータイ、もう半年も使ってるもんな。たぶん、ぼくの端末の中では10年前のノキア端末に次いで長い。

かといって、今回は「お持ち帰り0円」で買ったのであと2年月賦が残っているわけだが。

ソフトバンクモバイルになってからも外装交換サービスってやってるんだっけ?

シリコンカバー欲しいんだけど対応してないのよね。

[技術系]   MTでまっとうにエスケープしたエクスポート/インポートをできるようにするパッチ

at 10:58JST
MovableTypeエクスポートログ形式は腹を切って死ぬべきだ : ひろ式めもちょう
http://memo.hirosiki.jp/article/41332519.html

なんか一瞬「エクスポートのほうはめんどくさそうだ」と思ったけど、適当に処理してみる。こんな腐ったスクリプトを書けるのはひろ式先生だけ。あと、他人のこと偉そうに指摘するわりには、自分では
「エントリーのデータに\0が混じってるときちんと動作しないバグ」
を埋め込んでいるという話もある。

MTでハイフンをエスケープしたログをインポートするパッチ : ひろ式めもちょう
http://memo.hirosiki.jp/article/41336105.html

のパッチ取り込み済み。


*** lib/MT/ImportExport.pm.org	Thu May 10 09:37:57 2007 
--- lib/MT/ImportExport.pm Thu May 10 10:53:34 2007
***************
*** 297,302 ****
--- 297,303 ----
for my $piece (@pieces) {
$piece =~ s!^\s*!!;
$piece =~ s!\s*$!!;
+ $piece =~ s!^- !!mg;
if ($piece =~ s/^BODY:\r?\n//) {
$entry->text($piece);
}
***************
*** 526,532 ****
require MT::Template::Context;
my $tmpl = MT::Template->new;
$tmpl->name('Export Template');
! $tmpl->text(<<'TEXT');
AUTHOR: <$MTEntryAuthor strip_linefeeds="1"$>
TITLE: <$MTEntryTitle strip_linefeeds="1"$>
STATUS: <$MTEntryStatus strip_linefeeds="1"$>
--- 527,533 ----
require MT::Template::Context;
my $tmpl = MT::Template->new;
$tmpl->name('Export Template');
! my $tmplText = <<'TEXT';
AUTHOR: <$MTEntryAuthor strip_linefeeds="1"$>
TITLE: <$MTEntryTitle strip_linefeeds="1"$>
STATUS: <$MTEntryStatus strip_linefeeds="1"$>
***************
*** 538,556 ****
CATEGORY: <$MTCategoryLabel$>
</MTEntryCategories>
DATE: <$MTEntryDate format="%m/%d/%Y %I:%M:%S %p"$>
! -----
BODY:
<$MTEntryBody convert_breaks="0"$>
! -----
EXTENDED BODY:
<$MTEntryMore convert_breaks="0"$>
! -----
EXCERPT:
<$MTEntryExcerpt no_generate="1" convert_breaks="0"$>
! -----
KEYWORDS:
<$MTEntryKeywords$>
! -----
<MTComments>
COMMENT:
AUTHOR: <$MTCommentAuthor strip_linefeeds="1"$>
--- 539,557 ----
CATEGORY: <$MTCategoryLabel$>
</MTEntryCategories>
DATE: <$MTEntryDate format="%m/%d/%Y %I:%M:%S %p"$>
! __SEPARATOR__
BODY:
<$MTEntryBody convert_breaks="0"$>
! __SEPARATOR__
EXTENDED BODY:
<$MTEntryMore convert_breaks="0"$>
! __SEPARATOR__
EXCERPT:
<$MTEntryExcerpt no_generate="1" convert_breaks="0"$>
! __SEPARATOR__
KEYWORDS:
<$MTEntryKeywords$>
! __SEPARATOR__
<MTComments>
COMMENT:
AUTHOR: <$MTCommentAuthor strip_linefeeds="1"$>
***************
*** 559,565 ****
URL: <$MTCommentURL strip_linefeeds="1"$>
DATE: <$MTCommentDate format="%m/%d/%Y %I:%M:%S %p"$>
<$MTCommentBody convert_breaks="0"$>
! -----
</MTComments>
<MTPings>
PING:
--- 560,566 ----
URL: <$MTCommentURL strip_linefeeds="1"$>
DATE: <$MTCommentDate format="%m/%d/%Y %I:%M:%S %p"$>
<$MTCommentBody convert_breaks="0"$>
! __SEPARATOR__
</MTComments>
<MTPings>
PING:
***************
*** 569,578 ****
BLOG NAME: <$MTPingBlogName strip_linefeeds="1"$>
DATE: <$MTPingDate format="%m/%d/%Y %I:%M:%S %p"$>
<$MTPingExcerpt$>
! -----
</MTPings>
! --------
TEXT

my $iter = MT::Entry->load_iter({ blog_id => $blog->id },
{ 'sort' => 'created_on', direction => 'ascend' });
--- 570,584 ----
BLOG NAME: <$MTPingBlogName strip_linefeeds="1"$>
DATE: <$MTPingDate format="%m/%d/%Y %I:%M:%S %p"$>
<$MTPingExcerpt$>
! __SEPARATOR__
</MTPings>
! __ARTSEPARATOR__
TEXT
+ #-------- __ARTSEPARATOR__ \0\0
+ #----- __SEPARATOR__ \0
+ $tmplText =~ s/__ARTSEPARATOR__/\0\0/g;
+ $tmplText =~ s/__SEPARATOR__/\0/g;
+ $tmpl->text( $tmplText );

my $iter = MT::Entry->load_iter({ blog_id => $blog->id },
{ 'sort' => 'created_on', direction => 'ascend' });
***************
*** 588,593 ****
--- 594,602 ----
or return $class->error(MT->translate(
"Export failed on entry '[_1]': [_2]", $entry->title,
$tmpl->errstr));
+ $res =~ s/^-/- -/mg;
+ $res =~ s/\0\0/--------/g;
+ $res =~ s/\0/-----/g;
$cb->($res);
}
1;

[技術系]   MTでハイフンをエスケープしたログをインポートするパッチ

at 09:44JST
MovableTypeエクスポートログ形式は腹を切って死ぬべきだ : ひろ式めもちょう
http://memo.hirosiki.jp/article/41332519.html

V3.3。

diff -c lib/MT/ImportExport.pm.org lib/MT/ImportExport.pm 
*** lib/MT/ImportExport.pm.org Thu May 10 09:37:57 2007
--- lib/MT/ImportExport.pm Thu May 10 09:40:02 2007
***************
*** 297,302 ****
--- 297,303 ----
for my $piece (@pieces) {
$piece =~ s!^\s*!!;
$piece =~ s!\s*$!!;
+ $piece =~ s!^- !!mg;
if ($piece =~ s/^BODY:\r?\n//) {
$entry->text($piece);
}

[技術系]   MovableTypeエクスポートログ形式は腹を切って死ぬべきだ

at 08:31JST
MovableTypeエクスポートログ形式の問題点 : ひろ式めもちょう
http://memo.hirosiki.jp/article/41294601.html

のつづき。

MTのエクスポート結果って、
属性: 属性値
属性: 属性値
  :
BODY:
本文内容
----- ←項目区切り
ほかデータ列
  :
------- ←エントリ区切り

って感じで羅列になっているテキストファイルなわけだが。

ということは、これはどんな素人が見ても、
「本文中に ----- とか ------- とかが
 単独行で入ったらマズいな」
とわかる。通常、こういうものは何らかの方法でエスケープするものだ。

たとえば、いにしえのUNIX mbox形式では、メールメッセージの区切りが
From nantoka@nantoka

となっているわけだが、一般にメッセージ中行先頭の
From

は、
>From

でエスケープする慣習となっている。相互運用性にはやや混乱があるが、
http://man.qmail.jp/jman5/mbox.html
きわめてまっとうな方法で、これで20年は戦ってきた。

シェアの高いMTだし、当然このあたりは何か対応しているんだろうと思って確認してみると、

・エクスポートされるデータ
 →まったくエスケープされない

というのがわかった(V3.3)。

…正気か?

さらにさらに。

・エスケープされていないデータをインポートした場合
 →壊れたエントリが生成される

ということも確認できた。

…えー!?
マジですか…。

いくらMTのエクスポート画面で
「これは完璧なバックアップ手法じゃありません」
とうたってても、こりゃないだろ! というか、問題はバックアップではなく(バックアップならMySQLをダンプしておけばいい話)エクスポートが正常にできないということだ。相互運用性が確保されないという問題だ。

というか、大げさに言えばこれはセキュリティホールにも近い問題だ。なぜなら、上記のような形式で出力される中には「コメント」「トラックバック」のデータも含まれるから。
「お。気に入らないやつみっけー。
 こいつ、もうまともにエクスポートできないように、
 コメント欄に - を5つ書いといてやれ!」
と攻撃のネタにすることもできる。これだけで攻撃対象は自分のMTを簡易バックアップすることが不可能になるうえ、ほかのblogシステムへの移行もできなくなる。

ちなみに、いったんこの形式でエクスポートされたデータは機械的に問題点をチェックすることはできない。目視で修正するしかない!(検索すりゃ手間が多少省けるけど、コメントだけで1万件近いようなサイトを運営してる身には地獄だ)


そもそもMTがきちんとエスケープしないでエクスポートしている背景には、この機能がMTのテンプレート機能を転用して実装された簡易なものだということがあるようだ。

Movable Type Knowledge Base: Customized Exports
http://www.sixapart.com/movabletype/kb/imports/customized_expo.html

にはエクスポート形式の詳細のほか、いろいろなエクスポートの方法が書かれているが、あくまでMTのテンプレートを使った方法だけが紹介されている。まあ、言っちゃ悪いがテヌキだよね。


で、こんな簡単な問題はもちろんぼくじゃなくてもすぐわかるわけで、知ってる人はけっこういるみたいなんだけど、あんまり問題視されてないんだな…。おまけに、ご丁寧にほかのMT互換サービスも、このMTと同じ弱点をそのままマネしている。Seesaa BLOGもそう! -----のエスケープの必要を考えず、そのままエクスポートしている。おーい…。

唯一対応しているらしいのが

開発者ブログ MovableType形式と忍者形式のログエクスポートやログインポート
http://samurai.blog.shinobi.jp/Entry/111/

「忍者ブログ」だ。ここは
5つ以上の連続したハイフンと改行は5つの連続したハイフンと改行の間に半角スペースを入れます。

というAd Hocなやり方で対応している。忍者はいつもひと味違うサービスをやってるが、えらいな…。

忍者ブログは
「何らかの方法でエスケープしても、
 インポート側がアンエスケープできなければ意味がない」
という事情からこの方式を考え出したのだろう。行末に半角スペースが入っていても誰も気づかない。しかし、本来的には

エクスポート側
・行頭に-がある場合は「- 」を挿入する
インポート側
・行頭に「- 」がある場合はこれを削除する

という、より単純で明確な運用を普及させる必要があると思う。

とはいえ人に対応してもらうのを待っているわけにもいかないしな…。
いくつか方策を考えた。

・エクスポート側
 - MTでまっとうにエクスポートできるよう、プラグインを作る
  (とりあえず、ぼくは今「インポートする側」なので後回し)
 - XML-RPC APIを介して、MT互換blogから正常に“吸い出す”スクリプトを書く
  (…トラックバックとコメントって吸い出せたっけ?)
 - MT Perl API経由でバックエンドのDBからデータを吸い出すスクリプトを書く

・中間
 - MTエクスポートデータ中、怪しい「-----」を見つけて
  エスケープする支援スクリプトを書く

・インポート側(- エスケープ対応)
 - MTでまっとうにインポートできるようパッチを書く

※追記
エクスポート、インポートともにパッチを書いてみた↓

MTでまっとうにエスケープしたエクスポート/インポートをできるようにするパッチ : ひろ式めもちょう
http://memo.hirosiki.jp/article/41339889.html


めんどくさ…。

もうさー、とにかくこの
・まともにエスケープもしていない
・ファイル名(permlink URL)の保全もできない
MT形式を標準扱いするのはやめようよー。


追記:
…これ、コメント部分のインポート時パースにも問題ないか?
lib/mt/importexport.pm l.320から
my @lines = split /\r?\n/, $piece; 
my($i, $body_idx) = (0) x 2;
COMMENT:
for my $line (@lines) {
$line =~ s!^\s*!!;
my($key, $val) = split /\s*:\s*/, $line, 2;
if ($key eq 'AUTHOR') {
$comment->author($val);
} elsif ($key eq 'EMAIL') {
$comment->email($val);
} elsif ($key eq 'URL') {
$comment->url($val);
} elsif ($key eq 'IP') {
$comment->ip($val);
} elsif ($key eq 'DATE') {
my $date = $class->_convert_date($val) or next;
$comment->created_on($date);
} else {
## Now we have reached the body of the comment;
## everything from here until the end of the
## array is body.
$body_idx = $i;
last COMMENT;
}
$i++;
}
これだと、コメントの先頭に「(EMAIL|URL|IP|DATE):」な行があるとパースされてしまうよね。…URLのところがヘンにサニタイズをすり抜けたりしなきゃいいんだけど…。

別にケチつけたくて調べてるわけじゃないんだが、これならJUGEMかどっかみたいにXML形式でエクスポートしてくれたほうがいいなあ。もともとMTはXML関連モジュールを使用しているのだから、インポート/エクスポートに利用できないことないのに。

[雑記]   「コヨーテ」のゆみさんからメール

at 06:37JST
コヨーテのゆみです。
今日は、楽しかったです。ありがとうございました。
携帯番号080********です。電話くださいね!


…群馬の、うちと一文字違いドメインの建設会社のおじさんへ。
会社のメールアドレスの入った名刺をキャバクラで配るのはやめたほうがいいと思います。

というかやめてください。さとし社長。
じゃないと御社と中曽根弘文後援会との黒いつながりをバラす。

「優」で「さとし」と読むとははじめて知りました。
さらに過去の記事
2009/04 (1)   2008/12 (3)   2008/11 (9)   2008/10 (10)   2008/09 (20)   2008/08 (2)   2008/07 (23)   2008/06 (16)   2008/05 (22)   2008/04 (11)   2008/03 (21)   2008/02 (20)   2008/01 (21)   2007/12 (32)   2007/11 (37)   2007/10 (46)   2007/09 (63)   2007/08 (33)   2007/07 (41)   2007/06 (81)   2007/05 (173)   2007/04 (168)   2007/03 (113)   2007/02 (123)   2007/01 (92)   2006/12 (111)   2006/11 (185)   2006/10 (20)  

広告


この広告は60日以上更新がないブログに表示がされております。

以下のいずれかの方法で非表示にすることが可能です。

・記事の投稿、編集をおこなう
・マイブログの【設定】 > 【広告設定】 より、「60日間更新が無い場合」 の 「広告を表示しない」にチェックを入れて保存する。


×

この広告は1年以上新しい記事の投稿がないブログに表示されております。