« 2006年04月 | メイン | 2006年06月 »

2006年05月29日

mod_secutiryをmt-comments.cgiにも適用

朝サーバが落ちてた。Femoは既に移行済みなのでまぁ、よかった。

mod_secutiryをmt-comments.cgiにも適用

<FilesMatch "mt-(tb|comments).cgi">
  SecFilterEngine On
  SecFilterScanPOST On
  SecFilterDefaultAction "deny,log,status:406"
  SecFilterSelective POST_PAYLOAD "^[\x00-\x7F]+$"
</FilesMatch>


ちなみに、フォームから正しくPOSTした場合は、フォームのボタンのValueがマルチバイトを含むので問題ないはず。
さて効果はあるか。

2006年05月27日

[Femo]はてな記法の自動リンクサポート

Femoではてな記法の自動リンクをサポートしました。
id記法やurl、asin記法など一通り利用することができます。

femo-hatena-asin.png

asin記法で出力されるAmazonのAffiliate IDは僕のIDになってます。
後日IDの変更もサポートします。

"Parsing of undecoded UTF-8 will give garbage .." in Text::Hatena::HTMLFilter

以前にも書いたけど、

 stderr: Parsing of undecoded UTF-8 will give garbage when decoding entities at /usr/lib/perl5/site_perl/5.8.6/Text/Hatena/HTMLFilter.pm line 36.

はHTML::Parserのwarningsで、消すにはHTML::Parserに渡す前にutf8 flagをたてるしかなさそう。

そこで、Text::Hatena ver. 0.12のText::Hatena::HTMLFilterをいじくってみた。
基本は、Parserに渡す前にutf8 flagを立てる。
また、Text::Hatenaのtexthandler(autolink処理)に渡す前にはflagをoff、出力する時は、基本off
というところで、parse、texthandler、htmlの各メソッドを以下のようにしてみた。

sub parse {
    my $self = shift;
    my $html = shift or return;
    if ( Encode::is_utf8($html) ) {
        $self->{original_is_utf8} = 1;
    }
    else {
        Encode::_utf8_on($html);
    }
    $self->{parser}->parse($html);
}

sub texthandler {
    my $self = shift;
    return sub {
        my $text = shift;
        Encode::_utf8_off($text) if Encode::is_utf8($text);
        $text =
          &{ $self->{context}->texthandler }( $text, $self->{context}, $self );
        Encode::_utf8_on($text) unless Encode::is_utf8($text);
        $self->{html} .= $text;
      }
}

sub html {
    my $self = shift;
    my $html = $self->{html};
    Encode::_utf8_off($html) if Encode::is_utf8($html) && !$self->{original_is_utf8};
    $html;
}


Text::Hatenaは基本flagはoffの想定できているんだけど、utf8前提っぽいところもあるから、flagはonにしていた方が楽じゃないかなぁ。。

2006年05月24日

Femoのメンテナンスおよびサーバ移動を5月24日24時から行います

Femoをご利用いただきありがとうございます。
Femoのメンテナンスおよびサーバ移動を5月24日24時から行います。
30分ほどで終了する予定です。

DNSの書き換えも含むのでメンテナンス終了後に短時間アクセスができない可能性もあります。
ご迷惑をおかけしますが、よろしくお願いします。

今回の移動で、Femoのサービスが、私の自宅サーバからさくらのレンタルサーバに移ります。
今までより安定してサービスを行えると思いますので、これからもよろしくお願いします。


__追記__
終了しました。(1:23)
Webサーバの設定に間違いがあり、修正に手間取っておりました。

2006年05月23日

Template::Plugin::FillInForm::ForceUTF8

ForceUTF8シリーズ。

TT Pluginなんだけど、フィルターのデフォルトの名前は、fillinformのままにしてみている。
Template::Provider::Encodingをhacksて、[% USE FillInForm %]を自動的に書き換えると便利かも。
ソースはここから

package Template::Plugin::FillInForm::ForceUTF8;

use strict;
use base qw(Template::Plugin::Filter);
use HTML::FillInForm::ForceUTF8;

our $VERSION = 0.01;

sub init {
    my $self = shift;
    $self->{_DYNAMIC} = 1;
    $self->install_filter($self->{_ARGS}->[0] || 'fillinform');
    $self;
}

sub filter {
    my ($self, $text, $args, $config ) = @_;
    my $fif = HTML::FillInForm::ForceUTF8->new;
    return $fif->fill(scalarref => \$text, %$config);
}

1;


2006年05月22日

HTML::FillInForm::ForceUTF8をCPAN up

HTML::FillInForm::ForceUTF8をCPAN upした。

http://search.cpan.org/dist/HTML-FillInForm-ForceUTF8/

Template::PluginやCatalyst::Pluginを揃えると便利かもしれない。

XOOPSサイトのEntryFullText upgrader

xoops.pl

sub handle {
    my($self, $args) = @_;
    $args->{content} =~ m!<meta name="generator" content="XOOPS" />!;
}

sub extract {
    my($self, $args) = @_;
    return ($args->{content} =~ m!<div class="itemBody">(.*?)</div>!s)[0];
}


FPNとか。

2006年05月19日

Asa festoon

CD2枚でることに今気づいた。
Amazonのレコメンド精度よくないなぁ。

Sharing2
Sharing2
posted with amazlet on 06.05.19
Asa festoon
ゲートレコーズ (2006/05/10)

PERLA
PERLA
posted with amazlet on 06.05.19
Asa festoon
ゲートレコーズ (2006/05/24)

両方とも注文した。マリオと一緒に。

それと、ふと思い立ったので、昔々つくったRSSをPlaggerで作り直した
RSS 1.0から2.0へ変わった以外はたぶん問題ないはず。

2006年05月17日

FemoのURLについてのお知らせ

Femoを利用して頂いてありがとうございます。

FemoのURLですが、femo.jpに加えて
http://femo.nomadscafe.jp/
でサービスを行っておりましたが、サービスの安定稼働とサーバの移動のため、

http://femo.jp/

の方へ統一していこうと思っております。
nomadscafe.jpからは当分の間femo.jpへ自動的にリダイレクトされる形になります。

なお、サーバの移動については後日、停止時間などを含めてお知らせいたします。

mod_secutiryを使ってApacheでTrackback Spamを弾く

MTのTrackback Spam対策にmod_securityを使って英数字のみのTrackbackを弾くようにしてみた。

mt-tb.cgiが動く前にApacheとかProxyとかでSPAMを判定できるとサーバに優しいし、かなり良いんじゃないかと思う。

mod_secutiryを

# apxs -cia mod_security.c

でインストールして、

<Files "mt-tb.cgi">
    SecFilterEngine On
    SecFilterScanPOST On
    SecFilterDefaultAction "deny,log,status:406"
    SecFilterSelective POST_PAYLOAD "^[\x00-\x7F]+$"
</Files>


と設定。


フィルタリングされていると、

[Wed May 17 18:33:37 2006] [error] [client 213.178.208.228] mod_security: Access denied with code 406. Pattern match "^[\\\\x00-\\\\x7F]+$" at POST_PAYLOAD [severity "EMERGENCY"] [hostname "nomadscafe.jp"] [uri "/mt32/mt-tb.cgi/844"]
[Wed May 17 18:33:41 2006] [error] [client 213.178.208.228] mod_security: Access denied with code 406. Pattern match "^[\\\\x00-\\\\x7F]+$" at POST_PAYLOAD [severity "EMERGENCY"] [hostname "nomadscafe.jp"] [uri "/mt32/mt-tb.cgi/1122"]
[Wed May 17 18:34:23 2006] [error] [client 213.178.208.228] mod_security: Access denied with code 406. Pattern match "^[\\\\x00-\\\\x7F]+$" at POST_PAYLOAD [severity "EMERGENCY"] [hostname "nomadscafe.jp"] [uri "/mt32/mt-tb.cgi/1079"]

こんな感じのログが残ります。

参考:
株式会社ソフテック - mod_securityでWebサーバを守る(第1回)
Journal InTime - mod_securityでreferer spamよけ(2)

chmod 644 mt-tb.cgi

なんかサーバがガリガリ言っているし重い、と思って、psで調べると、mt-tb.cgiが数十個立ち上がってた。
error_logの方にしか残っていないんだけど、

[Wed May 17 12:59:35 2006] [error] [client 212.0.138.30] Premature end of script headers: mt-tb.cgi, referer: http://nomadscafe.jp/mt32/mt-tb.cgi/1024
[Wed May 17 12:59:35 2006] [error] [client 200.130.15.10] Premature end of script headers: mt-tb.cgi, referer: http://nomadscafe.jp/mt32/mt-tb.cgi/1138
[Wed May 17 12:59:35 2006] [error] [client 211.239.84.131] Premature end of script headers: mt-tb.cgi, referer: http://nomadscafe.jp/mt32/mt-tb.cgi/1029[Wed May 17 12:59:35 2006] [error] [client 212.0.138.30] Premature end of script headers: mt-tb.cgi, referer: http://nomadscafe.jp/mt32/mt-tb.cgi/1096
[Wed May 17 12:59:35 2006] [error] [client 202.88.129.254] Premature end of script headers: mt-tb.cgi, referer: http://nomadscafe.jp/mt32/mt-tb.cgi/921
[Wed May 17 12:59:35 2006] [error] [client 212.0.138.30] Premature end of script headers: mt-tb.cgi, referer: http://nomadscafe.jp/mt32/mt-tb.cgi/1020
[Wed May 17 12:59:41 2006] [error] [client 212.0.138.30] Premature end of script headers: mt-tb.cgi, referer: http://nomadscafe.jp/mt32/mt-tb.cgi/559
[Wed May 17 12:59:41 2006] [error] [client 222.112.213.55] Premature end of script headers: mt-tb.cgi, referer: http://nomadscafe.jp/mt32/mt-tb.cgi/1054[Wed May 17 12:59:41 2006] [error] [client 195.175.37.6] Premature end of script headers: mt-tb.cgi, referer: http://nomadscafe.jp/mt32/mt-tb.cgi/1046
[Wed May 17 12:59:41 2006] [error] [client 61.32.100.70] Premature end of script headers: mt-tb.cgi, referer: http://nomadscafe.jp/mt32/mt-tb.cgi/1078
[Wed May 17 12:59:42 2006] [error] [client 203.172.163.194] Premature end of script headers: mt-tb.cgi, referer: http://nomadscafe.jp/mt32/mt-tb.cgi/970[Wed May 17 12:59:42 2006] [error] [client 212.0.138.30] Premature end of script headers: mt-tb.cgi, referer: http://nomadscafe.jp/mt32/mt-tb.cgi/1102
[Wed May 17 12:59:42 2006] [error] [client 203.68.220.125] Premature end of script headers: mt-tb.cgi, referer: http://nomadscafe.jp/mt32/mt-tb.cgi/1066[Wed May 17 12:59:42 2006] [error] [client 203.131.168.19] Premature end of script headers: mt-tb.cgi, referer: http://nomadscafe.jp/mt32/mt-tb.cgi/711
[Wed May 17 12:59:42 2006] [error] [client 212.0.138.30] Premature end of script headers: mt-tb.cgi, referer: http://nomadscafe.jp/mt32/mt-tb.cgi/900
[Wed May 17 12:59:42 2006] [error] [client 212.0.138.30] Premature end of script headers: mt-tb.cgi, referer: http://nomadscafe.jp/mt32/mt-tb.cgi/1129
[Wed May 17 12:59:42 2006] [error] [client 212.0.138.30] Premature end of script headers: mt-tb.cgi, referer: http://nomadscafe.jp/mt32/mt-tb.cgi/595


こんな感じで10分間以上ストーム状態。
なす術がないので、mt-tb.cgiを

# chmod 644 mt-tb.cgi


ApacheレベルでのBanAsciiフィルタでもあればいいのかなぁ。

__追記__
mod_secutiryを導入して、mt-tb.cgiをもとに戻してtrackback受けれるようにしました。

2006年05月16日

CGI::Application::Plugin::DBIC::Schema

思いつきで書いた
SYNOPSISはこんな感じ

  # In your CGI::Application based web application module...
  use CGI::Application::Plugin::DBIC::Schema;

  sub setup{
      my $self = shift;
      $self->schema_config(
          schema_class => 'My::DBIC::Schema',
          connect_info => [
                            "DBI:...",
                            "username",
                            "password",
                            {AutoCommit => 1}
                          ]
      );
  }

  sub my_run_mode {
      my $self = shift;
      my $ret = $self->schema('Actor')->find(1);

  }


使い道はあまりないかもなぁ。

package CGI::Application::Plugin::DBIC::Schema;

use strict;
use base qw/Exporter/;
use UNIVERSAL::require;

our $VERSION = '0.01';
our @EXPORT = qw/schema_config schema/;

sub schema_config {
    my $self = shift;
    my $args = ( ref $_[0] ) : shift : {@_};

    die "schema_config() error: schema_class must be defined"
      unless defined $args->{schema_class};

    my $schema_class = $args->{schema_class};
    $schema_class->require
      or die
      "schema_config() error: Cannot load schema class '$schema_class': $@";

    $self->{DBIC_SCHEMA} = $schema_class->connect($args->{connect_info} || []);
}

sub schema {
    my $self = shift;
    $self->{DBIC_SCHEMA}->resultset(shift);
}

1;

YAPCのVideoを、Plaggerで

Filter::FindEnclosuresを使うと楽っぽいので
EntryFullTextでちょっとhack

custom_feed_handle: http://www\.archive\.org/search\.php\?query=subject:%22yapc%22
custom_feed_follow_link: /details/YAPC(Asia)?2006Tokyo
handle: http://www\.archive\.org/details/YAPC(Asia)?2006Tokyo
extract: (<a href="(?:[^"]*)">QuickTime</a>)(?:.*?)<h1><span class="rightmost"></span>(.*?)</h1><p class="content">(.*?)<h2>
extract_capture: more title body
extract_after_hook: $data->{body} .= qq(<p class="content">) . $data->{more} . qq(</p>) if $data->{more}


これを、適当な名前で、assets/Filter-EntryFullTextに放り込んで、
下の設定で動かす。

global:
  plugin_path:
    - /path/to/plagger/plugins
  timezone: Asia/Tokyo
  cache:
    base: /tmp/plagger
plugins:
  - module: Subscription::Config
    config:
      feed:
         - url: http://www.archive.org/search.php?query=subject:%22yapc%22
  - module: Aggregator::Simple
  - module: Filter::EntryFullText
  - module: Filter::FindEnclosures
  - module: Publish::Feed
    config:
      format: RSS
      dir: /path/to/tmp
      filename: %t.rss


iTunesでも確認しますた。

2006年05月15日

make disttest

Perl Moduleを書いて、それをpackageにするときに、

# make disttest

で最終確認しています。

↓これに載っていたような

続・初めてのPerl - Perlオブジェクト、リファレンス、モジュール
Randal L.Schwartz Tom Phoenix ドキュメントシステム
オライリー・ジャパン (2003/12)
売り上げランキング: 11,381

2006年05月14日

DS買った

PlaggerConで東京行った時にちょっと寄った某電気屋でnintendo DS Lite発見。即購入
一緒にTETRISを買ったんだけど、楽しいね。もろに戦略はまりまくり。
マリオブラザーズをBGMにするところなんて、悪魔だね。

今日は、「脳を鍛える大人のDSトレーニング」を買ってきた。
脳年齢「37歳」ですたorz

マリオが楽しみ。

2006年05月13日

Plagger::Plugin::Filter::ImageGathering

Plaggerがenclosure対応ってことで。
Image TagのURLをenclosureに追加していくPlugin

  - module: Filter::ImageGathering

configはない。

package Plagger::Plugin::Filter::ImageGathering;

use strict;
use base qw( Plagger::Plugin );

sub register {
    my($self, $context) = @_;
    $context->register_hook(
        $self,
        'update.entry.fixup' => \&update,
    );
}

sub update {
    my ( $self, $context, $args ) = @_;
    my $body = $args->{entry}->body;

    while($body =~ m!<img([^>]+)>!ig){
        $self->gathering($&,$context,$args)
    }
}

sub gathering {
    my ( $self, $tag, $context, $args ) = @_;

    my %attrs;
    while ( $tag =~ m!(\w+)\s*=\s*(["'])(.*?)\2!g ) {
        $attrs{$1} = $3;
    }

    return unless $attrs{src};

    my $enclosure = Plagger::Enclosure->new;
    $enclosure->url( URI->new($attrs{src}) );
    #$enclosure->length();
    #$enclosure->type();

    $args->{entry}->add_enclosure($enclosure);
}

1;



http://svn.nomadscafe.jp/public/library/perl/Plagger-Plugin-Filter-ImageGathering/

に置いておいた。

2006年05月11日

リポジトリみれるようにした。

リポジトリを公開することにした。
全部じゃないけど。

ここ

CPANにあげてたりあげてなかったりするPerlモジュールと、ちょっとアプリケーション。
Blogに書いていたものとか、整頓しながら増やしていく予定。

ディレクトリ構成とかはid:typesterさんが公開されているリポジトリを参考にしました。

PlaggerLDR::Model::DBIC

実際動くか試してないけど、Catalyst::Model::DBIC::Schemaを使うとたぶん、こうなる。

Index: lib/PlaggerLDR/Model/DBIC.pm
===================================================================
--- lib/PlaggerLDR/Model/DBIC.pm        (revision 0)
+++ lib/PlaggerLDR/Model/DBIC.pm        (revision 0)
@@ -0,0 +1,19 @@
+package PlaggerLDR::Model::DBIC;
+
+use strict;
+use warnings;
+use base qw/Catalyst::Model::DBIC::Schema/;
+use YAML;
+use List::Util qw(first);
+
+my $config = YAML::LoadFile( PlaggerLDR->path_to('root', 'config.yaml') );
+my $module = first { $_->{module} eq 'Store::DBIC' } @{$config->{plugins}};
+
+__PACKAGE__->config(
+    schema_class => 'Plagger::Schema::SQLite',
+    connect_info => $module->{config}->{connect_info}
+
+);
+
+1;
+
Index: lib/PlaggerLDR/Controller/Notify.pm
===================================================================
--- lib/PlaggerLDR/Controller/Notify.pm (revision 712)
+++ lib/PlaggerLDR/Controller/Notify.pm (working copy)
@@ -4,18 +4,9 @@
 use warnings;
 use base 'Catalyst::Controller';
 
-# XXX anti-DRY
-use YAML;
-use List::Util qw(first);
-use Plagger::Schema::SQLite;
-
-my $config = YAML::LoadFile( PlaggerLDR->path_to('root', 'config.yaml') );
-my $module = first { $_->{module} eq 'Store::DBIC' } @{$config->{plugins}};
-my $schema = Plagger::Schema::SQLite->connect(@{$module->{config}->{connect_info}});
-
 sub notify : Global {
     my($self, $c) = @_;
-    my $unread = $schema->resultset('Entry')->search({ read => 0 })->count;
+    my $unread = $c->model('DBIC::Entry')->search({ read => 0 })->count;
     $c->response->content_type('text/plain');
     $c->response->body("|$unread|http://reader.livedoor.com/reader/\n");
 }


Catalyst::Model::DBIC::SchemaをベースにしたModelを作ってそこにconnect_infoを書く。
DRYにできますよぉ。


API.pmの分は追記に。

Index: lib/PlaggerLDR/Controller/API.pm
===================================================================
--- lib/PlaggerLDR/Controller/API.pm    (revision 712)
+++ lib/PlaggerLDR/Controller/API.pm    (working copy)
@@ -4,14 +4,6 @@
 use warnings;
 use base 'Catalyst::Controller';
 
-use YAML;
-use List::Util qw(first);
-use Plagger::Schema::SQLite;
-
-my $config = YAML::LoadFile( PlaggerLDR->path_to('root', 'config.yaml') );
-my $module = first { $_->{module} eq 'Store::DBIC' } @{$config->{plugins}};
-my $schema = Plagger::Schema::SQLite->connect(@{$module->{config}->{connect_info}});
-
 sub default : Private {
     my($self, $c) = @_;
 }
@@ -20,7 +12,7 @@
     my($self, $c) = @_;
 
     my @subs;
-    for my $feed ( $schema->resultset('Feed')->search({ }) ) {
+    for my $feed ( $c->model('DBIC::Feed')->search({ }) ) {
         my $unread = $feed->entries({ read => 0 })->count;
         next if $c->req->param('unread') && $unread == 0;
 
@@ -46,7 +38,7 @@
     my $data;
     my @entries;
 
-    my $feed = $schema->resultset('Feed')->find($c->req->param('subscribe_id'));
+    my $feed = $c->model('DBIC::Feed')->find($c->req->param('subscribe_id'));
 
     $data->{subscribe_id} = $feed->id;
     $data->{channel} = {
@@ -95,7 +87,7 @@
 sub touch_all : Local {
     my($self, $c) = @_;
 
-    my $feed = $schema->resultset('Feed')->find( $c->req->param('subscribe_id') );
+    my $feed = $c->model('DBIC::Feed')->find( $c->req->param('subscribe_id') );
     for my $entry ($feed->entries({ read => 0 })) {
         $entry->read(1);
         $entry->update;

2006年05月10日

本とCD

べつやくれいの本

ココロミくん
ココロミくん
posted with amazlet on 06.05.10
べつやく れい
アスペクト (2006/05/01)


と、yes, mama ok?のtributeアルバム

tribute to yes,mama ok?
tribute to yes,mama ok?
posted with amazlet on 06.05.10
オムニバス
インディペンデントレーベル (2006/04/20)


申し訳ないのですが、このyes, mama ok? なる方々をしらなかった。
なぜ買ったのかと言えば、our hour と QYPTHONE。
our hourは久しぶりに聞いたなぁ

2006年05月07日

slashcodeサイトのEntryFullText

use Perlslashdot.orgslashdot.jpで確かめた。

slashcode.pl

sub handle {
    my($self, $args) = @_;
    $args->{entry}->permalink =~ m!article\.pl\?sid=\d\d/\d\d/\d\d/\d+!;
}

sub extract {
    my($self, $args) = @_;
    my $body = ($args->{content} =~ m!<div class="intro(?:text)?">(.*?)</div>!s)[0];
    if ($body && ($args->{content} =~ m!<div class="(?:bodytext|full)?">(.*?)</div>!s)[0]) {
        $body .= $1;
    }
    $body;
}


slashdot.orgはFeedBurnerを使っているみたいなので、permalinkでURLをhandleする必要があった。

さくらの専用サーバ申し込んだ

femo.jpの安定稼働のため、さくらの専用サーバに申し込んだ。
たぶん、再来週ぐらいから使えると思われ。ちなみにOSはFedora Core 4を選んだ。
lighttpdとかMySQL 5を使おうかなと考えりんぐ中。

問題はどうやって、femo.nomadscafe.jpからfemo.jpへの移動をするのかというところで、bookmarkletなんかもあるので、当分redirectかなと思っている。

しかし、初期+2ヶ月分で4万円は結構だなぁ。

2006年05月04日

Catalyst::Plugin::Snippets/Continuation

Catalyst::Plugin::Snippets
Catalyst::Plugin::Continuation
両方とも気になるモジュールではあるんだけど、
PREREQがおかしい。

WriteMakefile
(
          'NAME' => 'Catalyst::Plugin::Snippets',
          'VERSION_FROM' => 'lib/Catalyst/Plugin/Snippets.pm',
          'PREREQ_PM' => {
                           'Catalyst' => '5.691'
                         },
          'INSTALLDIRS' => 'site',
          'PL_FILES' => {}
        )
;


現時点でのCatalystの最新バージョンは「5.6901」

2006年05月02日

自宅サーバがホコリまみれ

最近不安定な自宅サーバですが、
暖かくなってきたので、CPUファンの回転数をあげようと箱をあけたら、ホコリまみれだった。

060502_0024~01.jpg

自宅サーバの掃除は定期的に行わないとだめだな。

2006年05月01日

漫画とか本とか

5月になりますた。

MOON LIGHT MILE 12 (12)
MOON LIGHT MILE 12 (12)
posted with amazlet on 06.05.01
太田垣 康男
小学館 (2006/04/27)
よつばと! 5 (5)
よつばと! 5 (5)
posted with amazlet on 06.05.01
あずま きよひこ
角川(メディアワークス) (2006/04/27)
チーズスイートホーム 3 (3)
こなみ かなた
講談社 (2006/04/21)
Perl Best Practices
Perl Best Practices
posted with amazlet on 06.05.01
Damian Conway
Oreilly & Associates Inc (2005/08)
売り上げランキング: 15,910
Ecology Of Everyday Life 毎日の環境学
小沢健二
東芝EMI (2006/03/08)


Amazonのおすすめ商品を持ってくるPlagger::Plugin::CustomFeed::AmazonYourStoreとかいうのを思いついた