このブログを検索

2011/12/28

sendmail

不正アクセスの試みが絶えない。 とりあえずftpdは起動しない。 sshdとsendmailは止めるわけにはいかない。

外部からのmailは転送できてlocalhostがダメってどういうことだ?

DAEMON_OPTIONS(`Port=smtp,Addr=127.0.0.1, Name=MTA')dnl


これがデフォルトなのですが、ポート番号を変え、さらに外部のメールを転送するために以下の様にしました。

DAEMON_OPTIONS(`Port=587,Name=MTA')dnl


しかしこうすると、外部のメール(つまりパソコンのメールソフトから送信する)は可能なのですが、サーバにsshでログインして

echo aiueo|mail root


とかやると、送信できないのです。 デフォルト設定に戻すとローカルの送信は可能になりますが外部から送信できない。 ローカルでも外部からも送信できる方法はないのだろうか? ローカルでmailコマンドを実行すると port 25になっているのか? mailコマンドでポート番号を指定する方法があるのか・・・? わからない!

とりあえず外部からメールを送る必要はないので、デフォルト設定に戻した。タダ不思議なのは、以前は両方できてたはずだということ。 それがbugzillaをインストールしてbugzillaからメールを送ろうとしたらできず、 あれと思って外部から送信したらそれもできなかった。 メールクライアントで認証設定を追加したら送れるようになった。 何も変えていないはずなのに・・・

/etc/mail/authinfo


を作成する方法が紹介されていた・・・しかしこのファイルはデフォルトでは存在しない・・・587にポートを変更するから特別な設定が必要なのか・・・ メンドクサイ・・・そもそもなんで25を587に変えたんだっけ・・・ たしか25では送信できなかったからだ・・・ 別に25が587に変わったから何だって言うんだ・・・スパマーが587に来たら同じ事じゃないのか・・・わけがわからん・・・

sendmailの設定( sendmail.mc → sendmail.cf )でポートをデフォルト(25)にし、iptablesでも25を開けているのに、 どうしても port 25が開かないのである。 サーバにsshで入って telnet localhost 25 とやればsendmailに接続できるのだが自宅のPCからはできず、nmapしてみると25が開いていない。サーバでnetstatした結果は 25 と 587以外に違いはないようだが・・・sendmailの設定とiptables以外に、ポートを制限する設定があるのだろうか?

25が開かないのはおそらくさくらのVPSの仕様(?)なのでしょう。 正確には「25が開かない」のではない。サーバでは開いているが、その手前でブロックしているのではないでしょうか。ルータかなんかで。本当はブロックしてはいけないはずですが、まあ25を使うのは危険のようだからそれはよしとしましょう。そして 587を使うとローカルからメールが送信できない理由は、どうもmailコマンドを使った場合認証しないからのようです。

echo test|mail root


とやったときに、アクセスするのはローカルのsendmailなのですが、ここで認証をしていないので送れないのです。外部のPCのメールソフトで「送信サーバには認証が必要」を設定しないようなものです。 mailコマンドで認証させる方法をman mailとかネットで検索してみましたがどうもないようで、それをさせるのが authinfoファイルを使うやり方のようです。ここにユーザ名とパスワードを設定するようです。

2011/12/23

BlackBerryが欲しい

BlackBerryが欲しい。iPhone4Sを使っていて、特に不満というわけではないのだが、docomoの端末を1台持っておきたいのである。今はdocomoもauもsoftbankも、「スマホ」をメインにしていて、電車のなかでもタッチパネルの端末を持った人だらけだ。でも「スマホ」は1台で十分だ。androidの端末を買ってみてiPhoneと比較してみたい気もするが、わざわざカネを出して買う気まではない。

以前からBlackBerryはいいなと思っていた。使ったことはないのだが、外観と、なによりQWERTY配列のキーボードが魅力だった。普通の携帯電話(私は「ガラケー」などという言葉は死んでも口にできない。「スマホ」もカッコつきでぎりぎり許容範囲だ)を使っていた時に、インターネットを利用したいのが主な理由で小さなPCを持ち歩きたいとずっと思っていた。しかしPCはどんなに小さくても大きすぎ、バッテリーの持続時間も短く、ACアダプターが必要だったりした。Linux Zaurusを買って見たが、1日で使用に耐えないことがわかった。iPhone3GSを買って、ほとんど私の欲求不満は解消された。心配していたタッチパネル上の仮想キーボードの感度がすばらしかったからである。

ところが最近、いやな傾向が見え始めた。それは、インターネットのサイトやサービスが「スマホ対応」を始めたことである。そもそもどうして「スマホ」が登場したかと言えば、携帯電話で無理やり利用していたインターネットの閲覧性や操作性を向上させることが一番であっただろう。つまり、「PCと同じようにインターネットを利用したい」ということだった。

携帯電話でも、「PCサイトビューアー」などというものが登場していたがやはり携帯電話の画面とキーボードでは限界があった。iPhoneを使い始めた時、flashが動かないとかいろいろと制限はあったが、ほとんどのサイトがPCとほぼ変わらず利用できることに感激し満足した。ところが最近、多くのサイトがiPhone対応もしくは「スマホ」対応を始めてしまった。サイトによっては適切な文字の大きさになって読みやすかったりするのであるが、一番困るのは、「スマホ対応サイト」では、PCで利用する時にはあるメニューやボタンの一部が省略されている場合があることだ。これは非常に腹立たしい。

そもそも、WWWというのは利用する端末を選ばないものなのである。パソコンだってOSも違うし解像度も言語も違うのだが、同じサイトを閲覧することができる。それは、サイトが各OSや言語に対応するようにしているのではなく、サイトもPC(ブラウザ)も仕様にのっとって相手のハードウェアを問わずに使用できるようにしていたのである。利用者の端末によってサービスを変えるのはよいことだと思っているのだろうが、わたしには余計なおせっかいである。

そして最近思うのは、やっぱり「スマホ」のインターネット利用にはまだまだ無理があるということである。それはiPhoneでも言えることである。というより、今までのWEBサイトが、余計な画像、動画、アニメーションなどを使いすぎていたのである。チラチラする広告もそうである。多くの人が携帯電話でインターネットを利用し始めた時、必要なものはそのなかのほんのちょっとの「ことば」つまり文字情報であるのだと気付いたはずだ。

それがカタチをとってサービスとなり世界中に広まったのがtwitterである。私はtwitterでインターネットの原理を再確認したような気がした。最近おこなわれているサイトの「スマホ対応」も、余計なものをけずって文字だけを表示している。画像、動画、音声などはリンクとして付加され、どうしてもという場合だけ参照すればよい。私はもう、インターネットで「マルチメディア」を利用することに全然魅力を感じなくなっている。文字だけでいい。動画はテレビでいい。

というわけで、もう一台端末を持つならBlackBerryと考えているのである。BlackBerryの現行機種は9780とかいうもので、来年に9900という新機種が出る予定のようであるが、これはタッチスクリーンに対応しているようだ。BlackBerryも「スマホ」化の流れにのみこまれつつある。

そもそもBlackBerryが「スマホ」のはしりだったのだが、いまや「スマホ」とは「タッチスクリーンかどうか」であるかのようになってしまった。「スマホ」にやや食傷気味なのだが、「電話とメールで十分」というところにはもう戻れない。動画やゲームはいらないがtwitterとブログとニュースくらいを利用する必要はある。となると、やっぱりBlackBerryでしょう。

2011/12/22

winny

winny開発者の無罪が確定したそうだ。このことについて、有名な大学教授でアルファブロガーな人などが、日本が技術的に遅れをとって大変な損失であったなどと言っているのを読んだ。

細かいことや厳密なことはメンドクサイからいつものように結論から言うが、もしwinny開発者が逮捕されずにwinnyがあのまま利用されていたとしても、それが世界をリードするような技術に発展することなどなかったであろう。

ただ、もはや止めることのできない違法コピーの蔓延が今よりちょっと早く進んだだけであっただろう。開発者も、利用者も、P2Pとかクラウドとか、技術的なこともそれが生むビジネスなんかにも全く興味はなかったはずだ。

私はwinnyを開発した人間も、それを利用した人間も軽蔑している。そしてそれは、開発者が有罪か無罪かなどということとは全く関係のないことである。

2011/12/21

さくらのVPSにbugzillaをインストールする

なんのために・・・?

ダウンロードは ftp.mozilla.gr.jp から。 ftpコマンドで。 bug-ja-2.20-ja.4+-final.tar.gz を落す。 一番新しいやつ。 anonymousでログインする方法がわからず調べる。ユーザ名のプロンプトでanonymousと入れ、パスワードはメールアドレスを入れる。tar xzvf で解凍し、QUICKSTART というファイルにインストール方法が書いてある。 bugzillaはperlで書かれている。 ./checksetup.pl というスクリプトがあって必要なものがあるかをチェックしてくれる。 perlのモジュールとか。 "not found"となったモジュールをインストールしていく。 モジュールインストールはこれ。

perl -MCPAN -e shell


optionalとあるが、GDも入れる。 グラフ表示などができるのだろう。 ぜひ欲しい。 が、install GDとやると....

cpan[5]> install GD
Running install for module 'GD'
Running make for L/LD/LDS/GD-2.46.tar.gz
Fetching with LWP:
ftp://ftp.riken.jp/lang/CPAN/authors/id/L/LD/LDS/GD-2.46.tar.gz
Fetching with LWP:
ftp://ftp.riken.jp/lang/CPAN/authors/id/L/LD/LDS/CHECKSUMS
Checksum for /root/.cpan/sources/authors/id/L/LD/LDS/GD-2.46.tar.gz ok

CPAN.pm: Going to build L/LD/LDS/GD-2.46.tar.gz

Notice: Type perl Makefile.PL -h for command-line option summary.

**UNRECOVERABLE ERROR**
Could not find gdlib-config in the search path. Please install libgd 2.0.28 or higher.
If you want to try to compile anyway, please rerun this script with the option --ignore_missing_gd.
(以下略)


となる。 libgdをインストールしてください、と言っている。 これはモジュールではないので、yumでインストールする。(調べてわかった)

yum install gd-devel


gd-develのインストールが終わったので cpanで install GDをやるがインストールできない。 cpan shellを一回抜けて起動しなおしたらinstallできた。 perlのモジュールチェックはOKになったが、そのあとが進まない。

Couldn't do defparams.pl: そのようなファイルやディレクトリはありません at Bugzilla/Config.pm line 133.
Compilation failed in require at ./checksetup.pl line 460.
BEGIN failed--compilation aborted at ./checksetup.pl line 460.


defparams.ja.pl

defparams.en.pl

というファイルがあるが、defparams.pl はない。 ja.plを .plとしてコピーしてみるがダメ。

cp defparams.ja.pl defparams.pl
cp l10nmes.ja.pl l10nmes.pl


進んだ。mysqlに接続できない、となって止まる。mysqlが起動していない。

service mysqld start


そして、以下を設定

$ mysql -uroot -p
Enter password:
mysql> GRANT ALL PRIVILEGES ON *.* TO bugs@localhost IDENTIFIED BY ‘password’ WITH GRANT OPTION;
mysql> flush privileges;
mysql> quit;


それから、localconfigに以下を設定

$db_user = 'bugs';
$db_pass = 'password';


localconfigというファイルは自動で作成されるようなのだがされなかったので、 上記の設定のみをviで書いて保存し、 checksetup.pl を実行したらいろいろと設定が書き込まれた。

apacheの設定を追加してapacheを再起動し、index.cgiを表示してみるが、エラーが出ていて殺風景な、スタイルシートが読み込めてないようなページが表示されている。ヘンだなとおもいつつアカウントを作ってみるが、メールが送信されない。以前はできていたはずのメール送信自体ができなくなっている。

なんかグダグダになってしまった。 コントロールパネルにログインできなくなったりする。 パスワードも間違っていないはずなのに。sshからrebootする。メールで問い合わせしようといろいろやっているうちにコントロールパネルにも入れた。やっぱりしょせんはVPS、いろいろ不具合があるのだろうか。

以下を参考に(というかそのままマネして)インストールができた。3.0.3-ja.7

www.nbrains.net/php/pukiwiki/index.php?Setup%2FBugzilla

何件かVPSに関して悩んでいることを登録してみる。が、日本語が化けたりする。トップページをカスタマイズしたいなと調べていると、3.4がリリースされたという情報が。2009年に。入れなおすか・・・ 本家は4.0.2だった。別のディレクトリに入れなおす。perlモジュールなどはもう入れてあるから、./checksetupが一発でできて、パスワードを設定し、.htaccessもコピーするだけでインストールできた。同じDBを使っているから登録したbugがそのまま表示される。・・・今回はそれでいいのだが、別のバグを管理する場合はuserを変えればいいのかな?

自分だけで使うなら英語でかまわないのだが、本当はこれを仕事で使いたい。「サーバ立ててbugzillaインストールすれば使えますよ、僕にやらせてください。」なんてね。日本の会社じゃ、やっぱり英語だと「えー英語なの・・・?」となってしまうから。

日本ではmantisの方がよく使われているようだ。 私は両方使ったことがあるがbugzillaの方が全然よかった。 というか、いままで使ったbtsでまともなものはbugzillaだけだと思っているくらいである。

2011/12/10

原因不明のハングアップ

パソコンがときどきハングする。10秒くらいか。起動しないこともある。

なんどかオフ・オンするが治らず。 いらないアプリをアンインストールする。 bitcometで落したいらないファイルを削除する。 デフラグする。 デスクトップにある余計なファイルを消す、または移動する。

タスクマネージャーなどで観察する。CPU使用率が上がっているように見えるがよくわからない。 電源を落してフタを開け、エアダスターを吹き付ける。 つい最近やったはずなのだが・・・ メモリを抜いてさしなおす。暖かい。 HDDのケーブルを抜いてさしなおし、位置も直す。 DVDドライブのケーブルを抜く。 CPUファンにエアダスターを吹き付ける。かなりホコリがでる。

電源を入れると、治った。いろいろやったので断言できないが、多分、CPUファンのホコリだと思う。 以前にも似たようなことがあった気がする。 

ハングというのは、パソコンの動作がすべて止まってマウスを動かしてもカーソルが動かなくなる状態。 音もでなくなるが、ダダダダダ・・・となることもある。 しばらく待つと動きだす。 これを不定期に1分くらいの間隔で繰り返す。 イヤでしょ?

2011/12/06

iPhone3GSと4S

iPhone4Sを使って1ヶ月ほどたつ。

その前は3GSを2年くらい使っていた。重い。持ちにくい。画面はキレイ。重い。3GSと4Sの重さの差は5gらしい。

3GSの時は、ずっとパソコンを使ってマウスを持っていた手でiPhoneを持つと『軽いな』といつも感心していたものだ。今はズシっと来る。気軽に使えない。裏までガラス張りになって、裸のまま机に置く気にならない。

3GSは裸で使っていたが4Sにはケースを付けた。ところがケースをつけるとポケットにスルっと入らない。

自宅に帰るとWifiでは使える3GSと4SとiPadを枕元で充電している。寝る前とか夜中に起きたときとか朝起きたときには、だいたい3GSを手に取り、twitterを見る。今はtwitterがあればほとんどほかには何もいらない。そもそもiPhone 3GSを買ったのもtwitter端末として買ったようなものだった。3GSの画質は確かに4GSにはっきりと劣るが、twitterの使用には全く問題ない。動作が遅いように感じるのも、ほんの少しだ。

3GSを使っていて4Sにしようかと迷っている人は、我慢すべし。

機種変すると、iPhoneが一個余ってしまいます。iPhoneはこれ以上進化のしようがないんじゃないだろうかと思わせる。だが、きっと10年も経てば、『こんなにゴツかったのか』と思うようになるんだろうな・・・

2011/12/03

ルータにシリアルポート経由アクセスするperlスクリプト

perlを使ってルータの設定をするのはよくやっていたが、全部telnetで、シリアルポートを使ったことがないのに気付いた。
Win32::SerialPort
を使う。

ppm install Win32::SerialPort
をやって、以下、サンプル。

use strict;
use Win32::SerialPort;

my $ob = new Win32::SerialPort('COM1') || die;

$ob->user_msg(1);
$ob->error_msg(1);

$ob->baudrate(9600);
$ob->parity("none");
$ob->parity_enable(1);
$ob->databits(8);
$ob->stopbits(1);
$ob->handshake('rts');

$ob->write_settings;

$ob->write("\n");
sleep 1;
my $result = $ob->input;
print $result;


$ob->write("en\n");
sleep 1;
my $result = $ob->input;
print $result;

$ob->write("enable\n");
sleep 1;
my $result = $ob->input;
print $result;


$ob->write("conf t\n");
sleep 1;
my $result = $ob->input;

print $result;

$ob->write("hostname donguri\n");
sleep 1;
$result = $ob->input;
print $result;

$ob->write("end\n");
sleep 1;
$result = $ob->input;
print $result;

$ob->write("reset\n");
sleep 1;
$result = $ob->input;
print $result;

$ob->write("y\n");

undef $ob;


sleepして結果を表示しているところはダサいですね。 ここはteratermの waitのようにしたいところですが、そのやり方は後で調べる。 とりあえずserialポートで入出力ができるというサンプルです。

プロンプト待ちバージョン。
use strict;
use Win32::SerialPort;
use Time::HiRes;

my $ob = new Win32::SerialPort('COM1') || die;

$ob->user_msg(1);
$ob->error_msg(1);

$ob->baudrate(9600);
$ob->parity("none");
$ob->parity_enable(1);
$ob->databits(8);
$ob->stopbits(1);
$ob->handshake('rts');

$ob->write_settings;

$ob->are_match('>','#','word:');
$ob->lookclear;

&waitfor("\n",">");
&waitfor("en\n","word:");
&waitfor("enable\n","#");
&waitfor("conf t\n","#");
&waitfor("hostname otanko\n","#");
&waitfor("end\n","#");
&waitfor("reset\n",'(y/n)');

$ob->write("y\n");

undef $ob;

sub waitfor{
    my($output_string,$prompt_to_wait)=@_;
    my $gotit = "";

    $ob->are_match($prompt_to_wait);
    $ob->write($output_string);

    until ("" ne $gotit) {
        $gotit = $ob->lookfor;
        die "aborted\n" unless (defined $gotit);
        sleep 0.1;
    }

    my ($match, $after) = $ob->lastlook;
    printf "%s%s",$gotit,$match;

}


$ob->are_match("hoge1", "hoge2", ...)


という風にして、特定の文字列を待つことができる。複数指定できる。 waitfor というサブルーチンを作って、入力するコマンドと、期待するプロンプトを指定して実行する。

$ob->lookfor で、are_matchで指定した文字列が来るのを待つ。

sleepは1秒未満で待ちたいので Time::HiRes を使う。

$ob->lastlook で、マッチした文字列を取得できる。 この例では are_matchを1個しかしていないので確認する必要はないが、 複数していした場合はどの文字列にマッチしたのかを知ることができる。 これでだいぶ使えるでしょう。 あとは、期待したプロンプトが帰ってこなかったときにタイムアウトするようにすれば完璧。

2011/12/01

refererによる文字コードの違い

検索エンジン経由で来たアクセスについては、検索語を即時ツイートするようにしているのだが、EZから来たものだけツイートされない。 それは、ツイートする前にしていた以下の処理が原因だった。

$unescaped = Encode::decode('utf8', $unescaped);


無条件にutf8でデコードしていたのだがEZはshif-tjisを使っている。 というわけでEZのときだけshift-jisでデコードし、それ以外はutf8でデコードするようにした。

ちなみにrefererによる動作を確認するには以下のようなスクリプトを使う。

use LWP::UserAgent;
use strict;
use warnings;

my $url = "http://sample.com/cgi-bin/test.cgi";
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(GET => "$url");

$req->referer("http://ezsch.ezweb.ne.jp/search/?sr=0101&query=aiueo%20%95a%93I");
my $res = $ua->request($req);
if($res->is_success){
    print $res->content;
}else{
    print $res->status_line;
}


bing, yahoo, googleはブラウザから検索すればいいのだがauの携帯がないのでEZの場合はこれを使った。 そこで気付いたのだがezschのquery文字列は短い。これがshift-jisのメリットか。

$req->referer に設定しているのは、実際にアクセスがあったログのHTTP_REFERERである。

2011/11/23

iPad2

来年1月にはiPad3が出るかという時期に今さらなレポートかもしれないが、「iPadって、どうなの?何に使うの?いるの?」という人はまだまだ多いのではないだろうか。そういう人の為に、買って1ヶ月たった私がレポートしましょう。

結論から言いましょう。iPadは不要。もし、パソコンの代わりだとか、インターネットの利用などにiPadを使おうと考えているなら、やめた方がいい。

iPadは、大きいiPhoneです。これは欠点でもあり利点でもある。私もiPhoneを使っていて『もうちょっと画面が大きかったらな・・・』と思うことが何度かあった。iPadが出たのはもう2年くらい前で話題になって私も欲しいとは思ったが、主に金銭的な理由で買うのを控えていた。しかしiPhone4Sの発売にともなってソフトバンクが実施したキャンペーンがきっかけで買うことを決意した。まず、画質があまりよくないのにがっかりした。店頭でデモ品が置いてあるのは何度も触っていたのだが、自分の物となって自室でじっくりみるのでは違う。また、せっかくの大画面(iPhoneと比べて)なのに、アプリやWEBサイトがその大きさを生かしきれておらず、逆にもてあましてしまっている。

twitterなんかは、iPhoneのほうが全然使いやすくて読み書きもしやすい。アプリや電子書籍も、iPadへの対応はまだ遅れていて充実していない。価格も高い。電子書籍は紙の本とほとんど値段が変わらないし、品揃えも少ないし、思ったより視認性というか、新聞などでページ全体を見渡せる感じが弱い。画面の大きさにくらべて解像度がそれほどではない感じがする。アプリは動かなくなったり突然落ちるなど異常終了するのがiPhoneより多いように感じる。そしてこれほどの画面の大きさであれば2つのアプリくらいは並べたくなるがそれはできない。

今のところiPadでいいなと思ったのはGarageBandのピアノくらいである。GarageBandはiPhoneにもアプリがあるが、iPhoneでピアノを弾くのはキツい。iPadなら、そこそこの演奏ができる。WEBや電子書籍の閲覧にはいいかなと思ったが、これもイマイチだ。まず、重い。

初代を店頭で持ってみて重いなと感じていたのが2では軽量化されたことも購入のきっかけになったのだが、それでもまだ重い。夜中に目覚めた時とかに枕元にあるiPhoneを見ることはよくあるが、ねっころがって片手でiPadを見るのはしんどい。仰向けになって両手で持つか、うつぶせになって下に置かないとダメだ。だから寝床にいるときはiPadは見ない。

入力に関しては、iPhoneとほとんど変わらない。入力のしやすさを数値で表すと、PCが10点とすると携帯電話は2点、iPhoneは5点でiPadは6点くらい。ブログを書くくらいできるかなと思ったがやっぱり物理的なキーボードでないとだめだ。タッチパッドというのは、やっぱり携帯する小型端末だからこその妥協案であって、座ってじっくり大きな画面で使用するならキーボードやマウスの方がまだまだインタフェースとしては優れている。

というわけで必要かどうかということで言えば、iPadは不要です。パソコンとiPhoneを持っている人には不要でしょう。ただ、いろいろと可能性を感じるデバイスではあります。アプリで遊んだり、これを使って何ができるかを検討してみたい、というような人なら買ってもいいと思います。私も買ったことを後悔はしてません。

2011/11/15

ezsch

アクセスログにデコードされていない文字列が。UAを見ると、"ezsch"とあった。 解析スクリプトの検索エンジンごとの処理に"ezsch"を追加する。 が、デコード結果が化ける。文字コードが違うのだろう・・・。 なんの文字コードなのかが判断できないので検索するとshift-jisらしい。
uri_unescapeの前にshiftjisでdecodeする。まだダメだ。 後か。 uri_unescapeした文字列をもう一回shift-jisでデコード。 できた。

しかし、やっていることはほとんど同じで、サーチエンジンによる違いというのは

  • UAに含まれる検索エンジン名

  • 検索文字列の前につく文字列(p= とか、 q= とか)

  • uri_unescapeの後にさらにデコードが必要な場合それをやる

なので、本当はこれらを引数にしてサブルーチン化すればよいのである。

2011/11/09

pre

またスタイルの話であるが、preを使っていると、iPhoneで表示が崩れる。

preにはソースを書くので1行の文字数がどうしても長くなる。 するとなぜかほかの部分の文字が大きくなってしまう。 preの幅にあわせて小さくなるならわかるのだが・・・ どうしよう・・・

2011/11/03

%25

google検索文字列のエンコードが、下記のように%のあとが4桁になっている場合がある。これをそのままデコードすると、25だけが取れる。読めるようにするにはこれをもう一度でコードしなければならない。

%25E5%25A4%25A7%25E6%25B1%259F%25E6%2588%25B8%25E7%25B7...


検索すると、「%25がついている場合は25を消す」という人がいたので私もマネした。

$string =~ s/%25([a-fA-F0-9][a-fA-F0-9])/%$1/g;


[]を2回繰り返す時の書き方がわからないので続けて書いた。

2011/10/29

IPアドレスから国を判別する

ヘンなアクセスをしてくるIPはムカつくからiptablesでブロックしている。 whoisで、どこの国かなどを見る。 基本的に日本人以外には有用なものはないから、日本以外を全部遮断してもいいんだけど、それじゃ中国のGreatFWだもんね。
ftp.apnic.net/stats/apnic/delegated-apnic-latest


ちなみにここを見ると、どの国にどのIPアドレスが割り当てられているかはわかるようである。 日本以外をブロックするとかができるわけだ。 でも、インターネットに情報をさらしておきながら国内にアクセスを限るってのもどうかと思う。 あとIPアドレスが海外のものでも、日本人が海外の会社でサーバを借りたとか、 海外勤務の日本人が、とか、そういう場合もあるからやっぱりアドレスを管理しているISPの国を見てもあまり意味はないかもしれない。

2011/10/28

画像アップローダの作成

画像アップローダーを作ろう。 そういうサイトはたくさんあるけど、なかなか私の使いたいものがない。 以前使っていたサイトがあって、それがとてもよかった。 まず、画像はすべてサムネイルが表示される。 サムネイルといっても、結構大きめで、それで十分楽しめるくらいの大きさである。 PCの1画面で、3、4列くらいかな。 背景は黒。各画像の下には短いコメントが表示される。 多くの場合は何もないか、ごく短い。 投稿者だけでなく閲覧者もコメントをつけられるが、そのコメントはサムネイル表示時には表示されない。

画像の表示はglobでいいかな。 まずglobで画像を表示させてみると、大きさがまちまちになる。

これをプレビュー画面では同じ大きさに統一したい。 Windowsのexplorerとかpicasaとかのように。 さて、どうやるか。 ちょっと調べるといろいろ出てくる。 いつもはとりあえずなんでもいいから動くものに食いついてきたけど、 今回はどんな方法があるのかを調べて吟味してから使おう。

Image::Magick

GD

ImgResize

画像のサムネイルを作成する。

#!/usr/bin/perl
use strict;
use Image::Magick;

print "Content-type: text/html\n";
print "\n";
my @files = glob "./images/*.png ./images/*.jpg";
foreach (@files){
&MakeThumbnails($_);
}

print '<table border="0" cellspacing="3" cellpadding="3" width=80%><tr>';
my @files = glob "./thumbnails/*.png ./thumbnails/*.jpg";
my $count =0;

foreach (@files){
if($count % 5 <1){
print "</tr><tr>";
}
print "<td><img src=\"";
print $_;
print "\"></td>";
$count++;
}

print '</tr></table>';

sub MakeThumbnails{
my ($name) = @_;
my $dir = './thumbnails';
(my $newname = $name) =~ s/\/images/\/thumbnails/;
my $img = Image::Magick->new;
my $x;
$x = $img->Read($name);
$x = $img->Resize(geometry=>"200x150");
$x = $img->Write($newname);
}


サムネイルの作成と表示を同時に実施している。 表示(リロード)するたびにサムネイルを上書きするのはムダかもしれない。 枚数が増えてくると重くなるから、ページを分けたりする必要もあるだろう。 サムネイルをクリックしたら元画像を表示するとか、コメントをつけたり削除したりできれば、 表示部分はOK。

あとは、アップロード部分か。

perlでimagemagickを使いたくて、cpanでインストールしたらエラーになった。

調べると、yumでいれればうまくいくとのこと。

yum install ImageMagick-perl


なんで・・?

2011/10/26

セッション管理

yahoo, google, twitter, amazon... 今はどこのサイトもログインしてそのユーザ専用ページが表示されるようになっている。 前からこの仕組みをやってみたいと思っていた。 idとパスワードを入力させて、それをデータベースで参照して正しければ認証する。 実際は暗号化したり、SQLとかを使っているのだろうが、 原理だけを確認するなら、その辺は平文でテキストファイルでよい。

テキストボックス2つとボタンを作って、postさせれば認証機能は実現できる。 しかし問題はその先である。 単純に考えるなら、



  1. OKなら ok.htmlを表示し、NGなら ng.htmlを表示する。

  2. OKなら"ok"を、NGなら"ng"を引数としてauth.cgiを呼び、引数に応じて「ようこそ」「認証できません」などと表示する。

しかし問題なのは、認証の可否をどこかに維持しておかなければならないということだ。 それを「セッション管理」といって、perlにも CGI:Session というモジュールがある。 それを使えばいいのだろうが、複雑で、mySQLなどもからんでいてメンドクサイ。 もっと単純にできないだろうか? IPアドレスで管理するのはどうだろうか? いったんIDとパスワードを認証したら、そのときのuserのIPアドレスと、認証がOKであることを、ファイルに記録しておく。 サイトでは常にそのファイルを参照するようにして、認証されているかどうかに応じてページの表示を変える。 多分、「セッション管理」とか言うのも、同じようなことをしているはずだ。あとはポート番号を見たり、認証した時間を記録しておいて一定時間がたったらタイムアウトさせるとか・・・ でもあれか、natしてたりしたらIPアドレスで管理したら全部同じになっちゃうな。 セッションIDというのはHTTPプロトコルの仕組みで、それをサーバとクライアント(ブラウザ)で保持するようだ。だが、パケットキャプチャしても"session id"みたいなフィールドが見つからない。

セッション管理というのは、ステートレスであるHTTPプロトコルで状態管理をさせるための苦肉の策のようだ。セッションIDを生成して、それをクッキーを使ってクライアントに渡す。

#!/usr/bin/perl

use CGI;
use CGI::Session;

my $cgi = CGI->new;
my $session = CGI::Session->new(undef, $cgi, {Directory=>'./tmp'});
session->param('name','mysession');

print $session->header(-charset=>'UTF-8');

print   $cgi->start_html(-lang=>'ja', -encoding=>'UTF-8', -title=>'http session test'),
$cgi->p('session id: '.$session->id.'<br/>',
'name: '.$session->param('name').'<br/>'),
$cgi->end_html;


とりあえずこのようなcgiを作って実行すると、session idが表示される。F5を押すたびにidは変わる。パケットキャプチャしてみると

Set-Cookie: CGISESSID=5d6b6c1c3248aa9b399060dcef4c4e58; path=/


のように、セッションIDがサーバからクライアントに返す HTTP OKのパケットの中に入っているのがわかる。・・・・・・で?

まずはcookieからだな。 cookieというのは、サーバ側から送信するもので、ユーザが閲覧するとユーザがcookieを無効にしていない限り勝手に保存される。 cookieには名前、値、ドメイン名、パスなどが設定できる。 ユーザが保存しているcookieは、環境変数

$ENV{'HTTP_COOKIE'}


で取得できる。 たとえば「名前」=「アクセス日時」というcookieを送信しておけば、次のアクセス時に「前回のアクセスは何月何日でした」などと表示できる。

amazon.co.jpにアクセスしたら、6個のcookieが保存された。

at-acbjp
session-id
session-id-time
session-token
ubid-acbjp
x-acbjp


値を見てもなんのことやらさっぱりわからないが、 サインインしたときにアカウントと関連付けて保存しておけば、どのアカウントかわかる。 どのサイトでも「ログインしたままにする」などのチェックボックスがついているが、 それをチェックしたときはcookieを見てアカウントの認証プロセスを飛ばすのだろう。 と、こう見てくるとperlの CGI::Session モジュールがやってることはたいしたことがないように思えてきた。 ただidを発行してcookieにセットしてるだけじゃないのか?




パソコンに写真がたくさん溜まってきて、特に見ないのだが捨てるのももったいなくてとってある。 これをwebに置くことにした。 いろいろあるけど、picasaのwebアルバムに落ち着いた。 いったん上げてしまうと、フォルダの階層が作れなかったり、削除や移動が一度にできなかったりとメンドクサイが、大量ファイル操作は一度ダウンロードして操作してアップロードするなどしている。それにしても重複ファイルの多いこと・・・メニューの「整理」を選ぶと、複数選択して削除や移動ができる。天下のgoogleがそんなことくらいできないわけないよな・・・

2011/10/25

sphinx

また新しいアドレスから sshアタックが来ていたので、iptablesに追加した。 しかしこれはイタチごっこになりそうだ。 と、誤って自分のアドレスをフィルタしてしまい、sshが固まった。 ヤバい・・・と、リモートコンソールがあることを思い出した。 しかし、なぜかアクセスできない。 と、「VNCコンソール」というものがあるのに気付いた。 よくわからないがこれだとアクセスできたのでiptablesの設定を直す・・・

denyhosts というソフトがあって一定の回数のアクセス失敗があると自動的に hosts.denyに追加してくれるものがあることを知り動かしてみたが、自分のアドレスが登録されてしまった。 過去のアクセス状況を見ているのだろうか。 それと、登録がホスト単位であること、拒否するのがsshdであることが気に食わない。 やっぱりiptablesでブロックごとドカンと跳ね除けることにした。

wikiを作ろうと思ったがsphinxというpythonでできたおもしろそうなのがあったので、 これを使ってみる。

yum install python-pip python-setuptools


をやってから、

pip-python install sphinx


をやる。 これだけでいいはずなのだが、インストール中にSyntaxErrorが出る。 最後は Successfully installed となっているので、

sphinx-quickstart


をやってみるが SyntaxError: invalid syntaxで動かない。 pythonのバージョンが古いのかと思ってupdateしてやり直したがダメ。 とりあえず、見送り。しょうがないからpukiwikiにする。 ダウンロードして解凍するだけ。 ちなみにPCにダウンロードしてFTPでアップロードした。 WEBにあるファイルをコマンドでダウンロードするにはどうすればいいのか? lynxを入れる?

sshdへの不正アクセスに悩んでいる人は多いようだが、私のように一人しか使ってないのなら、 もうsshdは止めておいて、使う時だけコンソールから入って起動したらいいんじゃないかな。もっというと全部リモートコンソールでやってしまってもいい。 とりあえずsshdできるユーザを制限。基本的にアクセス制限はデーモン単位でなくiptablesで出禁にする。・・・と、ムキになってアクセス制限をしてみたものの、 別にパスワードが割られたわけでもなし、 運用不能になるほど負荷があがったわけでもなし・・・。 止めてしまうよりもログを集めて分析したほうが面白いんじゃないかと思えてきた。

2011/10/24

587

自宅のPCでVPSのサーバにPOP3アクセスしてメールを受信することはできているが、送信できないことに気付いた。 VPSとはいえ自分で管理するサーバを持ったときに一番注意しなければならないのは不正アクセスである。 特にSPAMの踏み台になることは絶対に避けねばならない。 だから、少なくとも誰も彼もが私のVPSサーバにSMTPアクセスできるようになっていないことは確認できた。しかし自分のPCからはアクセスしたいので、いろいろ設定しているのだがどうもうまくいかない。

そのうち、/var/log/secure に大量の不審なアクセスのログが記録されているのに気付いた。 1秒おきにユーザ名を変えてsshアクセスしているログだ。アクセス元のアドレスは数個しかなかったのでwhoisでしらべてそれらを含むブロックをrejectした。 アドレスは中国、台湾、アメリカ、タイとバラバラである。 おそらく踏み台にされているのだろう。また、アクセスの仕方が非常に乱暴なのでごく単純なスクリプトを、興味本位で試しているようなものかもしれない。

whoisといえばいつもブラウザでANSIのwhoisを使っていたが、まてよと思ってcentosのコマンドでやってみたら検索できた。

どうしてもSMTPアクセスできない。 telnet 25 もできない。 PCでキャプチャしたら synを送ったきり応答がない。 サーバ側でtcpdumpしても何もこない。 ポートが開いていないのか、と、iptablesを見ると開いている。 でも、やっぱり25が開いていないとしか思えない、googleで探すとVPSの試用期間は25番が開かない、とある、 もしかして試用期間が終わったのに設定が解除されていないのか・・・?と思う。 nmapでスキャンしてみたら、やっぱり25は開いていなかった・・・

「さくら VPS sendmail 25 」などで検索してみると、どうやら「試用期間がすぎても25番が開かない」ということがあるようだ。 再起動したら直った、再起動してもダメだからポート番号変えた、などの情報があった。 再起動は何度かしたけどもう一辺やってみる・・・ダメ。 ポートを587に変える。 以前コメントにした DAEMON_OPTIONSで使用ポートを変更できる。 Addr=127.0.0.1 は削る。

DAEMON_OPTIONS(`Port=587,Name=MTA')dnl


iptables で 587をあけてiptablesをrestart。m4をやって、sendmailをrestartする。

送信できた・・・

この野郎~ッ!

しかしお陰様で sendmailやiptablesやnmapの使い方を勉強できたよ。

javamail入門

javamail入門という面白そうな本があったので、ちょっとやってみる。 javamailとかJAFとかを入れてみるがちゃんと動かない。 いつ入れたのか定かでないSDKを消して、入れなおす。
www.oracle.com/technetwork/java/javase/downloads/jdk-7u1-download-513651.html

インストーラが起動する。 デフォルトではデモをインストールしないようになっているが、インストールする。 インストール後、ユーザー登録画面が出てくる。 ついでなので登録しておく。

pathの登録が必要。

F:\Program Files\Java\jdk1.7.0_01\bin


言い忘れたけど Windows XPです。 昔書いたhello,world的なサンプルをコンパイルしてみる。

エラーになる。 ファイル名とクラス名が同じでないといけないのを思い出して、ちゃんと同じになっているものをコンパイルして動くことを確認する。

javamailは解凍したフォルダを program files\java に移しておき、 環境変数を登録する。 CLASSPATHのところに、mail.jarのフルパスを書く。

F:\Program Files\Java¥javamail-1.4.4\mail.jar;


ファイル名まで書かなければならない。 ということはjarを入れるたびに常にclasspathを書き換える必要があるのか?メンドクサイ・・・ と思うがそれはおいておく。

demoの msgshow.javaをコンパイルする。 classpathがうまく登録されていなかったり反映していないと、エラーが大量に出る。

ちなみに、WindowsXPの環境変数の変更は、 Program Files のように間にスペースがあっても""で囲んだりする必要はない。 コマンドプロンプトを起動していた場合は、そのままでは反映しない。(setをやってみるとわかる)。 コマンドプロンプトをいったん閉じて起動し直すと反映する。ログオフや再起動の必要はない。

実行してみた。

F:\Program Files\Java\javamail-1.4.4\demo>java msgshow -T pop3 -H example.com -U hoge -P xxxxxxx
--------------------------
MESSAGE #1:
This is the message envelope
---------------------------
FROM: John Lennon <john@example.com>
REPLY TO: John Lennon <john@example.com>
TO: hoge@example.com
SUBJECT: test
SendDate: Mon Oct 24 16:10:05 JST 2011
FLAGS:
X-Mailer NOT available

F:\Program Files\Java\javamail-1.4.4\demo>


感動。

じゃあ送信をやってみようと思ったら、うまくいかない。サーバはさくらのVPSを使っていたのだが、25番ポートがどうしても開かなかった。しかたがないので587番に変えた。ところがデモは25番を使っていて、ポートの指定はできなかった。さっそく改変の必要が生じた。しかしこんなのは簡単で、argvを格納しているところに新しい引数と変数を作り、

if (port != null)
props.put("mail.smtp.port", port);


とするだけでOKだった。ちなみにいじったのは msgsend.java である。

apple礼賛

appleは衰退するなどという無責任なことを書いた後にすぐ、appleを絶賛する人を見かけた(もちろんウェブで)。そしてあらためて感じたのは、appleが好きな人のapple礼賛ぶりの熱烈さである。でも、パソコンとかミュージックプレイヤーなどというものは料理で言えば皿などの器のようなものである。食事をご馳走になった後に、ひたすら「このお皿はいいですねえ。料理が引き立ちますねぇ、この模様がすばらしいですねぇ・・・、このナイフの切れ味とフォークの刺し易さには驚嘆します」などと料理について何もいわずに食器ばかりほめたら料理を作った人はガッカリするだろう。

わたしだって電球を発明したエジソンの業績はすばらしいと思う。蓄音機も、CDも、MDも、MP3も、インターネットも、FAXも、メールも、みんなすばらしい技術である。でも、appleを礼賛する人は、ブログを書いても音楽を聴いてもゲームをしても何をしても、「Macはいいな」「appleはいいな」と言っているような印象がある。それだけならいいが、たいていWindows否定がデザートのように追加される。

先ほど書いた閉鎖性ということについても、要するにナルシシズムであって、ハードウェアからソフトウェアそしてついにはコンテンツ売買までもappleで独占して悦にいっているのである。愛好者にしてみればこんなに気持ちのよいことはないであろう。しかし、そんなものは独裁者の築いた孤立した楽園のようなものである。そういう楽園を築き維持するためにはたいてい多数の犠牲者が存在しているものである。

2011/10/23

閉鎖的なappleは衰退する

iPhoneを使ってとても感激して、まるでペットのように肌身離さずという感じで愛用しているのだが、私はappleの繁栄はあまり長くは続かないと思う。理由は、appleが閉鎖的だからである。

好きな音楽や映画を聴いたり見たりしたくなったときに、iTunes Storeで探すとその品揃えの薄さにはいつもあきれる。iPhoneのアプリを作ってみたいと思っても、Mac OSが必要である。iPad2を買って、電子書籍も見てみたが、こちらも品揃えは薄く価格も高い。androidを始め、すでに類似品や模倣品がたくさん作られている。今はデバイスそのものしかマネされていないが、そのうちiTunesのようなシステムもマネされ始めるだろう。Macには「普通はイヤだ」という発想が見られる。「PCやWindowsはダサい」と、Mac以外のモノを露骨にバカにする態度を取る。それはユーザーにさえ見られることである。私が若い頃はMacintoshなんてとても買えたものではなかった。平気で100万円とかしていたのだ。そういう価格設定も、ビジネス上の戦略というよりは頑固な選良意識のようなものだと思う。デザインの美しさと、直感で操作できるUIはすばらしい。PCにつないでバックアップをとったりインターネットで音楽等を購入してすぐiPodで聴ける仕組みもすばらしい。だが、閉鎖的である。このままでは先がないと思う。多少みてくれがダサくても、UIが操作しづらくても、豊富なソフトが低価格で利用できるならそっちを選ぶ。

2011/10/21

sendmail

レンタルサーバから移行した。 いろいろメンドクサイのでおぼえがきを記す。レンタルサーバで動いていたcgiがinternal server errorになることがある。 /etc/httpd/logs/error_log を見ると、
Premature end of script headers
と書いてある。 改行コードがCRLFになっているとこうなるそうだ。 改行コードを確認するには、
od -c test.cgi
とやると、改行コードが\nとか\r\nとか表示される。 \r\nになっていた場合は、以下のようにして変換する。
$ tr -d \\r <windows.txt >unix.txt
sendmail
こいつがメンドクサイ。まず、みんなが当たり前のようにやっているが前提として理解しておく必要のあること。sendmailの設定ファイルは sendmail.cf というテキストファイルである。この設定ファイルはムズカシイことで有名で、私も以前ちょっと調べてみたことがあるがさっぱりわからなかった。最近は、sendmail.mc という設定ファイルの設定ファイルみたいなものができて、それをm4 というコマンドを以下のように使って sendmail.cfに変換してくれるようになったようだ。
m4 /etc/mail/sendmail.mc > /etc/mail/sendmail.cf
sendmail.mc なら、なんとなく何をしているのかが想像がつく。そして sendmail.mcだが、コメントの書き方がちょっと変わっていて、行頭に dnl と書く。行末にもdnlがついているところがあるが、これはあってもなくてもいいようだ。
dnl #
dnl DAEMON_OPTIONS(`Port=smtp,Addr=127.0.0.1, Name=MTA')dnl
dnl #

dnl #
dnl # Also accept email sent to "localhost.localdomain" as local email.
dnl #
LOCAL_DOMAIN(`hoge.net')dnl
dnl #
今例示した下記の設定は、メール転送をローカルに限るという設定なので、外部からのメールを受信する場合はコメントアウトする。
DAEMON_OPTIONS(`Port=smtp,Addr=127.0.0.1, Name=MTA')
さて、外部からのメールの受信であるが、実はまだうまくいっていない。いろんなアカウントを作るときにメールアドレスが必要になることがあり、VPSを持っていれば実質無制限にアカウントを作れるのだが、メールが受信できなきゃしょうがないな・・・
[root@wwwXXXXXu ~]# sendmail -d0.1 -bt < /dev/null
Version 8.13.8
Compiled with: DNSMAP HESIOD HES_GETMAILHOST LDAPMAP LOG MAP_REGEX
MATCHGECOS MILTER MIME7TO8 MIME8TO7 NAMED_BIND NETINET NETINET6
NETUNIX NEWDB NIS PIPELINING SASLv2 SCANF SOCKETMAP STARTTLS
TCPWRAPPERS USERDB USE_LDAP_INIT

============ SYSTEM IDENTITY (after readcf) ============
(short domain name) $w = wwwXXXXXu
(canonical domain name) $j = wwwXXXXXu.sakura.ne.jp
(subdomain name) $m = sakura.ne.jp
(node name) $k = wwwXXXXXu.sakura.ne.jp
========================================================

ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
Enter <ruleset> <address>
多分これが原因じゃないかと思う。wwwXXXXXu というのはVPSサーバに与えられるfqdnで、これを変えて使っている。sendmail.mc にドメイン名を設定したのだが、このコマンドに反映しない。このコマンドのオプションの意味はよくわからない。後で調べる。
gmailからVPSのアカウントにメールを送ると、/var/log/maillog に以下のようなログがあるので、サーバには届いているようである。
Oct 21 17:32:58 wwwXXXXXu sendmail[9748]: p9L8WtBO009748: from=<hoge@gmail.com>, size=1182, class=0, nrcpts=1, msgid=xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxx-cueQtTA@mail.gmail.com>, proto=ESMTP, daemon=MTA, relay=mail-bw0-f50.google.com [209.85.214.50]
Oct 21 17:32:58 wwwXXXXXu sendmail[9749]: p9L8WtBO009748: to=<hoge@example.com>, delay=00:00:00, xdelay=00:00:00, mailer=local, pri=314
56, dsn=2.0.0, stat=Sent
これは、ホスト名を逆引きして表示しているようである。 WEBブラウザで操作する「VPSのコントロールパネル」でホスト名を変更したら反映した。 このときに正引き登録が必要なので、新しくホスト名を付けた。 普段はホスト名なしでアクセスしていたのだが多分、名前は必要なんだよね? ついでに、 /etc/hosts, /etc/sysconfig/network にも設定する。 いらなかったかな? 再起動したら、コマンドプロンプトも変わった。
メールも来てた! めでたしめでたし。
rootじゃない、後から作ったアカウントでログインするのだが、そのアカウントではlsすらできない。いつもsu - をやってrootで操作していたのだがメンドクサイので、自分のアカウントの所属グループを変えることにした。 wheelにすればいいのだろうと思っていたがすでにwheelになっていた。 wheelではlsもできないのか・・・ rootのグループを見ると、admとか sysとかたくさんのグループに所属している。 rootと全く同じにする必要はないから、とりあえず admとかに入れてみたがダメだ。 そして気付いた、groupaddではひとつのグループにしか登録できないことを。 調べると vigr というコマンドがあって、これを使えばグループの設定ファイルを編集できる。 しかるべきグループに追加し、晴れて ls が実行可能となった。
所属グループの確認: id
一つのグループに所属させる場合の変更: usermod -G wheel hoge
グループ設定ファイル編集: vigr
何をしたかったかというと、アクセスログから検索語を探して表示しているcgiがあるのだが、件数がそんなにないので、見つかった時点でtweetするようにしようと思った。 すでに一つbotは稼動していて、試験的な運用なのでそれで試してもいいのだがせっかくなので新しいアカウントを取って新しいbotを作ろうと思います。
あれーまた受信できなくなった。 グループ変えたせいか?
・・・できた。ようわからん。
mail -u hoge
でhogeのメールを見る。
echo test|mail root
でrootに"test"という文字列を送る。
さて、メールが受信できるようになった。 しかし、日本語はエンコードされている。 デコードしなきゃ。 どうやるんだろう? perlでちょいちょいとやればできそうなのだが、よくわからない。情報もない。 しょうがないからpop3で受信する。 dovecotをインストール。
yum install dovecot
設定ファイルは特にいじらずに起動する。
service dovecot start
outlook expressで受信してみるがダメ。 telnet xxxx 110 でも入れない。 ping xxxx はいける。
service dovecot status
を見てみたら停止していた。 /var/log/maillog を見ると、
Oct 21 22:27:43 tal dovecot: auth(default): Unknown authentication mechanism 'dram-md5'
とあるので、設定ファイル /etc/dovecot.conf で dram-md5 と書いてあるところを探して、消して、再起動。 受信できた。こっちは簡単。 というか、sendmailもたいしたことはなかった。 でも、dnsとかiptablesとか、ある程度知ってないとワケがわからないかも。

2011/10/17

iPad2を買った

Softbankのキャンペーンが決定打となった。要は3GモデルをWifiで使えばいいのである。WifiモデルにはGPS機能がない。購入手続きの途中でシステム障害が起きて、一旦帰宅して昼寝をし、目覚めたらちょうど電話が鳴って復旧の連絡が入った。特にiPadでなければできないことがあるわけでも、したいことがあるわけでもなかった。PCにつないでiOS5のインストールをしたら林檎マークが表示されて進まない。ときどきピヒョ!というあのUSBでつないだ時の音がするがすぐに林檎マークになる。同期か何かしているのだろうとしばらく待っていたが様子がおかしいので強制終了したら、復元が必要になった。復元が終わり、Twitterなど必須アプリを入れる。iPhoneを使い始めた時は驚きと感動の連続だったが、それほどの衝撃はない。まあ、大きなiPhoneのようなものだから当然だが。

いらなかったかな....と思い始めたがebiReaderを入れて、iPadの用途が見えた。電子書籍リーダーである。これが主要な用途となるだろう。まだコンテンツが少ないようだがこれから増えていくだろう。

...以上、iPadのローマ字キーボードを打鍵して書いた。普通のキーボードの半分くらいの速度か。いくら慣れてもこれをブラインドタッチは無理だろう。外付けも面倒だし...見たり読んだりは問題ない。ただし、ずっと持っているにはまだ重く、寝転がったり座ったりしている時にどうやって固定するかが定まっていない。座っている時は膝にのせるのがいいかな。

2011/10/08

アクセスログ解析スクリプトの改善

アクセスログ解析スクリプト、改善した。
#! /usr/bin/perl

use strict;
use URI::Escape;
use Encode;
use DateTime;
use utf8;

my @line;
my @line2;
my @line3;
my $useragent;
my $unescaped;
my $print_level = 2;

sub print_selected{
    my ($date, $time, $host, $addr, $search_engine,
    $search_string,$useragent,$browser,$misc)=@_;

    print '<font face="georgia" size=-2><br></font>';
    print '<b>'.$search_string.'</b><br>';
    print '<font face="georgia" size=-2>';

    if($search_engine=~ /Google/){
        print ' <font color="navy"><b>'.$search_engine.'</b></font>';
    }elsif($search_engine=~ /Yahoo/){
        print ' <font color="red"><b>'.$search_engine.'</b></font>';
    }elsif($search_engine=~ /Baidu/){
        print ' <font color="orange"><b>'.$search_engine.'</b></font>';
    }else{
        print ' <font color="black"><b>'.$search_engine.'</b></font>';
    }
    $time =~ s/\[//g;
    print '<br><br></font>'."\n";
}

my $date = DateTime->now( time_zone => 'Asia/Tokyo' )->subtract(days=>1);
my $logfilename;

if($#ARGV >=0){
    my $test='cp ../../log/access_log_'.$ARGV[0].'.gz ../../log/tmp';
    system($test);

    $test='gunzip -f ../../log/tmp/*.gz';
    system($test);

    $test='mv ../../log/tmp/access_log_'.$ARGV[0].' ../../log/tmp/log.txt';
    system($test);

    $logfilename='../../log/tmp/log.txt';
}else{
    $logfilename='log.txt';
}

print "Content-type: text/html\n\n";
print "<html><head>\n";
print '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">';
print "<title>Searched Strings</title>\n";
print '
<style type="text/css">
<!--
BODY, TH, TD { font-family: "Osaka"; }
-->
</style>

'."\n";
print "</head>\n";

print "<body>\n";
#print "<a href=\"$logfilename\">$logfilename<\/a>  ";
#print "<br>print level:".$print_level."<br>";

print "<blockquote>\n";

open LOG,"<$logfilename" or die;

while(<LOG>){

    if(/googlebot\.com|Baiduspider/){
        if ($print_level > 1) {
            next;
        }
    }else{
        print "<br>";
    }

    print '<font face="georgia" size=-2>';
    print;
    print '</font>';

    @line=split;

    if(/.+(\(.+\))/){
        $useragent=$1;
    }

    if(/google/){
        @line2 = split /&q=|\?q=/, $_;
        @line3 = split /&/, $line2[1];

        $unescaped = uri_unescape($line3[0]);

        if($_ =~ /ie=SJIS/){
            $unescaped = Encode::decode('shiftjis',$unescaped);
        }

        $unescaped =~ s/\+/ /g;
        &print_selected(@line[0],@line[1],@line[2],@line[3],
        "Google",$unescaped,$useragent);

    }elsif(/yahoo.+search\?/){
        @line2 = split /p=/, $_;
        @line3 = split /&/, $line2[1];
        $unescaped = uri_unescape($line3[0]);
        $unescaped =~ s/\+/ /g;
        &print_selected(@line[0],@line[1],@line[2],@line[3],
        "Yahoo",$unescaped,$useragent);

    }elsif(/yahoofs.+search/){
        @line2 = split /p=/, $_;
        @line3 = split /&/, $line2[1];
        $unescaped = uri_unescape($line3[0]);
        $unescaped =~ s/\+/ /g;
        &print_selected(@line[0],@line[1],@line[2],@line[3],
        "Yahoofs",$unescaped,$useragent);

    }elsif(/baidu.jp\/s\?/){
        @line2 = split /wd=/, $_;
        @line3 = split /&/, $line2[1];
        $unescaped = uri_unescape($line3[0]);
        $unescaped =~ s/\+/ /g;
        &print_selected(@line[0],@line[1],@line[2],@line[3],
        "Baidu",$unescaped,$useragent);

    }elsif(/bing.+search/){
        @line2 = split /q=/, $_;
        @line3 = split /&/, $line2[1];
        $unescaped = uri_unescape($line3[0]);
        $unescaped =~ s/\+/ /g;
        &print_selected(@line[0],@line[1],@line[2],@line[3],
        "bing",$unescaped,$useragent);

    }elsif(/biglobe.+search/){
        @line2 = split /q=/, $_;
        @line3 = split /&/, $line2[1];
        $unescaped = uri_unescape($line3[0]);
        $unescaped =~ s/\+/ /g;
        &print_selected(@line[0],@line[1],@line[2],@line[3],
        "biglobe",$unescaped,$useragent);

    }elsif(/search\.goo\.ne\.jp/){
        @line2 = split /MT=/, $_;
        @line3 = split /&/, $line2[1];
        $unescaped = uri_unescape($line3[0]);
        Encode::from_to($unescaped, 'euc-jp','utf8');
        $unescaped =~ s/\+/ /g;
        &print_selected(@line[0],@line[1],@line[2],@line[3],
        "goo",$unescaped,$useragent);

    }else{
        print "<br>\n";
    }
}

close(LOG);

print "</blockquote></body></html>\n";
検索エンジンごとに個別にやっているところは、本当はまとめてしまいたいところなのだが、とりあえずはこれで。 これでもずいぶんすっきりした。

googleで、url(uri?)デコードしたした後に文字バケしたことがあった。 URLデコードのできるページで同じ文字列をデコードするとちゃんと表示される。shift-jisとかutf-8とかを判定してどのコードでも表示できるようにしているのだろう。どうやっているのかはわからない。 ログをよく見ると、

&ie=SJIS&oe=SJIS
というパラメータがついている。どういう場合にこうなるのかわからないが、あまりないので、この文字列があったら shift-jisをデコードするようにした。 最初は from_to で shiftjis から utf8 に変換したのだがなぜかうまくいかないので decode を使った。 Encodeの動作がイマイチよくわからない・・・

log解析スクリプトは、最新を上に表示したいので、print reverseを使ってログをひっくり返してから読むようにした。 そのときちょっとはまったのは、最初に

open FILE,">filename.txt";


とやって書き出すのはできるんだけど、その後にもういちどそこに書き込めないこと。 ファイルが開けない。 属性を書き換えていけたんだけど。 どうして一発目はかけるのに、その後はダメなんだろう?

perlのハナシじゃないんだけど、iPhoneでこのページを見ると字が小さすぎてしまう。useragentを見てページを作り分けるなんてことは面倒だしもっと簡単な方法があるだろうと調べた。以下のようにする。

print '<link href="../../css/bbz.css" type="text/css" rel="stylesheet">';
print '<link media="only screen and (max-device-width:480px)" href="/css/bbziphone.css" type="text/css" rel="stylesheet"/>';
print '<meta name="viewport" content="width=320, initial-scale=1.0, maximum-scale=1.0, user-scalable=no /">';


最初の行は、今まで書いてあった cssファイルを指定していたもの。その後の2行を足す。そして bbziphone.css に、iPhone用のスタイルを書く。とりあえずこれでできたけど、普通のと、iPhone用とほとんど同じで一部だけ違うっていうのが、ちょっとイヤだな。cssファイル内部でなんとかできないものかな?

2011/10/06

splitの区切り文字

splitの区切り文字は、複数の文字からなる単語でもよい。
@array = split /http/,$string;


こうすれば "http"の前後で文字列を分割できる。 何に使うかというとアクセスログの検索文字列の抽出である。 今は、まず ?で区切って、格納した配列を見て、また区切って、などとやっているのだが、 見逃しや余計な物がくっついてエンコードに失敗したりしている。 区切り文字は1文字でないとダメだと思い込んでいたのだ。

2011/08/30

642-813J SWITCHの準備

642-813J SWITCH
2008/3にBCMSNで取ったが3年過ぎてしまった。
黒本買ってきた。

<1章>キャンパスネットワーク設計

SONA (Service Oriented Network Architecture)

アプリケーション層
インタラクティブサービス層
ネットワークドインフラストラクチャ層

---

コア層では冗長化と高速コンバージェンスが必要


<2章 VLAN>

エンドツーエンドVLAN:企業LAN全体にわたり複数のスイッチを経由する広い範囲で構成されるVLAN
ローカルVLAN:狭い範囲に限定されたVLAN

DTP
AUTO-AUTO → access
AUTO-DESIRABLE → trunk
DESIRABLE-AUTO → trunk
DESIRABLE-DESIRABLE → trunk

allowed vlan 10,20 → 10と20を許可

allowed vlan 10
allowed vlan 20 → 20だけ許可(後の設定で上書き)


allowed vlan 10
allowed vlan add 20 → 10と20を許可


VTP Version: 2 であっても、VTP V2 ModeがDisableならV1で動作する

LACP 標準プロトコル
Pagp Cisco独自
(逆に書いていたが2012/2/4 気づいて修正した)


PAgp
Desirable/Auto

D-D → ○
D-A → ○
A-D → ○
A-A → ×


LACP
Active/Passive

A-A → ○
A-P → ○
P-A → ○
P-P → ×


簡単すぎる

ついこないだ18000円になったと思ってたら、24000円になったんだって?
受けるのやめようかな・・・

2011/07/29

TSHOOTの準備

Sat Oct 9 09:50:42 2010

ISCW(Implementing Secure Converged Wide Area Networks)はセキュリティ、IPsecとかファイアウォールとか。
ONT(Optimizing Converged Cisco Networks)はQoS、それに無線とVoIPが加わる。
ONTは黒本をやるところまで行ったのだが結局受験しなかった。
セキュリティやQoSというのは仕事でも触れる技術ではある。必要性は感じないことはない。
でも、これらは実感しにくいんだよね・・・。
ONTとISCWを黒本とかクラムメディアでとってしまおうかと思っていたが、せっかく買ったTSHOOTのガイドをパラパラ見ているとちょっとおもしろそうだ。単なるプロトコルの内容だけでなく、トラブルシュートの方法などが書いてある。これは受かるかどうかは別としてとりあえず読んでみる価値がありそうだ。取るだけなら年明けでもいいんだし。
とりあえず受けてみる。TSHOOT。468ページ。毎日読んでも一日10ページで47日。明日から始めたら12/12までかかる。
だがそれでやっと下準備が整ったにすぎない。間に実機確認をしたり、調べたりすることも必要。かなりのハードスケジュールである。
とりあえず全頁めくってみる。Trouble Ticket というのがある。構成図とshow commandの結果がある。トラブルのサンプルのようなものだ。これが全部で11個ある。これを全部読むだけでもおもしろそうだ。
security, voice, wirelessあたりが嫌だな。


Wed Nov 3 16:54:20 2010

chapter1を読み通した。ここはまだページ数も少なく序の口だが、思ったよりラクに読めた。これならいけるかもしれない。
dynamipsをVista32環境で復活させる。IISのFTPサーバを立てる。が、うまくアクセスできず、インターネット経由でFTPする。configを一定間隔でftpアップロードする archiveという設定を知る。


Fri Nov 5 04:27:23 2010

L3スイッチが必要だ。3550がだいぶ安くなった。EMIとSMIがある。パフォーマンスの問題だけなら安いほうでいいのだが、できることに違いがあるとなると困る。
SMIはRIPくらいしか動かず、EMIだとOSPFやBGPも使えるようだ。ルーティングはルータで、カタリストはL3スイッチとしての機能だけを見るようにすればよさそうだがどうせならEMIがいいな。

Tue Nov 9 21:51:13 2010

L3スイッチが我が家にやってきた!


Wed Dec 29 00:20:33 2010

ついにTCPに直面するときが来ました。SYN, ACK, FIN, セッション、なんのこっちゃ!!


Fri Jul 29 14:41:17 2011

複数台のcatalystをそれぞれvlanで区切って、その区切ったvlan同士をカスケードしてるんだけど、native vlanが一致しないというワーニングがうるさい。
native vlanってなんだっけ・・・と調べたがmode accessで使用している限りは関係ない。
きっとvlan idをあわせればメッセージは消えるだろうがメンドクサイ。
no cdp run
(この件については後日考察する)

2011/07/28

say

use 5.010;
say "hello";
sayという関数がversion5.10から追加されているそうだ。versionを確認したら5.14なので使ってみたらエラーになったので調べると、
use 5.010;
が必要とのことであった。sayは\nをつけなくても改行してくれる。

2011/07/27

おまじない?

sub logmsg{ print "$0 $$: @_ at ", scalar localtime, "\n" }
プログラミングPerlのSocketのサンプルにあった一行。

なんのおまじないか?と思った。

$0 はプログラム名、

$$ はプロセス番号(Windowsにもある)

@_ は引数(これは知ってた)

scalar localtime で時刻が人間に読める形式で表示できる。

2011/07/16

twitterのbot@さくらのVPS

さくらのVPSを借りた。 何がしたかったって、Net::Twitterをいれたかった。このためだけに借りたといっても過言ではない。 だが、多少の困難があった。インストールがすっといかなかった。

perl -MCPAN -e shell


とやると cpanのプロンプトになるので、

install Net::Twitter


とやればいいのだが、やたら長い上に最後にエラーになる。 ダラダラと出ているログは読んでられないのでまずサーチする。 失敗している人が散見され、いろいろ回避策が公開されていたがどれを試してもダメ。 結局、ログを見て、can't locate といわれているmoduleを片っ端から入れていった。 Math::Round とか。 あと、opensslのライブラリ(?)がないみたいなことを言われるので

yum install -y openssl-devel


をやった。

cpanのモジュールは依存関係にあるものを勝手にいれるんじゃなかったっけ? そんな親切なのはppm installだけなのか?

bot

use strict;
use warnings;
use utf8;
use Encode;
use Net::Twitter;

binmode STDOUT, ':utf8';

my $twit = Net::Twitter->new(
    traits => [qw/API::REST OAuth WrapError/],
    consumer_key    => 'YOUR_CONSUMER_KEY',
    consumer_secret => 'YOUR_CONSUMER_SECRET',
    ssl => 1,
);

$twit->access_token       ('YOUR_ACCESS_TOKEN');
$twit->access_token_secret('YOUR_ACCESS_TOKEN_SECRET');

while (1){
    my $line;
    open(my $file, "<tweets.txt");
    rand($.)<1 and $line = $_ while <$file>;
    close $file;
    my $decoded = Encode::decode('utf8', $line);
    $twit->update($decoded);

    sleep 3600;
}

exit;
テキストファイルからランダムに1行ずつ選んでツイートする、簡単なボット。 ちょっと手間取ったのは日本語の扱い。 tweets.txt は utf8で保存してあるのだが、なぜかそのまま Net::Twitterに渡すと文字化けする。 リテラルは化けない。 いろいろ調べて、utf8をいったんデコードして渡すという、ちょっと釈然としないやり方で解決。

2011/07/05

日報タイトル作成スクリプト

日報をメールで出すのだがタイトルは辞書登録して日付だけ書き換えていたのを日付取得してクリップボードにコピーするようにした。

use Win32::Clipboard;
my $clip = Win32::Clipboard();
($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime();
$m = $mon+1;
$text = sprintf ("日報\(2011/%02d/%02d\)",$m,$mday);
$clip->set($text);


.plはテキストエディタに関連付けているので、バッチファイルを作ってクイック起動にショートカットをおく。これでワンクリックでタイトルが生成され、貼り付ければよい。

年が固定になってる・・・ここはアレしてね。

2011/06/22

ファイルの存在確認シェルスクリプト

#!/bin/sh
if [ -e $1 ]; then
    echo \"$1\" exists.
    if [ -f $1 ]; then
        echo \"$1\" is a file.
    else
        echo \"$1\" is not a file.
    fi
else
    echo \"$1\" does not exist.
fi
実行例
filex.sh という名前で上記スクリプトを書く。
# ls
filex.sh  testdir  test.pl

# sh ./filex.sh testdir
"testdir" exists.
"testdir" is not a file.


# sh ./filex.sh test.pl
"test.pl" exists.
"test.pl" is a file.

2011/06/20

オブジェクト指向@perl

package Fruit;
# コンストラクタ sub new{ my $this = shift; my ( $name, $value, $quantity ) = @_ ; print "There are some $name"."s.\n\n" ; my $fruit = {"Name" => $name, "Value" => $value, "Quantity" => $quantity } ; bless $fruit, $this; return $fruit ; } # デストラクタ sub DESTROY{ my $this = shift; print "$this->{Quantity} $this->{Name}s are disposed.\n"; } # メソッドの定義 sub eaten{ $this = shift ; my ($nums) = @_; if($this->{Quantity}<$nums){ print "You demand $nums $this->{Name}"."s, but there are only $this->{Quantity} $this->{Name}s. \n\n"; }else{ $this->{Quantity}-=$nums; my $costs = $nums * $this->{Value}; print "You've got $nums $this->{Name}s. They cost $costs.\n\n" ; } } # アクセスメソッドの定義 sub howmany{ my $this = shift; print "There are $this->{Quantity} $this->{Name}"."s.\n\n"; } # main のパッケージ名を設定 package main; my $apple = new Fruit "Apple", 100, 30; $apple->eaten(3); $apple->howmany; $apple->eaten(10); my $banana = new Fruit "Banana", 80, 20; $banana->eaten(10); $banana->howmany; $banana->eaten(20);

2011/05/24

カレンダー

#($sec,$min,$hour,$mday,$month,$year,$wday,$stime) = localtime($times);
sub get_time(){
my ($t) = @_;
@a  =  localtime ( $t );
}

print $now = localtime;

@weekday = qw /Sun Mon Tue Wed Thu Fri Sat/;

print "<table border=1><tr>";
foreach(@weekday){
print "<td>$_<\/td>";
}
print "<\/tr>";


@b = &get_time(time);

$d = (@b[6] + 7) * -1;

for($i=0;$i<3;$i++){
print "<tr>";
for($j=0;$j<7;$j++){
@b = &get_time(time + $d * 24 * 3600);
$print_date = sprintf("%2d/%2d ",@b[4]+1,@b[3]);
print "<td>";
if($d == 0){
print "<b>";
print $print_date;
print "<\/b>";
}else{
print $print_date;
}
print "<\/d>";
$d++;
}
print "<\/tr>\n";
}

print "<\/tr><\/table>";





print(1+2)+3

print (1+2)+3;
を実行すると、3 と表示される。 最初はどうしてかわからなかったが、 以下のようにしてみるとわかる。
print (1+2);

print "\n";

print (1+2)+3;

print "\n";

$a=print(1+2);

print "\n";

$a=print(1+2);

print "\n";

print $a;

print "\n";

print (1+2)+3;

print "\n";
上記の出力結果は以下のようになる。
3
3
3
3
1
3
printという関数は引数を表示して結果を返す。
perl -e "print print \"hello\""
上記を実行すると
hello1
と表示される。helloの後ろにくっついている1は、print "hello" の実行結果である。 下記は「(1+2)の結果をprintし、その実行結果の値に3を足す」という意味になる。
print (1+2)+3
成功したらTRUE(1)なので1+3=4となるが、その値はprintされないので、 print(1+2) の結果の 3 のみが表示される。 もし (1+2)+3 という式の結果をprintしたいのであれば、以下のようにする必要がある。
print ((1+2)+3)

2011/05/23

カレンダー

その日の前の週と翌週を含めた3週間を表示する。

@weekday = qw /Sun Mon Tue Wed Thu Fri Sat/;

print "<table border=1><tr>";

foreach(@weekday){
    print "$_<\/td>";
}

( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst )
=  localtime ( time );

$last = ($wday + 7) * -1;


$d=$last;
for($j=0;$j<21 24="" 3600="" d="" hour="" if="" isdst="" j="" localtime="" mday="" min="" mon="" print="" sec="" time="" tr="" wday="=0){" yday="" year="">";
    }
    print "

";
    printf("%2d/%2d ",$mon+1,$mday);
    print "<\/d>";

    if($wday==6){
        print "<\/tr>\n";
    }
    $d++;
}

print "<\/tr><\/table>";

2011/05/10

ファイル列挙

重複チェックにはhashを使うと簡単らしい。
後でやってみる。

browse_directory("c:\\mydoc\\");

sub browse_directory{
local($dir)=@_;
local(*DIR,$file);

if(!opendir(DIR, $dir)){
return;
}

while ($file = readdir(DIR)) {
if(($file eq ".") || ($file eq "..")){
next;
}
if (-d "$dir\\$file") {
browse_directory("$dir\\$file");
}else{
$file_size = -s "$dir\\$file";
$file_size{"$dir\\$file"} = $file_size;
$file_name{"$dir\\$file"} = $file;
}
}
closedir(DIR);
}

foreach $fullpath (sort {$file_size{$b} <=> $file_size{$a}} keys %file_size)  {
print "$fullpath,$file_size{$fullpath},$file_name{$fullpath}\n";
}


指定したディレクトリ配下のファイルについて、フルパス、サイズ、ファイル名を取得してサイズの降順に並べる。

しかしこれには不具合がある。たまたま、フォルダ名が「○○表」というフォルダがあった。これがフォルダとしてではなく、ファイルとして認識されてしまったのだ。回避方法はあるようだがメンドクサイし意味がわからない。

shift-jisはダメだな。「ヤカン」が「ポット」とマッチするという冗談みたいなことが起きる。

while(<>){
if(/ポット/){
print;
print " matched\n";
}else{
print;
print " unmatched\n"
}
}


このスクリプトに「ヤカン」という文字列を含むファイルを読ませると、マッチする。




2011/05/01

重複ファイルの整理

写真を整理していて、重複したファイルがたくさんあることに気付いた。最初はWindowsのエクスプローラでサイズ順にならべて、目で写真をみながら消していたのだが大量にありすぎるのでperlでなんとかしようと思った。まず、あるディレクトリ以下のjpgファイルとそのサイズを取得する。(thanks to internet)

recursive( '.' );
exit();

sub recursive
{
    my( $sBaseDir ) = @_;
    my( @FileLists, $sFileName );

    @FileLists = glob( $sBaseDir.'/*' );

    foreach $sFileName ( sort( @FileLists ) ){
        if ( -d $sFileName ){
            &recursive( $sFileName );
        } elsif ( -f $sFileName ){
            if ($sFileName =~ /\.jpg/){
                $filesize = -s $sFileName;
                print( "$filesize $sFileName \n" );
            }
        }
    }
}
あと、これをしないとフォルダやファイル名に空白が含まれたときにうまくいかない。
ppm install File-Glob-Windows
これでサイズとファイル名が取れる。今回はこれをExcelで開いてサイズでソートしてサイズが同じものだけを残した後、秀丸で置換を使ってhtmlにし、それを見て不要なファイルを残して、また秀丸の置換を使ってバッチファイルを作って消した。サイズが同じjpgでももちろん違うファイルの場合がある。ここは目視で確認せざるを得ない。だが、サイズが同じもののみを表示するhtmlファイルを作るまでなら一発で作れるだろう。

perlにはsortという関数があって1次元の配列なら簡単にソートできるが多次元になるとちょっと面倒だ。WEBにサンプルがいくつかあるのでそれを使えばいいのだが・・・と思ったところで気付いた。別に大きさ順にソートする必要はない。文字列としてソートしても重複なら検知できる。

my @found_files;

sub recursive
{
    my( $sBaseDir ) = @_;
    my( @FileLists, $sFileName );

    @FileLists = glob( $sBaseDir.'/*' );

    foreach $sFileName ( sort( @FileLists ) ){
        if ( -d $sFileName ){
            &recursive( $sFileName );
        } elsif ( -f $sFileName ){
            if ($sFileName =~ /\.jpg/){
                $filesize = -s $sFileName;
                $tmp = $filesize." ".$sFileName;
                push(@found_files,$tmp);
            }
        }
    }
}

recursive( '.' );

@found_files = sort(@found_files);

@saved_files=();
$saved_size=0;

foreach(@found_files){
    @a = split(/ /,$_);
    if(@a[0] ne $saved_size){
        if($#saved_files>0){
            foreach $b(@saved_files){
                $b =~ s/^/<img src="/g;
                $b =~ s/$/">/g;
                print "$b\n";
            }
            print "<br>";
        }
        @saved_files=();
        push(@saved_files,@a[1]);
        $saved_size=@a[0];
    }else{
        push(@saved_files,@a[1]);
    }
}
exit();

サイズだけでは結構同じものがある。ファイルサイズだけでなく、確か widthとheightも取れるはず。それも見よう。

use Image::Size;

my @found_files;

sub recursive
{
    my( $sBaseDir ) = @_;
    my( @FileLists, $sFileName );

    @FileLists = glob( $sBaseDir.'/*' );

    foreach $sFileName ( sort( @FileLists ) ){
        if ( -d $sFileName ){
            &recursive( $sFileName );
        } elsif ( -f $sFileName ){
            if ($sFileName =~ /\.jpg/){
                $filesize = -s $sFileName;
                $tmp = $filesize." ".$sFileName;
                push(@found_files,$tmp);
            }
        }
    }
}

recursive( '.' );

@found_files = sort(@found_files);

@saved_files=();
$saved_size=0;
$saved_width=0;
$saved_height=0;

foreach(@found_files){
    @a = split(/ /,$_);
    ($new_width,$new_height) = imgsize(@a[1]);
    if(@a[0] ne $saved_size){
        if($#saved_files>0){
            foreach $b(@saved_files){
                $c =$b;
                $b =~ s/^/<img src="/g;
                $b =~ s/$/">/g;
                print "$c$b\n";
            }
        print "<br>";
    }
    @saved_files=();
    push(@saved_files,@a[1]);
    $saved_size=@a[0];
    $saved_width=$new_width;
    $saved_height=$new_height;
    }else{
        if($new_width == $saved_width){
            push(@saved_files,@a[1]);
        }
    }
}
exit();


Image::Size モジュールを使って、widthもチェックした。これくらいできれば、個人の使用としては十分。

2011/04/30

Perlで引数を取得するとき

サブルーチンで一つの引数を取得するとき
sub my_subroutine{
    my $val1 = @_;
    ...
}
とやってしまい、$val1が "1" となってしまった。
sub my_subroutine{
    my ($val1) = @_;
    ...
}
このようにしなければならない。@_ は、配列だからである。配列を、カッコで括った複数の変数に代入すると、その変数の数だけの配列がコピーされる。
上記の例は、配列の最初の要素を、$val1にコピーしているのである。基本的なことだけど。最初の $val1 = @_ とやると、配列 @_ の要素数が入るのかな。だから1になった。

2011/04/10

アクセスログ

さくらインターネットのレンタルサーバではwebalizerが使えるのだが、このログは午前0時に前日のログを作成するようになっている。「現在のログ」が見たくてさがしたのだがなかった。おそらく共用サーバなのでひとつにまとまっているのを分割しているのだと思う。そこでcgiでログをとることにした。環境変数をファイルにはくだけでよいので簡単である。flockという関数を、よくわからないが使ってみた。パースは厳密にやろうとすると大変なので、とりあえずそのまま書いて、検索語だけをデコードするようにした。




2011/04/08

tcl

proc load_file {} {
    set file [tk_getOpenFile]
    set f [open $file]
    text .t0
    pack .t0
    set line_count 1
    while {[gets $f line] >= 0} {
        .t0 insert end "$line\n"
        incr line_count
    }
    close $f
}
button .b -text "Open" -command load_file
pack .b

tclはおもしろいんだけど、一体どんな場合に使うんだろうと、ずっとピンと来ない。とりあえずActiveStateからダウンロードしてデモを見てみる。すごい。すごいけど、これをどうすればいいのだろう・・・

2011/03/20

指定したユーザーの最新のツイートを30件表示する

指定したユーザーの最新のツイートを30件表示する。PHP。perlの例は少ないので。

$num_of_tweets = 30;
$user_name = "your_name";

$contents = file_get_contents('http://search.twitter.com/search.atom?q=from:'.$user_name.'&rpp='.$num_of_tweets);

$xml = simplexml_load_string($contents);

print '

'.$user_name.'

'; print '
'; for ($i = 0; $i < $num_of_tweets; $i++ ) { $tweet = $xml->entry[$i]->title; $tweet = mb_convert_encoding($tweet,"SJIS","UTF-8"); $date_tweeted = $xml->entry[$i]->published; $date_tweeted = date('Y/m/d H:i:s',strtotime($date_tweeted)); print $tweet.' ('.$date_tweeted.')

'; } print '
';


件数を100件にしたが、うまくいかなかった。

phpでoauthを使う場合の定番とされているものがあるようだ。

https://github.com/abraham/twitteroauth

OAuth.php

twitteroauth.php

この二つのファイルをダウンロードしておく。

下記がサンプル。上記二つのファイルはこのスクリプト自体と同じ場所においておく。

require_once('twitteroauth.php');

$consumer_key = 'xxxxxxxxxxxxxxx';
$consumer_secret = 'xxxxxxxxxxxxxxxxx';
$oauth_token = 'xxxxxxxxxxxxxxxxxxxx';
$oauth_secret = 'xxxxxxxxxxxxxxxxxxxxx';

$connection = new TwitterOAuth($consumer_key, $consumer_secret, $oauth_token, $oauth_secret);
$content = $connection->get('account/verify_credentials');

$connection->post('statuses/update', array('status' => date(DATE_RFC822)));

実行しても何も表示されないが、twitterの自分のページを見ると、日付と時刻がtweetされているだろう。

今は自分のアプリケーションで自分のアカウントでツイートしているから、スクリプトに自分のconsumer key/secret, oauth token/secretを書き込んでいるが、実際には oauth token/secretは、利用者のそれを取得する必要がある。そのやり方も公開している人がいて、今ためしたらoauthによる認証まではできているようなのだが、肝心のそのあとのAPI操作ができない・・・

session_start();
require_once('twitteroauth.php');

$consumer_key = 'xxxxxxxxxx';
$consumer_secret = 'xxxxxxxxxxxxxxx';
$state = $_SESSION['oauth_state'];
$session_token = $_SESSION['oauth_request_token'];
$oauth_token = $_REQUEST['oauth_token'];
$section = $_REQUEST['section'];

if ($_REQUEST['test'] === 'clear') {
    session_destroy();
    session_start();
}

if ($_REQUEST['oauth_token'] != NULL && $_SESSION['oauth_state'] === 'start') {
    $_SESSION['oauth_state'] = $state = 'returned';
}

switch ($state) {
    default:
        $to = new TwitterOAuth($consumer_key, $consumer_secret);
        $tok = $to->getRequestToken();

        $_SESSION['oauth_request_token'] = $token = $tok['oauth_token'];
        $_SESSION['oauth_request_token_secret'] = $tok['oauth_token_secret'];
        $_SESSION['oauth_state'] = "start";

        $request_link = $to->getAuthorizeURL($token);

        $content = 'Click on the link to go to twitter to authorize your account.';
        $content .= '
'.$request_link.''; //(A) $req = $to->OAuthRequest("https://twitter.com/statuses/update.xml","POST",array("status"=>"test")); header("Location: $request_link"); break; case 'returned': if ($_SESSION['oauth_access_token'] === NULL && $_SESSION['oauth_access_token_secret'] === NULL) { $to = new TwitterOAuth($consumer_key, $consumer_secret, $_SESSION['oauth_request_token'],$_SESSION['oauth_request_token_secret']); $tok = $to->getAccessToken(); $_SESSION['oauth_access_token'] = $tok['oauth_token']; $_SESSION['oauth_access_token_secret'] = $tok['oauth_token_secret']; //(B) $req = $to->OAuthRequest("https://twitter.com/statuses/update.xml","POST",array("status"=>"test")); } $_SESSION['username'] = $tok["screen_name"]; //(C) $req = $to->OAuthRequest("https://twitter.com/statuses/update.xml","POST",array("status"=>"test")); header("Location: /"); }


最初は(C)のところだろうと書いてみたが、internal server errorになる。

(A),(B)に書いてみるとエラーにならないがtweetもされない。

2011/03/19

blockしているユーザの一括解除

blockしているユーザの一覧が見たくて、検索するとそういうページがあるのだが、その解除が一括でできない。半分くらい解除して、メンドクサイしこれくらいは簡単に作れるだろうと、やってみる。API辞典みたいな本は持っているのでblock一覧APIをタイプしてみるが Could not authenticate you となってしまう。そうだ、アプリを登録しないといけないのだ。
#!/usr/bin/perl

use strict;
use warnings;
use utf8;
use Net::Twitter;

my $twit = Net::Twitter->new(
traits => [qw/API::REST OAuth WrapError/],
consumer_key    => 'xxxxxxxxxxxxxxxxxxxxxxx',
consumer_secret => 'xxxxxxxxxxxxxxxxxxxxxxx',
ssl => 1,
);
$twit->access_token       ('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
$twit->access_token_secret('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');

my $array_ref = $twit->blocking();

#print Dumper $array_ref;

foreach my $hash_ref(@$array_ref){
print "$hash_ref->{'screen_name'}\n";
}


exit;
__END__


できた。

これでブロックしているユーザの一覧が表示される。WindowsXPで、ActivePerlをインストールして、Net::Twitterをインストールしておいて、Twitterのホームページでアプリケーションの登録をして、cosumuer_keyとかはその結果を書く。酒を飲みながらいろいろサーチしながら、すぐできました。

次は、これらのユーザのブロック解除ですね。

#!/usr/bin/perl

use strict;
use warnings;
use utf8;
use Net::Twitter;

my $twit = Net::Twitter->new(
traits => [qw/API::REST OAuth WrapError/],
consumer_key    => 'xxxxxxxxxxxxxxxxxxxx',
consumer_secret => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
ssl => 1,
);
$twit->access_token       ('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
$twit->access_token_secret('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');

my $array_ref = $twit->blocking();

foreach my $hash_ref(@$array_ref){
$twit->destroy_block($hash_ref->{'id'});
}

exit;
__END__


blockしているユーザを取得するまでは同じで、それに対して destroy_block をするだけ。ただし、このときの引数はscreen_nameではなくてidです。いいなあ、twitter。今回の震災でも、強さがはっきりわかりました。apiを公開するかどうかが、流行るかどうかですね。こんな感じで、followしている・されているユーザの一覧、followされてるユーザ全員のfollow, followしているユーザ全員のunfollowなども一瞬でできる。

2011/02/13

EMobileのD25HW

衝動的に買ってしまった。そして1,2日使って、「いらなかったかな」と思い始めている。iPhoneを使っているのだが、電波状況の悪さが気になり始めた。
Wifiはつながる場所に行かないと使えない。たとえば通勤中などはほとんど意味がない。オンにしているとそこらじゅうにあるが使えないAPがたくさん見つかるだけである。ある技術者でない人が「Wimaxがいい」というのをきいて、使ってみようと思った。この手のモノは、素人が「いい」と言わないものでないとダメだ。買ったのはWimaxではなかったが。なんでEMobileにしたかというのは、あまりちゃんとした理由がない。なんとなく、よく見聞きする名前だったからだ。EMobileといえば、数年前に高速の無線LANサービスを始めて話題になった。わたしもいいなと思ったが価格とサービスエリアの狭さにより使う気にならなかった。
キャンペーン中で、最初に払うのは1円のみ。ビックカメラのポイントで払った。
月額料金はコースがいくつかあるが、一番高い定額コースにした。4400円くらい(1年後から4800円くらいになる)。家で使っている光の固定回線よりちょっと安い程度である。年額5万円くらいだ。契約手続きをしている時点でようやく、こいつも充電が必要だ、ということに気づいた。
だが、電話もなにもしないんだから数日くらい持つだろうと思って、東海道線のなかでyoutubeを見まくっていたら、あっというまに電池の残りが減っていた。iPhoneの充電ケーブルにくわえてこいつのも持ち歩かなきゃダメか。エネループを使った携帯充電器がよく使われているようだけど、充電するための電池をまた充電するって、まあある程度持つにしても、なんかバカらしいな・・・
今まではyoutubeなんか外ではほとんど見れなかったが、Pocket Wifiがあればたいていのものはほとんど止まらずに見れた。今のところ、メリットはそれくらいである。今いる職場のある部屋ではSoftbankの電波が届かないのだがEMならと思ったがダメだった。これは痛かった。てっきりあそこはSoftbankだけダメなのかと思ったがそうではなかったようだ。youtubeの動画をゆっくり見るなんてことは、家で眠れないときなどにやればよい。ワンセグつきの携帯を持ったときも感じたことだが、動画なんか、落ち着いた場所で見るものだ。歩きながら、電車の中などで見るようなものではない。携帯のワンセグは、最初だけ珍しさからみたが、のちにほとんど見なくなった。それからインターネット自体も、そんなに大容量のデータのやりとりをすることはない。pocket wifiを使ってすぐに、iPhoneで感じていた「そこそこ便利だけどもうちょっと速くなれば最高なんだけどなあ」というくらいのところが、実は一番人がインターネットのありがたさを感じるのではないかと思った。
あと、買おうと決めてカウンターへ歩いていくときにドコモのpocket wifiがあるのを見て、『あっ、ドコモにすればよかった』と思った。まだ使い始めたばかりなので、いい使い道が見つかるかもしれないけどね。

2011/01/03

amebloから移行したブログの画像を取得

use LWP::Simple;
$filename=1;

while(<>){
    chomp;
    $url=$_;
    $file = $filename.'.jpg';
    getstore($url,$file);
    $filename++;
}

amebloから移行したブログの画像を取得する。画像のurlはファイルに書いてあり、それを引数とする。本当はそのurl一覧も取得したかったのだがなぜかできないので、そこはしかたなく手でコピペした。

centos5.5をいれて、ファイルサーバにする。メインのPCはスペックが低く、動画再生中に止まることがある。 centosをインストールすると入るtotemとかいうプレイヤーでは、mpegすら再生できない。コーデックがないのかとかいろいろやってみたが どうにもならず、xineをインストールすることで解決した。

centosではyumを使ってアップデートをするようだが、標準の「レポジトリ(ソフトウェア保管場所)」にあるソフトウェアはごく標準的なものしかないようなので、 dagというレポジトリから取ってくる。xineは標準レポジトリにはない。grep xineとすると xinetdしか引っかからない。