• Save
perl casual #4 大改造!! Perl劇的ビフォーアフター
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share

perl casual #4 大改造!! Perl劇的ビフォーアフター

  • 2,541 views
Uploaded on

http://cpanbook.koneta.org/post/5027293272/perl-casual-4

http://cpanbook.koneta.org/post/5027293272/perl-casual-4

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
2,541
On Slideshare
2,539
From Embeds
2
Number of Embeds
1

Actions

Shares
Downloads
0
Comments
0
Likes
0

Embeds 2

http://orhowilearnedtolovetheperl.com 2

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. 本が出ました• m(__)m
  • 2. CONFIDENTIAL @tomitaPerl Casual #4 @tomita
  • 3. アジェンダ• 物件1: バッチ処理• 物件2: メール送信フォーム の使い⽅紹介
  • 4. 物件1 バッチ処理 1
  • 5. $dbuser = company-batch;$dbpass = company-batch-pass;use DBI;$month = time - 60*60*24*7;($sec, $min, $hour, $mday, $mon, $year) = localtime($month);$month = sprintf("%4d%02d", $year+1900, $mon);$db = DBI->connect(dbi:mysql:company, $dbuser, $dbpass);$st = $db->prepare(q{ SELECT section, COUNT(*) AS count FROM inquiry WHERE DATE_FORMAT(ctime, "%Y%m") = ? GROUP BY section});$st->execute($month);open FH, "> $month.csv";while (my $row = $st->fetchrow_arrayref) { print FH join ",", @$row; print FH "¥r¥n";}
  • 6. 0 0 1 * * cd /home/app/; perl batch/dump.pl
  • 7. 改善したい点• 動くのだけど・・・
  • 8. $dbuser = company-batch;$dbpass = company-batch-pass;use DBI; パスワードをスクリ$month = time - 60*60*24*7;($sec, $min, $hour, $mday, $mon, $year) = プトに書きたくない localtime($month);$month = sprintf("%4d%02d", $year+1900, $mon);$db = DBI->connect(dbi:mysql:company, $dbuser, $dbpass);$st = $db->prepare(q{ SELECT section, COUNT(*) AS count FROM inquiry WHERE DATE_FORMAT(ctime, "%Y%m") = ? GROUP BY section});$st->execute($month);open FH, "> $month.csv";while (my $row = $st->fetchrow_arrayref) { print FH join ",", @$row; print FH "¥r¥n";}
  • 9. $dbuser = company-batch;$dbpass = company-batch-pass;use DBI;$month = time - 60*60*24*7;($sec, $min, $hour, $mday, $mon, $year) = localtime($month);$month = sprintf("%4d%02d", $year+1900, $mon);$db = DBI->connect(dbi:mysql:company, $dbuser, $dbpass); 前⽉指定が怪しい。$st = $db->prepare(q{ SELECT section, COUNT(*) AS count FROM inquiry あと引数で任意の⽉ WHERE DATE_FORMAT(ctime, "%Y%m") = ? GROUP BY section});$st->execute($month); を指定したいopen FH, "> $month.csv";while (my $row = $st->fetchrow_arrayref) { print FH join ",", @$row; print FH "¥r¥n";}
  • 10. $dbuser = company-batch;$dbpass = company-batch-pass;use DBI;$month = time - 60*60*24*7;($sec, $min, $hour, $mday, $mon, $year) = localtime($month);$month = sprintf("%4d%02d", $year+1900, $mon);$db = DBI->connect(dbi:mysql:company, $dbuser, $dbpass); 自作CSV出⼒部分の$st = $db->prepare(q{ SELECT section, COUNT(*) AS count FROM inquiry 不安 WHERE DATE_FORMAT(ctime, "%Y%m") = ? GROUP BY section});$st->execute($month);open FH, "> $month.csv";while (my $row = $st->fetchrow_arrayref) { print FH join ",", @$row; print FH "¥r¥n";}
  • 11. 改善したい点• パスワードをスクリプトに書きたくな い• 前⽉指定が怪しい。• あと引数で任意の⽉を指定したい• 自作CSV出⼒部分の不安• を置いておいて
  • 12. 潜在的な問題
  • 13. p.12
  • 14. $dbuser = company-batch;$dbpass = company-batch-pass;use DBI; use strict;$month = time - 60*60*24*7;($sec, $min, $hour, $mday, $mon, $year) = use warnings; localtime($month); がない = ケアレス$month = sprintf("%4d%02d", $year+1900, $mon);$db =$st = ミスの可能性 DBI->connect(dbi:mysql:company, $dbuser, $dbpass); $db->prepare(q{ SELECT section, COUNT(*) AS count FROM inquiry WHERE DATE_FORMAT(ctime, "%Y%m") = ? GROUP BY section});$st->execute($month);open FH, "> $month.csv";while (my $row = $st->fetchrow_arrayref) { print FH join ",", @$row; print FH "¥r¥n";}
  • 15. $dbuser = company-batch; 例外処理不⾜$dbpass = company-batch-pass;use DBI;$month = time - 60*60*24*7;($sec, $min, $hour, $mday, $mon, $year) = localtime($month);$month = sprintf("%4d%02d", $year+1900, $mon);$db = DBI->connect(dbi:mysql:company, $dbuser, $dbpass);$st = $db->prepare(q{ SELECT section, COUNT(*) AS count FROM inquiry WHERE DATE_FORMAT(ctime, "%Y%m") = ? GROUP BY section});$st->execute($month);open FH, "> $month.csv";while (my $row = $st->fetchrow_arrayref) { print FH join ",", @$row; print FH "¥r¥n";}
  • 16. $dbuser = company-batch;$dbpass = company-batch-pass;use DBI;$month = time - 60*60*24*7; ⽇本語を含む値($sec, $min, $hour, $mday, $mon, $year) = だった場合 localtime($month);$month = sprintf("%4d%02d", $year+1900, $mon);$db = DBI->connect(dbi:mysql:company, $dbuser, $dbpass);$st = $db->prepare(q{ SELECT section, COUNT(*) AS count FROM inquiry WHERE DATE_FORMAT(ctime, "%Y%m") = ? GROUP BY section});$st->execute($month);open FH, "> $month.csv";while (my $row = $st->fetchrow_arrayref) { print FH join ",", @$row; print FH "¥r¥n";}
  • 17. 潜在的な問題• use strict; use warnings; がない ←• 例外処理不⾜• ⽇本語を含む値だった場合
  • 18. use strictuse warnings;$dbuser = company-batch;$dbpass = company-batch-pass;use DBI;$month = time - 60*60*24*7;($sec, $min, $hour, $mday, $mon, $year) = localtime($month);$month = sprintf("%4d%02d", $year+1900, $mon);$db = DBI->connect(dbi:mysql:company, $dbuser, $dbpass);$st = $db->prepare(q{ SELECT section, COUNT(*) AS count FROM inquiry WHERE DATE_FORMAT(ctime, "%Y%m") = ? GROUP BY section
  • 19. perl -c> perl –c dump.plGlobal symbol "$dbuser" requires explicit package name atdump.pl line 5
  • 20. 潜在的な問題• use strict; use warnings; がない• 例外処理不⾜ ←• ⽇本語を含む値だった場合
  • 21. p.246, 247 PRポイント: 全編falseを返すのか、 例外を返すのか、例 外を返すにはどうし たらよいのかを触れ ている
  • 22. p.15
  • 23. use strictuse warnings;use autodie; autodie;my $dbuser = company-batch;my $dbpass = company-batch-pass;use DBI;my $month = time - 60*60*24*7;my ($sec, $min, $hour, $mday, $mon, $year) = localtime($month);$month = sprintf("%4d%02d", $year+1900, $mon);my $db = DBI->connect(dbi:mysql:company, $dbuser, $dbpass,{ RaiseError => 1,});my $st = $db->prepare(q{
  • 24. MAILTO=admin@example.com0 0 1 * * cd /home/app/; perl batch/dump.pl
  • 25. 潜在的な問題• use strict; use warnings; がない• 例外処理不⾜• ⽇本語を含む値だった場合 ←
  • 26. p.248 DBI DBI PRポイント: 全編を通して”⽂字列” を受け取るのか、返 すのかに触れている
  • 27. p.11 凡例
  • 28. my $db = DBI->connect(dbi:mysql:company, $dbuser, $dbpass,{ RaiseError => 1, mysql_enable_utf8 => 1,});...open(my $fh, >:encoding(cp932), $filename); open()の使い⽅ですが openモジュールの項目 で解説しています
  • 29. 改善したい点• パスワードをスクリプトに書きたくな い• 前⽉指定が怪しい。• あと引数で任意の⽉を指定したい• 自作CSV出⼒部分の不安
  • 30. 設定ファイルJSON形式YAML形式INI形式XML形式
  • 31. p.223 App::Options
  • 32. 改善したい点• パスワードをスクリプトに書きたくな い• 前⽉指定が怪しい。• あと引数で任意の⽉を指定したい• 自作CSV出⼒部分の不安
  • 33. use strict;use warnings;use autodie;use DBI; App::Options(use App::Options( option => { filename_format => { ./%s.csv s.csv default => ./%s.csv }, dbuser => { required => 1 }, dbpass => { required => 1 }, month => { required => 1, type => /^20¥d{4}$/ }, /^20¥ });my $db = DBI->connect(dbi:mysql:company, $App::options{dbuser}, App::options{dbuser} $App::options{dbpass}, App::options{dbpass} { RaiseError => 1, mysql_enable_utf8 => 1, },);
  • 34. •dump.confdbuser = company-batchdbpass = company-batch-pass> perl dump.pl --month=201103 --helpUsage: dump.pl [options] [args] --help print this message --dbpass=<value> [********] --dbuser=<value> [company-batch] --filename_format=<value> [./%s.csv] --month=<value> [201103] (/^20¥d{4}$/)
  • 35. 改善したい点• パスワードをスクリプトに書きたくな い• 前⽉指定が怪しい。 ←• あと引数で任意の⽉を指定したい• 自作CSV出⼒部分の不安
  • 36. p.95-p.95- Time::Piece
  • 37. Time::Piece Piece;use Time::Piece;use Time::Seconds; Time::Seconds;use App::Options( option => { filename_format => { default => ./%s.csv }, dbuser => { required => 1 }, dbpass => { required => 1 }, month => { type => /^20¥d{4}$/, default => do { localtime; my $d = localtime; $d- month_last_day; $d -= ONE_DAY * $d->month_last_day; $d- strftime(%Y%m); $d->strftime(%Y%m); }, }, });my $db = DBI->connect(dbi:mysql:company,
  • 38. 改善したい点• パスワードをスクリプトに書きたくな い• 前⽉指定が怪しい。• あと引数で任意の⽉を指定したい• 自作CSV出⼒部分の不安 ←
  • 39. p.202 Text::CSV
  • 40. my $rows = $db->selectall_arrayref(q{ SELECT section, COUNT(*) AS count FROM inquiry WHERE DATE_FORMAT(ctime, "%Y%m") = ? GROUP BY section}, {}, $App::options{month},);my $filename = sprintf $App::options{filename_format}, $App::options{month};open(my $fh, >:encoding(cp932), $filename); $csv Text::CSV-my $csv = Text::CSV->new({ auto_diag => 1, binary => 1, eol => "¥r¥n", "¥});$csv->print($fh, $_) for @$rows; csv- print($fh,
  • 41. なんということでしょう〜•before$dbuser = company-batch;$dbpass = company-batch-pass;use DBI;$month = time - 60*60*24*7;($sec, $min, $hour, $mday, $mon, $year) = localtime($month);$month = sprintf("%4d%02d", $year+1900, $mon);$db = DBI->connect(dbi:mysql:company, $dbuser, $dbpass);$st = $db->prepare(q{ SELECT section, COUNT(*) AS count FROM inquiry WHERE DATE_FORMAT(ctime, "%Y%m") = ? GROUP BY section});$st->execute($month);
  • 42. なんということでしょう〜•afteruse strict;use warnings; https://gist.github.com/956691use autodie;use DBI;use Text::CSV;use Time::Piece;use Time::Seconds;use App::Options( option => { filename_format => { default => ./%s.csv }, dbuser => { required => 1 }, dbpass => { required => 1 }, month => { type => /^20¥d{4}$/, default => do { my $d = localtime;
  • 43. 導⼊したモジュール• strict• warnings• autodie• Text::CSV• Time::Piece• App::Options
  • 44. モジュールのインストール• → p.421- App::cpanminus
  • 45. App::cpanminusの項目で取り上げてApp::cpanminusいる内容• cpanmコマンド自体の導⼊⽅法• インストールパスの確認⽅法• 特定のディレクトリにインストールす る⽅法(ユーザー権限で)• インストール失敗時のトラブルシュー ティング
  • 46. > cpanm -l extlib autodie Text::CSV Time::Piece App::Optionsuse strict;use warnings;use FindBin; FindBin;use lib "$FindBin::Bin/extlib/lib/perl5";use autodie;use DBI;use Text::CSV;use Time::Piece;use App::Options(> perl -Mlib="extlib/lib/perl5/" dump.cgi
  • 47. 物件2 メール送信フォーム 2
  • 48. 割愛
  • 49. 割愛
  • 50. 1ページ目のサンプルがほとんど• strict/warningsに通らない• jcode.pl付属(2005年以前?)• メールのソースを⼿作り• 自作のバリデーション• エラー⽂⾔が送信プログラムに書いてある• ※だめというわけではありません
  • 51. 改造• というよりは作り直しの例
  • 52. サーバー サーバー・バリデーション ・バリデーション ・処理(メール送信)
  • 53. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><link rel="stylesheet" href="http://static.koneta.org/base.css" type="text/css" /><title>お問い合わせフォーム</title></head><body><h1>お問い合わせフォーム</h1> https://gist.github.com/956691<form method="post" id="form"> <p>お名前<br /> <input type="text" class="input text" name="name" /></p> <p>メールアドレス<br /> <input type="text" class="input text ascii" name="email" /></p> <p>お問い合わせ内容<br /> <textarea class="input" name="comment"></textarea></p> <p class="notice message hide">入力内容を確認してください。</p> <p class="error message hide">送信失敗しました。info@koneta.orgまで送信願います。</p> <p class="information message hide step2">この内容で送信してもよいですか?</p> <button type="submit" class="step1" value="2">確認</button> <button type="submit" class="step2 hide" value="1">修正</button> <button type="submit" class="step2 hide" value="3">送信</button></form> <p class="success message hide step3">お問い合わせありがとうございました。</p></body></html>
  • 54. サーバーサイド• JSON作成• JSON RPC サーバー• ⼊⼒値バリデーション• メール作成• メール送信• 割愛: トークン、丁寧なエラー
  • 55. サーバーサイド• JSON作成 ←• JSON RPC サーバー• ⼊⼒値バリデーション• メール作成• メール送信
  • 56. p.180 JSON
  • 57. use JSON;my $res = { version => 1.1 };if (my $error = validate($req)) { $res->{error} = $error;}if ($res->{validate} and $req->param(step) eq submit) { $res->{result} = sendmail($req);} encode_json($res);my $body = encode_json($res);
  • 58. サーバーサイド• JSON作成• JSON RPC サーバー ←• ⼊⼒値バリデーション• メール作成• メール送信
  • 59. Plack::Request;use Plack::Request;my $app = sub { $req Plack::Request- new(shift); my $req = Plack::Request->new(shift); my $res = { version => 1.1 }; if (my $error = validate($req)) { $res->{error} = $error; } if ($res->{validate} and $req->param(step) eq submit) { $res->{result} = sendmail($req); } my $body = encode_json($res); return [ 200, Content- application/json json [ Content-Type => application/json ], [ $body ], ];};
  • 60. なんということでしょう〜•before 割愛
  • 61. なんということでしょう〜•afteruse strict;use wanings;use JSON https://gist.github.com/956691use Plack::Request;my $app = sub { my $req = Plack::Request->new(shift); my $res = { version => 1.1 }; if (my $error = validate($req)) { $res->{error} = $error; } if ($res->{validate} and $req->param(step) eq submit) { $res->{result} = sendmail($req); }
  • 62. p.334, 335 Plack
  • 63. サーバーサイド• JSON作成• JSON RPC サーバー• ⼊⼒値バリデーション ←• メール作成• メール送信
  • 64. p.346 FormValidator::Lite• おすすめ理由 http://d.hatena.ne.jp/tomi-ru/20110119/1295394476
  • 65. なんということでしょう〜•before 割愛
  • 66. •after qw/Email/;use FormValidator::Lite qw/Email/;sub validate { my ($req) = @_; ($req) req FormValidator::Lite- new($req); my $form = FormValidator::Lite->new($req); $form- $form->check( email => [REQUIRED, EMAIL], comment => [REQUIRED], ); $form- has_error; return unless $form->has_error; return { name ValidateError ValidateError, => ValidateError, code => 100, message => Validate Error, };}
  • 67. サーバーサイド• JSON作成• JSON RPC サーバー• ⼊⼒値バリデーション• メール作成 ←• メール送信
  • 68. なんということでしょう〜•before 割愛
  • 69. •afteruse utf8;use Encode;use Email::MIME; Email::MIME; Email::MIME-my $email = Email::MIME->create( header => [ From => $req->param(email), $req param(email), req- To info@koneta.org info@koneta.org, => info@koneta.org, Subject => [問い合わせフォーム], [問 わせフォーム], フォーム ], attributes => { charset iso-2022- => iso-2022-jp, encoding => 7bit, }, sprintf( body_str => sprintf( "[Name]¥n%s¥ n[Comment]¥n%s", "[Name]¥n%s¥n¥n[Comment]¥n%s", $encoding- $req param(name) req- $encoding->decode( $req->param(name) ), $encoding- $encoding->decode( $req->param(comment) ), $req param(comment) req- ),);
  • 70. サーバーサイド• JSON作成• JSON RPC サーバー• ⼊⼒値バリデーション• メール作成• メール送信 ←
  • 71. なんということでしょう〜•before 割愛
  • 72. •afteruse Email::Send; Email::Send;my $sender = Email::Send->new({ mailer => Sendmail }); Email::Send- Sendmail Sendmail$sender- send($email)$sender->send($email) or die "send() failed!";
  • 73. CONFIDENTIALありがとうございました。
  • 74. • http://twitter.com/tomita
  • 75. One More• ⼀⽅ロシアは・・・• テスト