2008年04月10日

CustomFields/XMLRPCServer.pm 不具合

検索してみても報告事例が見当たらないので、メモ。MT4.1の
addons/Commercial.pack/lib/CustomFields/XMLRPCServer.pm
の16行目、
my ($cb, $mt, $entry, $original) = @_;
が引数を取り違えてるみたいです。正しくは
my ($mt, $entry, $original) = @_;
じゃないかな。
XML-RPCインターフェイスで日付がずれるのは、たぶんこれが原因かと。
既存のエントリー編集の時も、追記の更新が反映されないとかおかしなことが起こってるはずです。
これじゃXML-RPC経由でCustomFieldsはまともに機能しないはずなんで、まだ誰もXML-RPCでCustomFieldsは使ってないってことなのかも。

2008年02月01日

MT4.1 CustomFields メモ

Movable Typeが4.1になって標準でCustomFieldsがサポートされるようになった。
めでたい。
このCustomFieldsのおかげでデータベース色の強い使い方をする場面がいっそう増えそうなんだけど、そうなるとイニシャルで多めのデータ入力を要求される場面も増えそうだ。しかしいかんせん4.1の動作がちょっと重い。20個くらいのエントリーを入れろと言われただけでも辛い。自動化して一気に片付けたい。
というわけで以下、Movable Type Perl APIでCustomFieldsを扱うメモ。
まだ正式なドキュメントを見つけていないので、ただしい使い方なのかは不明。勝手に試してみただけ。

addons/Commercial.pack/lib/CustomFields/XMLRPCServer.pm
がちょうどいいサンプルになっている。

例えば、
#!/usr/bin/perl
use strict;
use warnings;
use CGI;
use lib qw(lib extlib);
use Data::Dumper;
use MT::Entry;
my $q = new CGI;
my @keywords = $q->keywords;
my $id = shift @keywords;
my $entry = MT::Entry->load($id);
print $q->header(
-type => 'text/plain',
-charset => 'UTF-8',
);
print Dumper $entry;
てな感じでエントリーをdumpするだけのCGIで4.1のエントリーを読むと、CustomFieldsで付け足したデータはシリアライズされていてそのままは読めない。
いったんentryをロードしたあとにget_metaを呼ぶと、アンシリアライズされて読めるようになる。こんな感じ。
#!/usr/bin/perl
use strict;
use warnings;
use CGI;
use lib qw(lib extlib addons/Commercial.pack/lib);
use Data::Dumper;
use MT::Entry;
use CustomFields::Util qw( get_meta save_meta );
my $q = new CGI;
my @keywords = $q->keywords;
my $id = shift @keywords;
my $entry = MT::Entry->load($id);
my $meta = get_meta($entry);
print $q->header(
-type => 'text/plain',
-charset => 'UTF-8',
);
print Dumper $entry;

で、読むだけならべつにuse CustomFields::Utilしなくても
my $entry = MT::Entry->load($id);
my $meta = $entry->meta('customfields');
ってやるだけで読めるようになるみたいだ。

ふむふむ。

2005年07月19日

サーバ間のMTデータ移動

Movable Typeで、別サーバにデータを移したいことがある。
dbディレクトリにBarkleyDBでデータをためている場合、同系列のOSやCPUならそのままコピーすれば動くかもしれないが、OS XからLinuxとかLinuxからFreeBSDなんて場合はそうもいかない。
といって、データのExport機能で書き出すと、ImportするときにエントリIDがずれたりする(ことがある)。

そこで以下のような方法で移動してみた。

以下、もちろん無保証です。2.661でしか試してません。要Storable。

引越先サーバにMovable TypeのディレクトリをPUT。mt-load.cgiを実行。
引越元サーバでStorableでデータをファイルに吐き出すスクリプトをmt.cgiと同じディレクトリに置き、CGIとして実行。
storedというディレクトリが出来るので、中身ごとFTPでGETし、引越先にそのままPUT。
引越先サーバでStorableでデータを書き戻すスクリプトをCGIとして実行。
Movable Typeにログイン、パスなどを新環境に書き換え、保存、再構築。

吐き出し書き戻しするデータは、自分の環境で必要そうなものを適当に選んだだけなので、抜けがあるかもしれない。

2005年07月17日

moblog スクリプト更新

Movable Type用のperlによるmoblogスクリプト、post2blogを更新。
Download file

メタデータである位置情報をエントリー時に本文テキストに静的に埋め込んでしまうより、メタなまま保持させて必要なときにプラグインで加工処理する方が美しいということで、位置情報の取り出しは廃止した。

更新内容:
・位置情報取り出し機能の廃止
・カテゴリー設定機能の追加

2006-09-29 更新内容:
・ネストしたMIMEパートに対応
・MIMEパートの並び順通りに添付ファイルを本文に挿入

設定方法その他は基本的には旧版と大差ないが、位置情報取り出しの廃止に伴い、Image::Infoはpost2blog単体では不要になった。

2006-09-29 追記
入れ子になったMIMEでエラーが起きるのを修正するべくAppleのMail.app(添付をAppleDoubleで送るので入れ子になる)でテストを繰り返すうち、画像の直後に「↑これがその画像です」と書いたりして添付画像と本文の位置関係で情報を示すことがあるのに気づいたので、それまでの「まとめて添付ファイル+本文」からメール通りに並べるように変更。

設定部分:
my $MT_DIR = '/Library/WebServer/Documents/mt/';
Movable Typeをインストールしているディレクトリ。
my $url = 'http://www.your-site.com/movabletype/mt-xmlrpc.cgi'; # CGIPath + 'mt-xmlrpc.cgi'
mt-xmlrpc.cgiのURL
my $blog_id = 1;
ポスト先のblog ID
my $username = 'Melody';
my $password = 'Nelson';
ポストするユーザ名とパスワード
my $category_id = 1;
プライマリのカテゴリ。0ならカテゴリを設定しない。
my @categories = (2, 3, 4);
その他のカテゴリのリスト。プライマリのカテゴリが0ならこれも無視される。
my $parse_path = '/Users/Shared/post2blog';
メールをParseするときにファイルを展開するディレクトリ
my $ffmpeg = '/usr/local/bin/ffmpeg';
ffmpegをインストールしているなら、そのパス。''にするとamcや3gpのサムネールを生成しない。
my ($maxx, $maxy) = (320, 320);
添付写真の表示サイズ

位置情報を持つエントリーから地図サービスへリンクするなどの機能は、locations.plプラグインでどうぞ。

2005年07月14日

Movable Type用 位置プラグイン

Google Mapsが日本地図対応になった。しかも詳細。
いやー、すごいです。

というわけで、Google Maps APIなどの位置情報ツールとMovable Typeをつなぐプラグインを作成。エントリーに含まれる緯度経度を返します。
(2005-07-15 01:00 ちょっと変更)
locations.pl
(測地系変換にNowralさんのコードを使用させていただきました。ありがとうございます。)

インストール:
locations.plをpluginsディレクトリに置く
Image::Info
HTML::Parserに含まれるHTML::LinkExtor
が必要。HTML::Parserは多くのサーバに最初からインストールされているようだが、Image::Infoがない場合はここ参照

対応する位置情報:
・エントリー本文にimgタグとして記述され、同じサーバに置かれている画像のExif GPSタグ
・エントリー本文に含まれる地図サービスのURL ( walk.eznavi.jp / www.gpspowered.jp / mapfan.com / www.mapion.co.jp )

タグ記述例:

<MTEntries> <MTLocations> <$MTLocation coordinate="latitude" datum="1"$><br /> </MTLocations> </MTEntries>

パラメータ:

coordinate 緯度か経度かの指定。無指定の場合「緯度,経度」とカンマで区切って返す latitude 緯度 longitude 経度 datum 測地系。無指定の場合WGS84 0 WGS84 1 Tokyo97 format 緯度経度の表記方法。無指定で度単位。 dms 度.分.秒

実例:
その1-1:Individual Entry Archiveテンプレートに

<MTLocations> <a href="http://maps.google.com/maps?q=<$MTLocation datum="1"$>+(HERE)&spn=0.004588,0.006136&hl=ja">Google Maps</a><br /> </MTLocations>
と記述すると、位置情報が含まれるエントリーの場合Google Mapsの該当する位置へのリンクが生成される。こんな感じ

その1-2:Individual Entry Archiveテンプレートに

<MTLocations> <a href="http://www.mapfan.com/index.cgi?MAP=E<$MTLocation coordinate="longitude" datum="1" format="dms"$>N<$MTLocation coordinate="latitude" datum="1" format="dms"$>&ZM=12">Mapfan</a><br /> </MTLocations>
と記述すると、位置情報が含まれるエントリーの場合Mapfanの該当する位置へのリンクが生成される

その1-3:たとえばこのようなCGIをMovable TypeのCGIと同じディレクトリに置き、Individual Entry Archiveテンプレートに

<MTLocations> <a href="<$MTCGIPath$>red2map.cgi?ll=<$MTLocation$>&entry_id=<$MTEntryID$>">Map</a><br /> </MTLocations>
と書くと、地図サービスを選択してリンクすることができる。Google Mapsを選ぶとこんな感じ

その2:data.xmlという出力ファイル名のインデックス・テンプレートを作る。中身は以下。

<markers> <MTEntries lastn="100"><MTLocations> <marker lat="<$MTLocation datum="1" coordinate="latitude"$>" lng="<$MTLocation datum="1" coordinate="longitude"$>" permalink="<$MTEntryPermalink$>"/> </MTLocations></MTEntries> </markers>

Google Maps APIのこれを参考に、

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> <title>My Blog with Google Maps</title> <style type="text/css"> v?:* { behavior:url(#default#VML); } </style> <script src="http://maps.google.com/maps?file=api&v=1&key=abcdefg" type="text/javascript"></script> </head> <body> <div id="map" style="width: 640px; height: 640px"></div> <script type="text/javascript"> //<![CDATA[ var map = new GMap(document.getElementById("map")); map.addControl(new GSmallMapControl()); map.addControl(new GMapTypeControl()); map.centerAndZoom(new GPoint(139.741308333333,35.6553083333333), 4); function createMarker(point, permalink) { // Create a lettered icon for this point using our icon class from above var icon = new GIcon(); icon.image = "http://labs.google.com/ridefinder/images/mm_20_red.png"; icon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png"; icon.iconSize = new GSize(12, 20); icon.shadowSize = new GSize(22, 20); icon.iconAnchor = new GPoint(6, 20); icon.infoWindowAnchor = new GPoint(5, 1); var marker = new GMarker(point, icon); var html = "<a href=?"" + permalink + "?">" + permalink + "</a>"; GEvent.addListener(marker, "click", function() { marker.openInfoWindowHtml(html); }); return marker; } var request = GXmlHttp.create(); request.open("GET", "data.xml", true); request.onreadystatechange = function() { if (request.readyState == 4) { var xmlDoc = request.responseXML; var markers = xmlDoc.documentElement.getElementsByTagName("marker"); for (var i = 0; i < markers.length; i++) { var point = new GPoint(parseFloat(markers[i].getAttribute("lng")), parseFloat(markers[i].getAttribute("lat"))); var marker = createMarker(point, markers[i].getAttribute("permalink")); map.addOverlay(marker); } } } request.send(null); //]]> </script> </body> </html>
というhtmlを作ると、地図上に最近100件のエントリーの位置がマップされる。こんな感じ

2005年06月16日

post2blog セキュリティホール

重要 post2blogの2004-04-13以前の版には、セキュリティホールがあります。 内容と対策はこちら

post2blogの添付ファイル名処理についてのご指摘を坂井まどかさんから頂きました。感謝です。ありがとうございました。

投稿先メールアドレスの漏洩がなければ問題ありませんが、一旦漏洩した場合はかなり危険ということで、特に上記リンク先の「内容1」については必ず対策してください。

となると、やはり漏洩を前提としたポリシーということになり、そうなるとXSSの可能性もあるので、これも対策しました(リンク先「内容2」)。

これ以外に、post2blogの内容も若干見直して、近日中にまたアップデートする予定です。

2005年03月09日

春の告白

春の告白

というプロジェクトのサイト構築をしました。

blogシステムにちょっと手を加えて運用(最近blogばっかり)。参加者が自分でblogにユーザ登録できるようにしたのと、登録と同時にそのユーザ名でmoblog可能になるように改造。管理者にメール送ってユーザ登録依頼、とかやってると春の息吹を逃してしまうので。

現在の東京の気温によってバックグラウンドの色が変わります。

2005年02月09日

時間遡行Blog

昔の空中写真を眺めたり並べてつなげたりしているうちに、その写真上に現在の様子をマッピングしたくなってきた。およそ60年の時を隔てたマッピング。

そこで、ULSEを改造して、時間遡行Blogを作ってみた。
slsa.jpg
Suburban Landscape Search Engine - Chofu edition

地図を非表示にするとこんな感じ。
slsa2.jpg

個々のエントリーでは、その地点周辺の拡大写真を表示する。
slsa3.jpg

本当はその地点を中心にした空中写真を動的に生成したいところだが、Movable Typeのプラグインや単なるCGIで強引にやるとさすがに負荷が高すぎるので、とりあえず全体の写真を8x8個に分割したものをあらかじめ用意し、その中からエントリーの地点が含まれるものを選んで表示するようにしている。(その後変更

動的に生成できれば、例えば、GPS携帯でその場所の1946年の空中写真を見るなんてこともできるようになる。「いま」と「1946年」を「ここ」という位置で結びつける。気分はタイムマシーン。

追記:
こうなると「未来」にもマッピングしたくなってくるが、何で「未来」を表すかが問題。都市計画図を使っても面白くない。絵が地味だし、なにより役人が引いた線が「未来」ってわけもないし。結局要するに未来は予測不能なのだった。「いま」を蓄積して未来になってそれを見るしかないかな。もしくは未来になったつもりでこれを見る。
そういう、バックキャスティングの道具としてこの手のものをうまくしつらえられると面白いのだけれど。

追記 2005-02-11:
・いくつかのエントリーで、あまりにも地図エリアの端にポイントが来ているのを見て、やっぱりなんとかしようと考えてみた。
投稿ポイントを中心にして写真や地図を動的に生成するのは確かに負荷が高いが、なにも厳密にど真ん中のピクセルに表示する必要もない。大体真ん中辺りに表示されて、周囲の様子が読み取れればそれで良い。ならば表示している地図領域をさらに縦横奇数個に分割し、中心にくる領域部分にエントリーをマッピングすればいいと気がつく。これならページ生成時の負荷は今までとさほど変わらない。というわけで、とりあえず試しに、縦横3個に分割、つまり全体から見ると24x24に分割。これで充分かも。
・各エントリーで表示される空中写真や地図の縮尺がULSEに比べてずいぶん小さいので、細かい位置のズレも気になってくる。ところが、現在のWIN端末で写真に埋め込む位置情報を手動で修正すると、なぜか測地系が日本測地系(TOKYO97?)に変わってしまう。この妙な仕様に合わせ、エントリーの位置が日本測地系の場合は
http://homepage3.nifty.com/Nowral/02_DATUM/02_DATUM.html#HowTo
を参考に、ページ生成時に測地系変換を行うようにした。

2005年01月18日

スパム大掃除

これまでの対策
http://minken.net/mt/archives/000406.html
http://minken.net/mt/archives/000401.html
が奏効して、スパムが付くことはほとんどなくなった。
が、スパマーのアクセス自体は一向に減らない。

httpd.confをいじって、変なリファラを送ってくるやつには403を返すようにしたが、それでも減らない。Movable Typeにはリファラを自動表示する仕組みはない上、403まで返されて、もう全くなんの役にもたたないにも関わらず延々アクセスをくり返している。となると403とはいえサーバはなにがしかのレスポンスをご丁寧にも返しているわけで、そのセッションが無駄。送っているのは大したデータ量じゃないけど無駄。httpdのログも無駄。

スパムに含まれる無数のリファラをDNSで引いてみると、AレコードのIPアドレスはほとんど同じ。アクセス元はバラバラだが、全部集めてみるとこれも結構かぶっている。なので、
・リファラをDNSで引いてIPが特定のものになるアクセスをログから拾う(スパムと判定)
→アクセス元ごとのスパム回数をカウント
→4回以上来たものをipfwでまとめてdeny(なんとかの顔も3度まで)
という掃除スクリプトを書いて一気に弾いた。オープンな匿名プロキシ経由とおもわれるが、そんなプロキシ経由のアクセスは問答無用で弾いてよろしい。

というわけで、もしスパマーと同じ匿名プロキシ経由の方がいたなら、さようなら。いないだろうけど。

動的にipfw add denyすることも可能だが、ちょっと怖いので、これは今後の課題とする。以上、今日のお掃除は終わり。

追記 2005-01-20:
結果的に、denyしているものはやっぱりほとんどがオープンプロキシ。proxy xxx.xxx.xxx.xxx(←IPアドレス)というキーワードでGoogleすると、ほとんどのアドレスについてオープンプロキシのリストを公開しているページにヒットする。
日本国内と思われるものは3〜4個しかないが、全部LogoVistaの翻訳プロキシ。設定を間違えているのか、意図的にオープンにしているのか。トホホ。

2005年01月06日

被検索

ランドスケープサーチエンジンという名のULSEに来る人は、実際どういうサーチを経て来ているのかということで、WebサーバのログのRefererのうち、検索エンジンと思われるものを拾い出し、デコードして検索語を引き出すものを作ってみた。
Urban landscape search engine: Search words

これを見ると、いかに人々が実空間の情報を求めているのかが分かる。
ULSEがそのニーズにきちんと応えているとは言えないが、応えうる情報がネット上にあまりにも少ないが故にULSEが検索の上位に来ている、という可能性は充分にある。

こんなところにも、実空間と情報空間の乖離、及びそれを結びつける回路の需要が見て取れるのだった。

ちなみに、今書いているこのblogのログも同じようにパースしてみると、
http://minken.net/cgi-bin/parse.pl

全然違うニーズが浮かび上がってくるのだった。

http://video.search.yahoo.co.jp/bin/search?p=%b6%db%c7%fb
これはどうなの?(cam.mpgのほうのことです)
プレビュー画像を見ると、これから始まる緊縛の様子を盗撮しているようにしか見えない。ある意味正しいわけですが。

って書くと、このエントリーにも、また緊縛を求める人々が辿り着いてしまうのだろうなぁ。すみません。緊縛緊縛。

2004年12月08日

動くULSE

Urban Landscape Search Engineを動かしてみる。

考え考え制作開始。
Move
http://ld.minken.net/move.html
軌跡が増えると激重。

Nm2
http://ld.minken.net/nm2.html
軌跡なし、全国版。

2004-12-13
同期の方法を見直したもの。題名も表示するように変更。
http://ld.minken.net/move5.html
全国版。一人のユーザーにつき一日一件の投稿のみ表示。
http://ld.minken.net/move4.html
関東版。軌跡は直前のもののみ表示。全投稿を表示。

日時や位置などの情報をXMLか何かでサーバから取得するのが今風なんだろうけど、2000あまりある投稿数を考えると、読み込みだけで相当待たされることになる。実際、トップページで最近まで使っていた、HTML+CSSの地図は容量が1MB近くになっていた。
そこで、全投稿のユーザー・位置・日付を変数にセットしたswfをMingで生成し、そこに実際の動きなどを記述したswfを読み込んで動かすことにした。つまり、子(各点)が親に情報を聞きつつ自分で動く感じ。これなら容量は大幅に節約でき、読み込みにもほとんど時間がかからない。
しかしこの方法だと子同士の同期がなかなか難しい。
親から全子にイベントを送信し、それで子が動くというのが間違いないんだろうけど、forループで順番に子にイベントを回しているとちょっともたつく。一斉にイベント送信する方法はないのかな?

こういう多数のオブジェクトを同期させて動かすのに、Flashでは普通どういう方法を使うんだろう?
ちゃんとFlashを触るのは初めてなので、そのあたりの作法がまだいまいちつかめていない感じ。

Mingが対応しているFlashのバージョンが古いので、親自身はあまり新しい振る舞いは出来ない。オールドタイプの親を伺いつつ、最新技術(いまのところ使ってないけど)を手にした子が走り回るというものを作らねばならない。Movable Typeのテンプレート、Ming、新旧バージョンのActionScriptと、もう脳味噌がねじ切れそう。特にPerlでMingを使ってActionScriptを書いているときは時々頭が真っ白になります。Mingはflaファイルは作らないので、どういうSWFが出来上がっているのか、自分でもよくわからない。SWFをデコードできるツールでも探す必要がありそう。

つづく(かな?)。

2004-12-09
以下メモ。
・あらかじめ親が全ての情報を把握しておく必要はなく、子の「点呼」を取るような方式でもある程度同期を取れるかもしれない。例)一日の仕事が終わった子は、親に報告をする。親は全ての子の報告が終わった時点で一日日付を進める。
・時間まで含んだ同期、例えば一斉に夕暮れになってゆくとか沖縄は真っ暗だけど犬吠埼ではもう夜が明けてきたなぁというようなものにしようとすると、日付だけでなく「時」レベルで同期を取る必要がある。現在写真一枚表示するのに17フレーム使っているので、日によっては一日400フレームとかになる可能性がある。30秒あまりか。まぁそういう日があってもいいような気はする。でも一日の長さが不定というのは、なんだかわかりにくいものになる危険性もあるな。
そもそも人それぞれの経験を一律に「地図」に載せようとする以上、どこかでこういう裂け目が生まれるのは必然か。というかこの裂け目こそが醍醐味であるはずなのだな。ふーむ。

2004-12-17
ということで、
・日時や位置などの情報は親が一括して持っているが、子に指示は出さない
・子は親に逐次問い合わせて勝手に動く
というものを作ったが、子の数だけloadMovie()しているのがいかにもマズい感じなので、親、子、孫にして、親が子をloadMovie()。親から子に孫の生成を指示。duplicateMovieClip()で生成された孫が親の親に問い合わせて走り回る。というものに変更。ここで孫がしばらくすると止まってしまうという現象でハマる。法則性なし。時間が経つとポロポロ止まり始める。結論だけ書くと、親が定期的に孫のメソッド(内容はなんでも良い)を呼ぶと止まらずに最後まで仕事をやりとげる。なぜかは不明。放任はダメなのか。
孫が親のプロパティを直接操作しまくっているので、この辺りでちゃんとメソッド経由で操作するように書き換えておくことにする。ついでに時間の巻き戻し機能を視野に入れ始めようと思うが、しかし、構造体のコピーの仕方が分からない。参照じゃなくて複製する方法が見当たらない。またドハマり。複製もできた方が簡単に時間を戻せるんだけどなぁ。
↑というのは、つまりオブジェクト指向におけるシャローコピー/ディープコピー問題であるらしいということが調べていて今わかった。Javaなんかもディープコピーは自分で書かないとできないらしい。そういうものなのか。

2004年10月25日

リビルド終了を待たずにコメント動作を完了

Movable Typeでコメントを書き込むと、リビルド動作を伴うので終了までずいぶん待たされることがある。

jm@foo: コメント時のリビルドではお知らせメール機能を利用してインデックスのリビルドを非同期で行う方法を試したが、アーカイブの種類が多かったりするとこのやりかたでもまだまだ遅い。そこで以下の改造をしてみた。

jm@foo: コメント時のリビルドにも書いている、forkする方法。要するに、同期してリビルドしなければならないIndividual Entryアーカイブ以外は子プロセスとして裏でゆっくりリビルドしてもらい、親のプロセスはさっさと終了する。

lib/MT/App/Comments.pmの190行目、

$comment->save; $app->rebuild_entry( Entry => $entry )
$comment->save; my $pid = fork(); if (!$pid) { close STDOUT; $app->rebuild_indexes( Blog => $blog ) or return $app->error($app->translate( "Rebuild failed: [_1]", $app->errstr)); exit; } $app->rebuild_entry( Entry => $entry )
に変更。さらに lib/MT.pmの196行目
return 1 if $blog->is_dynamic; my $at = $blog->archive_type; if ($at && $at ne 'None') { my @at = split /,/, $at; for my $at (@at) { if ($at eq 'Category') { my $cats = $entry->categories; for my $cat (@$cats) { $mt->_rebuild_entry_archive_type( Entry => $entry, Blog => $blog, ArchiveType => $at, Category => $cat, ) or return; } } else { $mt->_rebuild_entry_archive_type( Entry => $entry, Blog => $blog, ArchiveType => $at ) or return; } } }
return 1 if $blog->is_dynamic; $mt->_rebuild_entry_archive_type( Entry => $entry, Blog => $blog, ArchiveType => 'Individual' ) or return; my $pid = fork(); if (!$pid) { close STDOUT; my $at = $blog->archive_type; if ($at && $at ne 'None') { my @at = split /,/, $at; for my $at (@at) { if ($at eq 'Category') { my $cats = $entry->categories; for my $cat (@$cats) { $mt->_rebuild_entry_archive_type( Entry => $entry, Blog => $blog, ArchiveType => $at, Category => $cat, ) or return; } } elsif ($at eq 'Individual') { } else { $mt->_rebuild_entry_archive_type( Entry => $entry, Blog => $blog, ArchiveType => $at ) or return; } } } exit; }
に変更。 でもMTの3.1ではリビルドを非同期で行うか否かの設定もできるようになっているみたいなので、バージョンアップするのが一番いいかも。

2004年10月20日

ecto 2.0.4

ecto 2.0.4

しばらく前にレジストしていたのだが、EUCはHTML Entityでエンコードしないと化ける、という情報を読んで、それじゃあなあ、と使わずにいた。
しかし今日ふと、最近のMovable Typeの日本語化パッチはXMLRPCをUTF-8に統一していることを思いだし、ectoもXMLRPCを使っているんだろうからエンコードなしでも化けないのではないかと試してみた。

…化けなかった。

2004年10月14日

エントリー保存時にインデックスをリビルドしない

前のエントリーに引き続き、次々エントリーを編集したいときの話。
次々エントリーを編集していくときは、一つ保存するたびにいちいちインデックスをリビルドされると時間とCPUの無駄。なのでリビルド権限のないユーザーを作って試してみたが、エントリー保存の際は権限がなくてもリビルドしてしまう。そこでlib/MT.pmを読んでみると、コード中のコメントに、エントリの依存関係を考慮するのは大変だから前後のエントリーとインデックスは決め打ちでまとめてリビルドしちゃうよーんとか書いてある。一応 BuildDependencies というフラグがあるので、これを利用して他のファイルをリビルドしないように変更する。

lib/MT/App/CMS.pm 2320行目

$app->rebuild_entry( Entry => $entry, BuildDependencies => 1 ) or return;
if ($perms->can_rebuild) { $app->rebuild_entry( Entry => $entry, BuildDependencies => 1 ) or return; } else { $app->rebuild_entry( Entry => $entry, BuildDependencies => 0 ) or return; }
に変更。

これでリビルド権限のないユーザーで入って編集しているときはエントリー自身以外のファイルはリビルドされなくなった。リビルドしたいときは権限を持ったユーザーで入り直してリビルドする。

追記
しかし考えてみるとエントリー自身のリビルドも無駄。エントリーのタイトルなどを変更した場合はIndividual Archiveをまとめてリビルドしないと前後のエントリーの<MTEntryPrevious>や<MTEntryNext>に表示されるタイトルが古いままになってしまう。Individual Archiveをまとめてリビルドすれば編集したエントリー自身も当然リビルドされるので、二重にリビルドすることになる。

そもそも権限がなくてもリビルドされるようになっているのは、そうじゃないと普通は不便だからだが、ここにあげているような状況の場合は逆に厳密に権限に従うのが理に適っている。
というわけで結局上記の変更は破棄して以下のようにした。

lib/MT/App/CMS.pm 1747行目

if ($obj->status == MT::Entry::RELEASE() || $status_old eq MT::Entry::RELEASE()) {
if ( ($obj->status == MT::Entry::RELEASE() || $status_old eq MT::Entry::RELEASE() ) && $perms->can_rebuild) {
に変更。

エントリー編集画面内にプレビュー表示

大量のエントリーを次々に編集するときなど、プレビューを見ながら作業したいことがある。
そこで以下のようにしてみた。

lib/MT/App/CMS.pm 509行目

$param{can_view_log} = $app->{author}->can_view_log; } elsif ($type eq 'category') {
$param{can_view_log} = $app->{author}->can_view_log; require MT::Builder; require MT::Template::Context; require MT::Blog; my $blog = MT::Blog->load($blog_id); my $ctx = MT::Template::Context->new; $ctx->stash('entry', $obj); $ctx->stash('blog', $blog); my $build = MT::Builder->new; my $preview_code = <<'HTML'; <p><b><$MTEntryTitle$></b></p> <$MTEntryBody$> <$MTEntryMore$> HTML my $tokens = $build->compile($ctx, $preview_code) or return $app->error($app->translate( "Parse error: [_1]", $build->errstr)); defined(my $html = $build->build($ctx, $tokens)) or return $app->error($app->translate( "Build error: [_1]", $build->errstr)); $param{preview_body} = $html; } elsif ($type eq 'category') {
に変更。そして tmpl/cms/edit_entry.tmpl の好きなところに<TMPL_VAR NAME=PREVIEW_BODY>を追加。つまりEntry編集画面のテンプレートにプレビュー画面と同じ変数が渡るようにして、それを表示するようにした。

コメントスパム対策その2

しばらくログを取ってみたら、スパムの多くがRefererを送って来ていないようなので、jm@foo: コメントスパム対策に加えて、以下のようにしてみた。

lib/MT/App/Comments.pm 161-162行目の

} my $comment = MT::Comment->new;
} require MT::ConfigMgr; my $cfg = MT::ConfigMgr->instance; my $archive_url = $blog->archive_url; my $comment_cgi = $cfg->CGIPath . 'mt-comments.cgi'; my $refer = $ENV{'HTTP_REFERER'} || 'No referer'; unless ($refer =~ /^($archive_url|$comment_cgi)/) { $app->log("Invalid referer ($refer), $user_ip"); return $app->handle_error('リファラ(<a target="_blank" href="http://service1.symantec.com/SUPPORT/INTER/nisjapanesekb.nsf/jp_docid/20031024163125947?Open&src=&docid=20021020160209947&nsf=support%5CINTER%5Cnisjapanesekb.nsf&view=jp_docid&dtype=&prod=&ver=&osv=&osv_lvl=">参考</a>)が無効です'); } my $comment = MT::Comment->new;
に変更。こちらはベイジアンフィルタの場合と違い、コメントを保存する前に弾いている。 はじめ、
return $app->handle_error($app->translate('Invalid referer'));
として、ja.pmを使って日本語メッセージを表示しようと思ったのだが、なぜか日本語に変換されないので、コード中に直書き。そういえば'Name and email address are required. 'も日本語化されていない。なぜだろう?

2004年09月25日

コメントスパム対策

Bayesian filter for MTでスパムを一括削除できるようにしてあるが、削除する作業すら面倒。そもそもスパムと分かっているコメントは保存されないようにしたい。同じようなことを考えている人は絶対いると思うのだが、ちょっと探しても見つからなかったので、以下のようなことを試してみた。

lib/MT/App/Comments.pmの190行目と191行目

$comment->save; $app->rebuild_indexes( Blog => $blog )
を以下のように書き換え。
$comment->save; require MT::Bayesian; my $by = MT::Bayesian->new; $by->new_bayesian( {blog_id => $entry->blog_id, comment_id => $comment->id} ); if ($by->spam>0) { $comment->remove; $by->remove; return $app->error($app->translate( "Spam.", $app->errstr)); exit; } $app->rebuild_indexes( Blog => $blog )
これでベイジアンフィルタがスパムと判定したコメントは書き込めなくなった。本当は $comment->save の前に弾きたいのだが、うまく行かなかったので一旦保存して判定してから削除している。これでもリビルドは掛からないし、とりあえず満足。

2004-10-11 追記
しばらく使ってみると、フィルタの学力(笑)が足りないのか、しばしばスパムではないものも弾いてしまうことがあった。そこで以下のように変更した。

if ($by->spam>0) { $comment->remove; $by->remove; return $app->error($app->translate( "Spam.", $app->errstr)); exit; }
if ($by->prob*100>50) { #$comment->remove; #$by->remove; return $app->error($app->translate( "Spam.", $app->errstr)); exit; }
に変更。上の方では「スパムか否か」で判定していたところが、下ではもう少し細かく数値で指定できるようになる。$by->prob*100>50の「50」がmt-bayesian.cgiのManage Comments画面に表示されるSpam Probability。例えばうちに来るspamはほとんど全てが90%以上のProbabilityだが、spamではないものも時々70%とかになることがあるので、この数値を75程度にすることで誤判定が減ることを期待できる。 さらにコメントとその判定結果の削除を省略し、誤判定したコメントも後からManage Comments画面でspamではないと学習し直させ、復活可能にすることにした。結局こまめにメンテナンスが必要な状態に一歩後退してしまったが、立て続けに数十のスパム爆弾でリビルドが掛かりまくることを考えると、これでもまだマシ。 ベイズフィルタがもう少し賢くなったら再度問答無用モードに戻そうと思っている。

2004-10-14 追記
現在のところ以下のようにしている。

require MT::Bayesian; my $by = MT::Bayesian->new; $by->new_bayesian( {blog_id => $entry->blog_id, comment_id => $comment->id} ); if ($by->prob*100>70) { #$comment->remove; #$by->remove; $app->log("Spam: $user_ip"); return $app->handle_error('スパムコメントの可能性があります'); }
$app->errorだと終了しっぱなしなので、$app->handle_errorにして、誤判定された人が修正しやすいようにしたのと、なぜかうまく働かない$app->translateを外した。

Refererなしスパムが大半の場合は、こちらの方法がベイジアンフィルタもいらないので簡単で手っ取り早い。

2004年08月31日

動画や音声でもmoblog

040831_2328~01.3gp
040831_2328~01
speaker040831_2335~01.wav
moblogゲートウェイを以下のように改造。
・3gppムービーにもサムネールが付くようにした。
・qcpをwavに変換するようにした。

W21SAに機種変更していろいろ試したくなったので瞬発的に改造。

静止画だけじゃないmoblog。
イヤホンマイク端子につないで使える、広範囲の音を拾えるマイクを探したい。
でも15秒だけ、音質もcdmaOneですが。(追記:W21SAはイヤホンマイク経由で録音の音声入力ができないことが判明。がーん。)

サムネール生成は、3gppも映像トラックはamcと同じm4vなので、ffmpegでの処理自体は何も変更しなくて良い。なので添付ファイル拡張子の判定をちょこっといじっただけ。
qcpファイルを、もっと一般的な音声ファイルに変換するのは、以前からやりたかったのだが、OS Xで動くコンバータがなかったので放置していた。QuickTimeが音声トラックのqcelp形式を扱えるはずなのだが、qcp単体のファイルはダメ。qualcommもOS9用のコンバータしか出しておらず、待ってても出てきそうにないので、仕方なく、別マシンのWindowsに送り込んで変換させたものを取ってくるという大げさな方法で実現。あまりにも美しくない処理方法なので、おそらく元バージョンのバージョンアップには反映しないと思います。

2004年01月19日

AddMaps プラグイン

2005-07-14 緯度経度を取り出す、より汎用的なプラグインを作成しました。地図サービスへのリンクにも使えます。→こちら

アップロードされた画像ファイルに位置情報が含まれていたら、地図へのリンクを付加するプラグイン。Movable Type のプラグイン自体初めて書くので、なにか変なことをしているかも。

いままで自作のmoblogスクリプトで位置を取り出していたのだが、エントリー前に本文を書き換えてしまうよりプラグインのほうがひょっとしてスマートなのかも、と思って作ってみた。プラグインのいいところは、moblogに限らず普通にアップロードしたファイルでも処理できるところ。一方短所は、とりあえず思いつくところだと、あらためてリビルドするとそのたびに処理するのが無駄、ということだが、他にもあるだろう。

インストール:
AddMaps.plをMovable Typeのpluginsに置いてください。

なお、このプラグインを使用するにはImage::Infoが必要です。インストールしていない場合は、Image::Infoを展開してできるlib/Image以下の「Info」「Info.pm」「TIFF.pm」を、Movable Typeのextlib/Imageの下に、もとからあるSize.pmと一緒に置いてください。こんな感じ。

使用方法:
テンプレートで、地図へのリンクを付加したいタグに「add_maps="1"」を追加してください。例えば、
<$MTEntryBody add_maps="1"$>
という具合。すると、テキスト中のimgタグを探して、その画像ファイルがローカルにあるもので、かつGPS情報が含まれていたら、画像の横に「(MAP)」というリンクを追加します。

なお、このプラグインを使用することで損害などが発生しても私は責任を一切負いません。悪しからず。

Download file

2003年10月24日

コメント時のリビルド

MovableTypeでコメントを付けようとすると、えらく時間がかかることがある。リビルドが原因だが、特にULSEではややこしいテンプレートを使っているので、シャレにならないくらい遅くなっていた。以下対策メモ。

MovableTypeには、コメント先のエントリーのAuthorにメールを送るお知らせ機能がある。このメールをトリガーにしてリビルドするようにすれば、コメントのセッション自体はリビルドを待つことなく即終了できる。

というわけで、
・lib/MT/App/Comments.pmでリビルドしているところをコメントアウト。
・Authorのメールアドレスを、リビルドした後改めてメールを送信、という動作をするPerlスクリプトへのエイリアスにする。
とすると、あっと言う間にコメント動作が終了する。

そんなわかりにくいことしないでforkするようにすればいいんだろうけど、MTに手を入れるところが少ない方がいいだろうということで、この方法を採用。

2003年06月18日

International Moblogging Conference

International Moblogging Conference
参加登録してみました。
位置情報付きmoblogも、すでにやっている人がいるのだろう。

…と思ったら、ばりばり位置情報ネタの人たちもスピーカーの中に入ってますね。
http://www.clickgraphic.com/toripspace/

多摩美の人たちらしい。

Posted by jiro at 15:11 | コメント (6)

International Moblogging Conference

International Moblogging Conference
参加登録してみました。
位置情報付きmoblogも、すでにやっている人がいるのだろう。

…と思ったら、ばりばり位置情報ネタの人たちもスピーカーの中に入ってますね。
http://www.clickgraphic.com/toripspace/

多摩美の人たちらしい。

Posted by jiro at 15:11 | コメント (6)

2003年05月30日

地図サイト

Mapionの地図
@NAVIの地図

同じ場所の同じようなスケールでも、これだけ違う。
実用的なのは、mapion。でも位置情報として面白いのは@NAVI。

mapionの地図にはアドレス(何町何丁目とか)が載っているので、頭の中で場所の特定はしやすい。でも実際の場所を反映しているのは道路と地割りくらい。街というのはこんなもんじゃないだろうと思ってしまう。一方@NAVIはアドレスがないので不便だけど場所の様子がわかる(ような感じがする)。この「ような感じがする」のが面白いポイント。

Posted by jiro at 18:11 | コメント (3)

2003年05月22日

moblogシステム概要


2005-07-17 機能を整理して新版を作成しました。→こちら。

重要! 2005-06-16 更新 2004-04-13以前の版には、セキュリティホールがあります。内容と対策はこちら

このweblogに携帯メールから書き込めるようにしているシステムの概要とセットアップ方法
環境:
Mac OS X 10.2 (10.3以降はSendmailからPostfixに変更されているので、後半のSMTPの設定方法が異なる)

概要:
1.メールサーバでメールを受ける
2.題名、本文、添付ファイルをとりだす
3.weblogに書き込む
という動作をするスクリプトを使用。XMLRPCを使用しているので、メールサーバとMovable Typeが動いているWebサーバは別のマシンでも良い。

更新履歴

  • 2005-06-13: セキュリティ対策(投稿内容のサニタイズ)
  • 2004-04-13: A5501TのExifタグに対応。(GPSタグの度が1/100000、分・秒共に0)
  • 2004-02-13:
    • [Movable Type 2.661 + 日本語化パッチ]に対応。
    • GPS情報の抽出をexiflistからImage::Infoに変更。
    • mencoderによるamcファイルの変換を廃止。(QuickTime6.5によりamc再生環境が整ったため不要と判断)
  • 2003-07-24: Extendedが生成されないバグを修正。
  • 2003-07-20: Altitudeタグがない場合に対応。

この手の動作をするpythonのスクリプトとしてmail2entryというものがすでにあるが、これがOS X10.2に含まれるバージョンのpythonではうまく動かなかったので、perlで書いてしまった。車輪の再発明かも。
Download file
GNU General Public License version 2日本語) に従ったフリーウェアです。

位置付写真を添付したメールでMovable Typeに書き込むための基本的な機能しか実装してません。

  • 想定している測地系は、WGS-84。
  • 地図へのリンクは、@NAVI。
  • カテゴリーは扱いません。
  • ffmpegをインストールしておけば、auムービーメールのサムネールを作って同時にアップロード。
  • ムービーに埋め込んだ位置情報には対応していません

測地系の変換をして日本測地系のMapionを使う、自動的にカテゴリーを設定する、などの拡張をするには、nob sekiさんのSync A World You Want To Explore: GPSは正確だが、地図情報は?が参考になります。

メールから書き込む機能はいらない、画像に地図リンクだけ付け足したい、という場合は、AddMapsプラグインをどうぞ。

スクリプトの設定:

my $url = 'http://www.your-site.com/movabletype/mt-xmlrpc.cgi';
Movable Type のmt.cgiをmt-xmlrpc.cgiに置き換えたもの。

my $blog_id = 2;
書き込みたいweblogのid。Entry編集画面のURLにblog_id=で表示されているもの。

my $username = 'Melody';
my $password = 'Nelson';
書き込むユーザ名とパスワード。メール書き込み用に新しくユーザを追加したほうがいいかも。

my $code = utf8; # utf8, euc, jis, sjis
書き込む漢字コード
(2.661+日本語化パッチではXML-RPCがutf8に統一されているようなので、この設定は削除)

my $MT_DIR = '/Library/WebServer/Documents/mt/';
同じマシンにMovable Type をインストールしているならば、そのディレクトリ。文字列の最後は/で。

my $parse_path = '/Users/Shared/post2blog';
テンポラリファイルを作るディレクトリを用意する。OS Xの場合、Finder上から確認しやすい/Users/Shared/に作るのが良いかも。

モジュールのインストール:

OS XでMovable Typeが動いている環境の標準以外で必要なperlモジュール
http://search.cpan.org/author/ERYQ/IO-stringy-2.108/
http://search.cpan.org/author/GAAS/MIME-Base64-2.20/
http://search.cpan.org/author/MARKOV/MailTools-1.58/
http://search.cpan.org/author/ERYQ/MIME-tools-5.411a/
http://search.cpan.org/author/DANKOGAI/Jcode-0.83/
http://search.cpan.org/~gaas/Image-Info-1.16/

MIME-toolsをインストールする前に、その上の3つをインストール。

それぞれを展開したディレクトリの中で
% perl Makefile.PL
% make
% sudo make install
でインストールできる。

OS Xの標準に含まれていないものとしては、SOAP::Liteも必要だが、Movable Typeが動いている環境ならば、すでにインストールされている。Movable Typeを動かしているマシンとは別のマシンでこのスクリプトを動かす場合は、SOAP::Liteもインストールする。SOAP::Liteは依存するモジュールが多くてややこしいので、CPANモジュールを使ったほうがいいかもしれない
まずはCPANモジュール自身のアップデート。途中でいろいろ聞いてくるが、基本的にはすべてデフォルトでよい。つまりひたすらリターンキー。
% perl -MCPAN -e shell
cpan> install Bundle::CPAN
ただしlibwww-perlのインストール中に
Do you want to install the HEAD alias? [y]
と聞いてくるので、これだけはnと答えないと、大文字小文字を区別しないHFS+ボリュームの場合/usr/bin/headコマンドを潰してしまう。

cpan> reload cpan

CPANモジュールを使っていると、途中でperl5.8.0とかのインストールが始まってしまうことがある。そんなときはダウンロード中にすかさずCtrl+Cで中断。

cpan> install SOAP::Lite

sendmailの設定:
まずはサーバとして動くようにする。
[参考ページ]
http://pisa.csrs.is.uec.ac.jp/TechInfo/Macintosh/SendmailOnJaguar/UptheSendmailOnJaguar.html

[参考ページ]に書いてないこと:
DNSで引けるマシン名がなくてIPアドレスだけの場合
/etc/mail/local-host-names
に、生IPアドレスを[]で囲んだものを記入。仮にアドレスを192.168.0.1とすると
192.168.0.1
[192.168.0.1]
これは、SMTPサーバによってはTo: user@192.168.0.1では送信ができず、To: user@[192.168.0.1]とする必要があるため。.macはこのパターン。ezwebは[]なしで送信可。

次に、サーバに届いたメールをスクリプトに渡すようにする。
スクリプトを/usr/adm/sm.bin内に置く。
% sudo mkdir -p /usr/adm/sm.bin
% sudo cp post2blog /usr/adm/sm.bin
% sudo chmod 555 /usr/adm/sm.bin/post2blog

NetInfoマネージャで[参考ページ]の通りにaliasesを追加。ただし、"members"にはアドレスのかわりにスクリプトへのパイプをフルパスで記入。
| /usr/adm/sm.bin/post2blog

再起動。

これで、
alias名@IPアドレス
にメールを送信すれば書き込まれる。


重要:
2004-04-13以前の版には以下のセキュリティホールがあります。最新のものをダウンロードしなおして使用するか、以下の対策を取ってください。

内容1:
添付ファイル名のサニタイズを行っていないため、投稿先メールアドレスが漏洩すると、最悪の場合、メールを受信するサーバ上で任意のコードの実行が可能です。

この脆弱性情報は坂井まどかさんによるものです。ありがとうございました。

対策1:
オリジナルの添付ファイル名を使用しないようにしてください。

例) $parser->output_under($parse_path); の次行に $parser->filer->ignore_filename(1); を追加。

内容2:
同じく投稿先メールアドレスが漏洩した場合、題名、本文などを利用したXSSが可能になります。
対策2:
投稿内容のサニタイズを行ってください。

例) スクリプト冒頭に BEGIN { my $MT_DIR = '/Library/WebServer/Documents/mt/'; unshift @INC, $MT_DIR . 'extlib'; unshift @INC, $MT_DIR . 'lib'; } use MT::Sanitize; を追加。 my $sub = $head->get('Subject'); の次行に $sub = MT::Sanitize->sanitize($sub); を追加。 $cont = $j->set($cont)->utf8; の前行に $cont = MT::Sanitize->sanitize($cont); を追加。

以上二つの変更を行ったものと旧バージョンとのdiffは以下。

% diff -c post2blog.old post2blog *** post2blog.old Thu Jun 16 17:55:58 2005 --- post2blog Thu Jun 16 17:58:40 2005 *************** *** 10,15 **** --- 10,20 ---- # You can redistribute it and/or modify it under the terms of # the GNU General Public License version 2. # + BEGIN { + my $MT_DIR = '/Library/WebServer/Documents/mt/'; + unshift @INC, $MT_DIR . 'extlib'; + unshift @INC, $MT_DIR . 'lib'; + } use strict; *************** *** 17,35 **** my $blog_id = 2; my $username = 'Melody'; my $password = 'Nelson'; - my $MT_DIR = '/Library/WebServer/Documents/mt/'; my $parse_path = '/Users/Shared/post2blog'; my ($maxx, $maxy) = (320, 320); - unshift @INC, $MT_DIR . 'extlib'; - use MIME::Parser; #use Data::Dumper; use File::Basename; use Jcode; use XMLRPC::Lite; use Image::Info qw(image_info dim); my $j = new Jcode; --- 22,38 ---- my $blog_id = 2; my $username = 'Melody'; my $password = 'Nelson'; my $parse_path = '/Users/Shared/post2blog'; my ($maxx, $maxy) = (320, 320); use MIME::Parser; #use Data::Dumper; use File::Basename; use Jcode; use XMLRPC::Lite; use Image::Info qw(image_info dim); + use MT::Sanitize; my $j = new Jcode; *************** *** 43,51 **** --- 46,56 ---- my $parser = new MIME::Parser; $parser->output_under($parse_path); + $parser->filer->ignore_filename(1); my $entity = $parser->parse_data($str); my $head = $entity->head; my $sub = $head->get('Subject'); + $sub = MT::Sanitize->sanitize($sub); my $message_id = $head->get('Message-ID'); my $cnttype = $entity->mime_type; $sub = $j->set($sub)->mime_decode->utf8; *************** *** 85,90 **** --- 90,96 ---- } close(CONT); } + $cont = MT::Sanitize->sanitize($cont); $cont = $j->set($cont)->utf8; my @conts = split(/?n?n?n/, $cont);

moblogシステム概要


2005-07-17 機能を整理して新版を作成しました。→こちら。

重要! 2005-06-16 更新 2004-04-13以前の版には、セキュリティホールがあります。内容と対策はこちら

このweblogに携帯メールから書き込めるようにしているシステムの概要とセットアップ方法
環境:
Mac OS X 10.2 (10.3以降はSendmailからPostfixに変更されているので、後半のSMTPの設定方法が異なる)

概要:
1.メールサーバでメールを受ける
2.題名、本文、添付ファイルをとりだす
3.weblogに書き込む
という動作をするスクリプトを使用。XMLRPCを使用しているので、メールサーバとMovable Typeが動いているWebサーバは別のマシンでも良い。

更新履歴

  • 2005-06-13: セキュリティ対策(投稿内容のサニタイズ)
  • 2004-04-13: A5501TのExifタグに対応。(GPSタグの度が1/100000、分・秒共に0)
  • 2004-02-13:
    • [Movable Type 2.661 + 日本語化パッチ]に対応。
    • GPS情報の抽出をexiflistからImage::Infoに変更。
    • mencoderによるamcファイルの変換を廃止。(QuickTime6.5によりamc再生環境が整ったため不要と判断)
  • 2003-07-24: Extendedが生成されないバグを修正。
  • 2003-07-20: Altitudeタグがない場合に対応。

この手の動作をするpythonのスクリプトとしてmail2entryというものがすでにあるが、これがOS X10.2に含まれるバージョンのpythonではうまく動かなかったので、perlで書いてしまった。車輪の再発明かも。
Download file
GNU General Public License version 2日本語) に従ったフリーウェアです。

位置付写真を添付したメールでMovable Typeに書き込むための基本的な機能しか実装してません。

  • 想定している測地系は、WGS-84。
  • 地図へのリンクは、@NAVI。
  • カテゴリーは扱いません。
  • ffmpegをインストールしておけば、auムービーメールのサムネールを作って同時にアップロード。
  • ムービーに埋め込んだ位置情報には対応していません

測地系の変換をして日本測地系のMapionを使う、自動的にカテゴリーを設定する、などの拡張をするには、nob sekiさんのSync A World You Want To Explore: GPSは正確だが、地図情報は?が参考になります。

メールから書き込む機能はいらない、画像に地図リンクだけ付け足したい、という場合は、AddMapsプラグインをどうぞ。

スクリプトの設定:

my $url = 'http://www.your-site.com/movabletype/mt-xmlrpc.cgi';
Movable Type のmt.cgiをmt-xmlrpc.cgiに置き換えたもの。

my $blog_id = 2;
書き込みたいweblogのid。Entry編集画面のURLにblog_id=で表示されているもの。

my $username = 'Melody';
my $password = 'Nelson';
書き込むユーザ名とパスワード。メール書き込み用に新しくユーザを追加したほうがいいかも。

my $code = utf8; # utf8, euc, jis, sjis
書き込む漢字コード
(2.661+日本語化パッチではXML-RPCがutf8に統一されているようなので、この設定は削除)

my $MT_DIR = '/Library/WebServer/Documents/mt/';
同じマシンにMovable Type をインストールしているならば、そのディレクトリ。文字列の最後は/で。

my $parse_path = '/Users/Shared/post2blog';
テンポラリファイルを作るディレクトリを用意する。OS Xの場合、Finder上から確認しやすい/Users/Shared/に作るのが良いかも。

モジュールのインストール:

OS XでMovable Typeが動いている環境の標準以外で必要なperlモジュール
http://search.cpan.org/author/ERYQ/IO-stringy-2.108/
http://search.cpan.org/author/GAAS/MIME-Base64-2.20/
http://search.cpan.org/author/MARKOV/MailTools-1.58/
http://search.cpan.org/author/ERYQ/MIME-tools-5.411a/
http://search.cpan.org/author/DANKOGAI/Jcode-0.83/
http://search.cpan.org/~gaas/Image-Info-1.16/

MIME-toolsをインストールする前に、その上の3つをインストール。

それぞれを展開したディレクトリの中で
% perl Makefile.PL
% make
% sudo make install
でインストールできる。

OS Xの標準に含まれていないものとしては、SOAP::Liteも必要だが、Movable Typeが動いている環境ならば、すでにインストールされている。Movable Typeを動かしているマシンとは別のマシンでこのスクリプトを動かす場合は、SOAP::Liteもインストールする。SOAP::Liteは依存するモジュールが多くてややこしいので、CPANモジュールを使ったほうがいいかもしれない
まずはCPANモジュール自身のアップデート。途中でいろいろ聞いてくるが、基本的にはすべてデフォルトでよい。つまりひたすらリターンキー。
% perl -MCPAN -e shell
cpan> install Bundle::CPAN
ただしlibwww-perlのインストール中に
Do you want to install the HEAD alias? [y]
と聞いてくるので、これだけはnと答えないと、大文字小文字を区別しないHFS+ボリュームの場合/usr/bin/headコマンドを潰してしまう。

cpan> reload cpan

CPANモジュールを使っていると、途中でperl5.8.0とかのインストールが始まってしまうことがある。そんなときはダウンロード中にすかさずCtrl+Cで中断。

cpan> install SOAP::Lite

sendmailの設定:
まずはサーバとして動くようにする。
[参考ページ]
http://pisa.csrs.is.uec.ac.jp/TechInfo/Macintosh/SendmailOnJaguar/UptheSendmailOnJaguar.html

[参考ページ]に書いてないこと:
DNSで引けるマシン名がなくてIPアドレスだけの場合
/etc/mail/local-host-names
に、生IPアドレスを[]で囲んだものを記入。仮にアドレスを192.168.0.1とすると
192.168.0.1
[192.168.0.1]
これは、SMTPサーバによってはTo: user@192.168.0.1では送信ができず、To: user@[192.168.0.1]とする必要があるため。.macはこのパターン。ezwebは[]なしで送信可。

次に、サーバに届いたメールをスクリプトに渡すようにする。
スクリプトを/usr/adm/sm.bin内に置く。
% sudo mkdir -p /usr/adm/sm.bin
% sudo cp post2blog /usr/adm/sm.bin
% sudo chmod 555 /usr/adm/sm.bin/post2blog

NetInfoマネージャで[参考ページ]の通りにaliasesを追加。ただし、"members"にはアドレスのかわりにスクリプトへのパイプをフルパスで記入。
| /usr/adm/sm.bin/post2blog

再起動。

これで、
alias名@IPアドレス
にメールを送信すれば書き込まれる。


重要:
2004-04-13以前の版には以下のセキュリティホールがあります。最新のものをダウンロードしなおして使用するか、以下の対策を取ってください。

内容1:
添付ファイル名のサニタイズを行っていないため、投稿先メールアドレスが漏洩すると、最悪の場合、メールを受信するサーバ上で任意のコードの実行が可能です。

この脆弱性情報は坂井まどかさんによるものです。ありがとうございました。

対策1:
オリジナルの添付ファイル名を使用しないようにしてください。

例) $parser->output_under($parse_path); の次行に $parser->filer->ignore_filename(1); を追加。

内容2:
同じく投稿先メールアドレスが漏洩した場合、題名、本文などを利用したXSSが可能になります。
対策2:
投稿内容のサニタイズを行ってください。

例) スクリプト冒頭に BEGIN { my $MT_DIR = '/Library/WebServer/Documents/mt/'; unshift @INC, $MT_DIR . 'extlib'; unshift @INC, $MT_DIR . 'lib'; } use MT::Sanitize; を追加。 my $sub = $head->get('Subject'); の次行に $sub = MT::Sanitize->sanitize($sub); を追加。 $cont = $j->set($cont)->utf8; の前行に $cont = MT::Sanitize->sanitize($cont); を追加。

以上二つの変更を行ったものと旧バージョンとのdiffは以下。

% diff -c post2blog.old post2blog *** post2blog.old Thu Jun 16 17:55:58 2005 --- post2blog Thu Jun 16 17:58:40 2005 *************** *** 10,15 **** --- 10,20 ---- # You can redistribute it and/or modify it under the terms of # the GNU General Public License version 2. # + BEGIN { + my $MT_DIR = '/Library/WebServer/Documents/mt/'; + unshift @INC, $MT_DIR . 'extlib'; + unshift @INC, $MT_DIR . 'lib'; + } use strict; *************** *** 17,35 **** my $blog_id = 2; my $username = 'Melody'; my $password = 'Nelson'; - my $MT_DIR = '/Library/WebServer/Documents/mt/'; my $parse_path = '/Users/Shared/post2blog'; my ($maxx, $maxy) = (320, 320); - unshift @INC, $MT_DIR . 'extlib'; - use MIME::Parser; #use Data::Dumper; use File::Basename; use Jcode; use XMLRPC::Lite; use Image::Info qw(image_info dim); my $j = new Jcode; --- 22,38 ---- my $blog_id = 2; my $username = 'Melody'; my $password = 'Nelson'; my $parse_path = '/Users/Shared/post2blog'; my ($maxx, $maxy) = (320, 320); use MIME::Parser; #use Data::Dumper; use File::Basename; use Jcode; use XMLRPC::Lite; use Image::Info qw(image_info dim); + use MT::Sanitize; my $j = new Jcode; *************** *** 43,51 **** --- 46,56 ---- my $parser = new MIME::Parser; $parser->output_under($parse_path); + $parser->filer->ignore_filename(1); my $entity = $parser->parse_data($str); my $head = $entity->head; my $sub = $head->get('Subject'); + $sub = MT::Sanitize->sanitize($sub); my $message_id = $head->get('Message-ID'); my $cnttype = $entity->mime_type; $sub = $j->set($sub)->mime_decode->utf8; *************** *** 85,90 **** --- 90,96 ---- } close(CONT); } + $cont = MT::Sanitize->sanitize($cont); $cont = $j->set($cont)->utf8; my @conts = split(/?n?n?n/, $cont);

2003年05月14日

ムービーのサムネイル

S_030513_1909~01.amc
S_030513_1909~01 (MPEG1)
( --> MPEG1 )
結局MEncoderとは別にffmpegをmake。やっとmpegのサムネイルが生成可能になった。

最終的にはffmpegというメジャーなところに青い鳥的に落ち着いたけど、いろいろ調べたり様々なライブラリをmakeしようとしてエラーに悩まされたり、ずいぶん遠回りをしてほとんど丸一日費やしてしまった。

おかげで今まで疎かった動画関係なんかの情報をちょっとは得られたけど…

Posted by jiro at 04:39 | コメント (0)

ムービーのサムネイル

S_030513_1909~01.amc
S_030513_1909~01 (MPEG1)
( --> MPEG1 )
結局MEncoderとは別にffmpegをmake。やっとmpegのサムネイルが生成可能になった。

最終的にはffmpegというメジャーなところに青い鳥的に落ち着いたけど、いろいろ調べたり様々なライブラリをmakeしようとしてエラーに悩まされたり、ずいぶん遠回りをしてほとんど丸一日費やしてしまった。

おかげで今まで疎かった動画関係なんかの情報をちょっとは得られたけど…

Posted by jiro at 04:39 | コメント (0)

2003年05月13日

ムービーメールで書き込み

S_030402_1307~01.amc ( --> MPEG1 )
専用アプリがないMacではezmovieを再生できないと思っていたが、内部データはmpeg4なので、試しにオープンソースのMPlayerに放り込んでみると再生できた。

MPlayerの動作を見ていると、きちんとファイルの構造と内容を解析してから内部のデータを取り出して再生しているようだ。再生開始の際、この解析に少し時間を取られるが、多数のフォーマット入り乱れてデータ内部で入れ子のようになっている動画や音声データを扱うには、特定の構造と内容の組み合わせしか再生しようとしないQuickTimePlayerよりずいぶん頼もしい。

が、音声が消えてしまう。音声トラックのデータはqcelpだが、MPlayerでそれらしきフォーマットをデコードするライブラリはQuickTime。設定を書き替えて無理やりデコードさせようとするとQuickTimeを呼ぶ段階でクラッシュする。

なんでqcelpなんて古いフォーマットを採用したんだろう。cdmaone機の再生チップとかの問題かなー。

というわけでMPEGには音声トラックがありません。

Posted by jiro at 02:18 | コメント (4)

ムービーメールで書き込み

S_030402_1307~01.amc ( --> MPEG1 )
専用アプリがないMacではezmovieを再生できないと思っていたが、内部データはmpeg4なので、試しにオープンソースのMPlayerに放り込んでみると再生できた。

MPlayerの動作を見ていると、きちんとファイルの構造と内容を解析してから内部のデータを取り出して再生しているようだ。再生開始の際、この解析に少し時間を取られるが、多数のフォーマット入り乱れてデータ内部で入れ子のようになっている動画や音声データを扱うには、特定の構造と内容の組み合わせしか再生しようとしないQuickTimePlayerよりずいぶん頼もしい。

が、音声が消えてしまう。音声トラックのデータはqcelpだが、MPlayerでそれらしきフォーマットをデコードするライブラリはQuickTime。設定を書き替えて無理やりデコードさせようとするとQuickTimeを呼ぶ段階でクラッシュする。

なんでqcelpなんて古いフォーマットを採用したんだろう。cdmaone機の再生チップとかの問題かなー。

というわけでMPEGには音声トラックがありません。

Posted by jiro at 02:18 | コメント (4)