ラベル perl の投稿を表示しています。 すべての投稿を表示
ラベル perl の投稿を表示しています。 すべての投稿を表示

2011年9月13日火曜日

HTML::Templateを使って認証プログラムを作成

HTML::Templateを使用することで、外部に用意してあるHTMLをCGIスクリプトの中に読み込むことができます。HTMLデザインとスクリプトを明確に分離することで、メンテナンス性が高まります。ただし、HTML::Templateは標準モジュールではないので、CPANを使ってインストールする必要があります。

今回はHTML::Templateを使って、簡単な認証プログラムをかきました。
ID/PWに guest/guestと入力してログインボタンをクリックすれば、ログイン後のhtmlページを表示します。

%2525E3%252582%2525B9%2525E3%252582%2525AF%2525E3%252583%2525AA%2525E3%252583%2525BC%2525E3%252583%2525B3%2525E3%252582%2525B7%2525E3%252583%2525A7%2525E3%252583%252583%2525E3%252583%2525882011-09-1321.59.13-2011-09-13-21-05.png


enter.tmpl
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="ja">
<head>
<meta http-equiv="content-type" content="text/html; charset=shift_jis">           
</head>
<body>
<div align="center">
<form action="login.cgi" method="post">
<b>認証</b></br>
ID : <input type="text" name="id" ><br><br>
PW : <input type="password" name="pw" ><br><br> 

<div align="center">
<input type="submit" name="login" value="ログイン">
</div>
</form>
</body>
</html>

login.cgi
#!/usr/bin/perl

# モジュール宣言
use strict;
use warnings;
use CGI;
use CGI::Carp qw(fatalsToBrowser);
use HTML::Template;

# ユーザのID/PW
my %user = ( "guest" => "guest" );

# CGIオブジェクトの生成
my $cgi = new CGI();

# ログイン処理
if ($cgi->param('login')) {       
        &login;
}
&enter_form;

#---------------------------------------------------------------------
# ログイン認証
sub login {
        # idのパラメータ取得
        my $id = $cgi->param('id');
        # pwのパラメータ取得
        my $pw = $cgi->param('pw');
       
        # id/pwがguest/guestならば、test.htmlを表示
        if ($id eq "guest" and $pw eq "guest") {
                print "Content-type: text/html\n";
                print "Location: ./test.html\n\n";
               
        }
}

# HTML::Templateを使用してログイン画面表示
sub enter_form {
        # HTML::Templateオブジェクトを作成
        my $tmpl = HTML::Template->new(filename => 'enter.tmpl');               
        # HTMLの出力
        print "Content-type: text/html\n\n";
        print $tmpl->output;
}        

今回は同ディレクトリに、HTMLテンプレートとCGIスクリプトを実装しましたが、テンプレートファイルはWebクライアントが直接アクセスできないディレクトリに配置するのが普通みたいです。

それと、CGIスクリプトの中にID/PWを記述するのではなく、隠しファイル等を使って、Webクライアントがアクセスできないディレクトリに配置しておかないとダメです。

2011年5月8日日曜日

twitterのXMLを処理する

ブームに乗り遅れた感はありましたが、XMLを勉強しました。
twitterのXML情報を読み込んで、プログラミングを実装します。

当初の目的としては、TwitterのXML情報を読み込んで、Tweetを発信した位置情報を返し、今あの人がどこにいるのかを探すツイセキッターたるものを実装しようとしていました。
しかし、XMLの中身を調べてみると、発信した位置情報を示す箇所は見当たらず(当然だな)、諦めました。

なので、ツイッターで発信したツイートをコマンドラインに表示するプログラミングを書くことにしました。

さすが、Perl。すでにモジュールが広まっていました。
XML::FeedとURIをcpanでインストールして、以下のプログラミングを書くだけです。


#!usr/bin/perl

use strict;
use warnings;
use XML::Feed;
use URI;
binmode STDOUT, “:utf8”;

my $user_id = ‘hogehoge’;
my $url = “http://twitter.com/statuses/user_timeline/${user_id}.atom”;

my $feed = XML::Feed->parse( URI->new( $url ) )
or die XML::Feed->errstr;
for my $item ( $feed->entries ) {
print $item->content->body, “\n”;
}



XML::Feedは下記に対応しています。Tweeterにとどまらず幅広い使い方が可能です。
・RSS 0.91
・RSS 1.0
・RSS 2.0
・Atom


参考:http://fleur.hio.jp/perldoc/mix/lib/XML/Feed.mix.html

2011年4月25日月曜日

perlでエラーログを抽出する

最近、仕事でデータをインポートする作業が多くなっています。
1000件、2000件ともなると、エラーが置きたさいにデータの確認が大変です。

エラーのデータだけを抽出したcsvを出力することで、どのようなデータでERRORが起きるのかの把握で時間短縮ができるのでは?と思い、Perlで実装しました。

インポートの際には、下のようなログがでます。
SUCCESS line no. 1 ...
ERROR line no. 2 ...

実装としては、
*csvファイルとログテキストを同じ階層に配置させておく。
*ログテキストを読んで、ERRORの後の番号(行数)を配列として保存する
*CSVファイルを読んで、上で保存した番号(行数)のデータだけを新規のCSVとして出力する



#!usr/bin/perl

use strict;
use warnings;

## register files
print "log_txt : ";
chomp(my $log_txt = <STDIN>);
print "csv : ";
chomp(my $csv = <STDIN>);
print "exporter_csv : ";
chomp(my $export_csv = <STDIN>);

## data of culumn for csv
my @error_num = ("0");

## run
my $error_data = &error_data_number();
my $create_csv = &create_csv_with_error_data();
print "compleate!\n";


## stored number of error data
sub error_data_number {
        open IN, '<', $log_txt or die "file open error: $!";

        while(<IN>) {
                chomp;
                if (/(ERROR line no. )(\d+)/) {
                        push(@error_num, $2);
                }
        }
        close IN;
}


## create csv with error data
sub create_csv_with_error_data {
        open IN, '<', $csv or die "$csv file open error: $!";
        open OUT, '>', $export_csv or die "$export_csv file open error: $!";

        my @data = <IN>;
        while (@error_num) {
                my $fred = shift(@error_num);
                print OUT $data[$fred];
        }

        close IN;
        close OUT;
}


ここ最近Perlを勉強中ですが、たいていのことはPerlで実装できるんだな、と感じてきました。
Linuxでは標準でインストールされていて、使い勝手の良い言語なだけに、インフラ屋は、Perlを理解して使いこなすことで、作業効率が上がります。

勉強もかねて、作業を効率にさせてくれるものは、どんどん実装していこうと思います。
とくに自動化できるところは、押し進めていきたいです!


2011年4月12日火曜日

正規表現

Perlには、組み込まれている専用の特殊言語によって記述された小さなプログラムをもっています。これを正規表現といいます。正規表現 (regular expression) は、高速で柔軟で信頼性の高い文字列処理を行います。Perlでは、正規表現のことをしばしばパターンと呼びます。その結果はTrue(マッチする)か、False(マッチしない)のいずれかになります。

単純なマッチ
$_の内容に対して、正規表現をマッチさせるには、スラッシュで囲んで指定します。

$_ = "Taichi Shindo";
if (/aich/) {
print "It matched.\n";
}

/で囲まれた文字列を、$_の中から探し、見つかれば真の値を返します。



ワイルドカード文字
ドット( . )はワイルドカード文字です。改行文字を除いたあらゆる文字1個にマッチします。

例)/ab.cd/
        abbcd, ab=cd, ab.cd の全てにマッチします。


量指定子
パターンの中で何かを繰り返したいときにつかいます。
■アスタリスク(*)は直前に置かれたものに0回以上マッチすることを表します

■プラス記号(+)は直前に置かれたものに1回以上マッチすることを表します

■クエスチョン記号(?)は直前に置かれたものが0回もしくは1回現れるのどちらかです。
        例)/ab-?cd/
                ab-cd, abcd のいずれかを含む文字列にマッチする

■ブレース( { } )は、繰り返し回数の最小と最大を表す2つの数字をコンマで区切って並べる。
        例)/a{2, 4}/
                aa, aaa, aaaa のいずれかを含む文字列にマッチする


選択肢
縦棒( | )は、その左側か右側のどちらか一方にマッチすることを表します。
例)/abc | def | ghi/
        abc, def, ghi のどれかを含む文字列にマッチします


文字クラス
文字クラスは、ブラケット( [ ] )の間に文字を並べ、その文字のどれか1個にマッチする場合、Trueを返します。
例)/[abc]/
        a, b, c のどれかの文字のを含む文字列にマッチする

■ハイフン ( - ) を使って文字の範囲を指定する
ハイフン( - )を使って文字の範囲を指定することができます。
例)/[a-zA-Z]/
        アルファベットの大文字・小文字合わせて52文字のどれかに含む文字列にマッチする

■文字クラスのショートカット
よく使われる文字クラスについてはショートカットが用意されています。
\d        数字にマッチする [0-9] と同じ意味
\w        全ての文字 [a-zA-Z0-9_]と同じ意味
\s        空白文字 [ \f\t\n\r ] と同じ意味(フォームフィード、タブ、改行文字、復帰文字)


アンカー
正規表現では、文字列の特定の場所に固定するために、アンカーが用意されています。
■キャレットアンカー( ^ ): 文字列の先頭を表す
        例)/^abc/
                文字列の先頭にある abc を含む文字列にマッチする

■ドル記号アンカー( $ ): 文字列の末尾を表す
        例) /abc$/
                文字列の末尾にある abc を含む文字列にマッチする

*よく使われるパターンに空白文字にマッチを表す、/^\s*$/ があります

■ワードアンカー( \b ) : ワードの両側にマッチします
        例)/\babc\b/
                abc の文字列にマッチする       
                abcd, zabc などの文字列にはマッチしない


後方参照
カッコで囲むことによって、パターンを正規表現エンジンに記憶させることができます。これによって、後方参照を実現することができます。

例)/(.)\1/
        任意の1文字にマッチして、その後ろに同じ文字がもう1個続くものにマッチする
        abccd, abb などを含む文字列にマッチする

2011年4月6日水曜日

ハッシュを定義する

ハッシュとは、配列と同じように任意の個数の値を格納するデータ構造の一つです。ただし、配列とは違って、格納する個々の値を指定するのに、数値 (index) の代わりに名前を使います。この名前をキーと言います。

name [1] = “Hanako”

indexである “1” の値に名前を使う事ができます。
下記のように表すことができます。

$name{“ Yamada “} = “Hanako”

“Yamada” がキー、”Hanako” が値になります。

配列はindexがユニークな値になっています。ハッシュでも、キーはユニークな値しか認められません。


ハッシュの要素にアクセス
要素にアクセスする場合は以下のように書きます。

$hash{$some_key}

具体例として、
$name{“Yamada”} = “Hanako”;
$name{“Suzuki”} = “Taro”;
$name{“Shindo”} = “Taichi”;


ハッシュの全体にアクセス
ハッシュ全体を表すには、”%”を使います。

%name = (“Yamada”, “Hanako”, “Suzuki”, “Taro”, “Shindo”, “Taichi” };

■ハッシュをほどく
Perlは、検索が速くできるような順番で、キーと値のペアを格納するため、リストに戻したさいに、元のリストとお同じ順番で並ぶとは限りません。

#!usr/bin/perl
%some_hash = ("Yamada", "Hanako", "Suzuki", "Taro", "Shindo", "Taichi");
@any_array = %some_hash;
print "@any_array\n";

実行してみる

$ perl 5_2_1
Yamada Hanako Shindo Taichi Suzuki Taro


■ => を使ってキー/値を定義する
人間にとって、どれがキーで、どれが値かを分かりやすくするために、”=>” を使います。

%name = (“Yamada” => “Hanako”, “Suzuki” => “Taro”, “Shindo” => “Taichi” };


関数を使う
ハッシュ全体を扱う関数がいくつかあります。

■keys ・ values
keys : ハッシュに含まれる全てのキーから成るリストを返します。
values : ハッシュに含まれる全ての値から成るリストを返します。

サンプルとしては下記の通りです。

%name = ("Yamada", "Hanako", "Suzuki", "Taro", "Shindo", "Taichi");

my @key = keys %name;
my @value = values %name;

print "\%nameのキー:@key\n";
print "\%nameの値:@value\n";

実行すると、下記が出力されます。
%nameのキー:Yamada Shindo Suzuki
%nameの値:Hanako Taichi Taro


■each
each : 評価するたびに、次のキー/値のペアを返します。繰り返しに利用されます。

サンプルとしては下記の通りです。

%name = ("Yamada", "Hanako", "Suzuki", "Taro", "Shindo", "Taichi");

while( ($key, $value) = each %name ) {
print "$key => $value\n";
}

実行すると下記が出力されます。
Yamada => Hanako
Shindo => Taichi
Suzuki => Taro

2011年4月5日火曜日

サブルーチンを定義する

Perlでは、ほかの言語と同様にサブルーチン (subroutine:ユーザ定義の関数) を定義することができます。これを利用することで、何度も再利用することが可能になります。

サブルーチンの定義
■下記のように定義します。

sub ${subrootine} {
        body;
}

sub と subrootineの名前を置き、その後ろにbody(コード)を置き、ブレースで囲みます。
例えば、以下のように書きます。

sub hello {
        print “Hello, Perl ! “;
]

■Perlのサブルーチンの特徴としては、下記に挙げるものです。
・サブルーチン定義は、プログラムファイルのどこに置いても構いません。
・サブルーチン定義は、特別な処理をしない限りグローバルです。
・同じ名前を持つサブルーチンが2つあると、後ろに置かれたものが、前に置かれたものを上書きします。


戻り値
■Perlでは、サブルーチンの戻り値を単純にしました。
つまり、サブルーチンの中で最後に行われた計算の結果を自動的に戻り値にしました。
例えば下記のコードを作成します。

#!usr/bin/perl

sub hello {
print "Hello Perl !\n";
$num1 + $num2;
}

$num1 = 1;
$num2 = 2;

$num3 = &hello;
print "\$num3 is $num3.\n";

$num4 = $hello;
print "\$num4 is $num4.\n";



結果は下記のとおりです。
Hello Perl !
$num3 is 3.
Hello Perl !
$num4 is 3.

つまり、$num1 + $num2 が戻り値になります。


■誤って、サブルーチンの最後の行にコードを加えてしまったらどうなるでしょう。

#!usr/bin/perl

sub hello {
print "Hello Perl !\n";
$num1 + $num2;
        
print “It is mistake!”;
}

$num1 = 1;
$num2 = 2;

$num3 = &hello;
print "\$num3 is $num3.\n";

$num4 = $hello;
print "\$num4 is $num4.\n";


結果は下記の通りです。
Hello Perl !
It is mistake!$num3 is 1.
Hello Perl !
It is mistake!$num4 is 1.

printの表示が成功したことを示す ” 1 “ の値が戻り値になっています。
$num1 + $num2 の値はどうなるのでしょうか?Perlはそれを捨ててしまいます。
もし、警告を有効にしておくと、下記のメッセージも出力されます。

Useless use of addition (+) in void context at subrountine_sample_1 line 5.


■最後に評価された式を返す
下記の式を見てみましょう。
subroutineで最後に評価される式としては、$num1もしくは$num2のどちらかです。

#!usr/bin/perl

sub larger_num1_or_num2 {
if ($num2 < $num1) {
$num1;
} else {
$num2;
}
}

$num1 = 1;
$num2 = 2;

$large_number = &larger_num1_or_num2;

print "\$large_number is $large_number.\n";



引数
サブルーチンに対して引数を渡すには、サブルーチンの直後にリスト式を置きます。
$n = larger_num1_or_num2(10 , 15);

この引数は、サブルーチンを実行している間、自動的に特別な配列変数@_に代入されます。

#!usr/bin/perl

sub larger_num1_or_num2 {
if ($_[1] < $_[0]) {
$_[0];
} else {
$_[1];
}
}

$large_number = &larger_num1_or_num2(10, 15);

print "\$large_number is $large_number.\n";


return演算子
サブルーチンの残りを実行せずに、即座に値を返すのが、Perlのreturn文の使い方です。

2011年3月19日土曜日

OracleとPerlを連携

せっかくOracleをインストールしたので、OracleとPerlを連携しよう。

ということで、DBIとDBD:Oracleをインストールみました。

$ cpan install DBI
$ cpan install DBD::Oracle

DBD::Oracleのインストールがうまくいかない?
調べてみると、同様に上手くいかないという声が。
下のサイトで解決方法が書いてありました。
http://www.movabletype.jp/documentation/mt5/advanced/creating-an-oracle-database.html

$ cpan P/PY/PYTHIAN/DBD-Oracle-1.22.tar.gz

でうまくいきました。


dbtest.cgiプログラムを作成します。
%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%882011-03-1922.01.37-2011-03-19-22-00.png
さっそく、URLを打ち込む。
エラーが出る。

ORA-12541: TNS: リスナーがありません (DBD ERROR: OCIServerAttach) at /var/www/cgi-bin/dbtest.cgi line 7.

%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%882011-03-1922.08.05-2011-03-19-22-00.png


んーsqlplusに接続してみた。

%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%882011-03-1922.08.59-2011-03-19-22-00.png

あ、Oracleがshutdownされていたんだ。
Oracleを起こしてみた。ついでに、リスナーも起こしてみる。

sql > startup
sql > quit

$ lsnrctl start


再度URLを入力
%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%882011-03-1922.37.57-2011-03-19-22-00.png


おし、完成。

Perlプログラムを実行する

perlのプログラムを実行してみる。

エディタはEmacsを使ってみました。

%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%882011-03-1911.31.15-2011-03-19-11-25.png

Perlプログラムをターミナルで実行してみました。
%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%882011-03-1911.30.49-2011-03-19-11-25.png

解説
■#!/usr/bin/Perlって何を表しているの?
#!/usr/bin/Perlは特別なコメントです。このプログラムはファイル/usr/bin/Perlに格納されていることを意味しています。

Perlプログラムのうち最も移植性が低い部分です。各マシンごとに、どのように記述するのかを調べる必要があります。


■このプログラムのファイル名は、my_programになっているけど拡張子をつけなくてもいいの?
Unixシステムでは、Perlは拡張子をつける必要はありません。ただし、Unixシステム以外だと必要なものもあるので、各自調べる必要があります。

プログラムを使うだけの人にとっては、どの言語で書かれているのかは、必要ではないので、拡張子をつけないのが流行っていたりもします。


■ $ chmod a+x my_program で何をやっているの?
システムに対して、このファイルがプログラムであると教えることができます。


■ $ ./my_program ドットとスラッシュはなぜ必要なの?
シェルが同名の別プログラムを起動してしまうことを防ぎます。

これは、カレントディレクトリからmy_programファイルを探すという意味です。