Perlの最近のブログ記事

今回の LINE API テストにつかった Perl ソース(PSGI 対応)の bot.psgi を載せておく。
API リファレンスに載っているソース例を元に作成した。
前回のエントリーを書いてから、メッセージの出力を追加してるけど)

use strict;
use warnings;
use utf8;
use LINE::Bot::API;
use LINE::Bot::API::Builder::SendMessage;
use Plack::Request;

my $channel_secret = '84xxxxxxxxxxxxxxxxxxxxxxxxxxxxec';
my $channel_access_token = '8sXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcDnyilFU=';

my $bot = LINE::Bot::API->new(
channel_secret       => $channel_secret,
channel_access_token => $channel_access_token,
);

sub {
my $req = Plack::Request->new(shift);

unless ($bot->validate_signature($req->content,
$req->header('X-Line-Signature'))) {
return [200, [], ['bad request']];
}

my $events = $bot->parse_events_from_json(
$req->content);
foreach my $event (@{ $events }) {
if ($event->is_user_event && $event->is_message_event
&& $event->is_text_message) {

my $messages = LINE::Bot::API::Builder::SendMessage->new;
$messages->add_text( text => $event->text );
$messages->add_text( text => 'って言ったのね?');
my $res = $bot->reply_message($event->reply_token,
$messages->build);
}
}

return [200, [], ["OK"]];
};

これで、

20200512_line1.jpg

こんな感じに、ユーザが入力した文字を復唱したあとで、「って言ったのね?」と問いかけるウザい形に(笑)。

ポイントは、use utf8 と宣言して、プログラム内に記述される文字列リテラルがすべて「flagged utf8」(utf8 フラグ有効)になるようにすること。
LINE Messaging API に送る文字列は utf8 フラグ有効にしたものでないと駄目。use utf8 してないと、LINE 画面で文字化けする。

まあ、use Encode 宣言して、ひとつひとつ Encode::decode('utf8', 'って言ったのね?') という具合にしても(多分)一緒だけど。いちいちするのは面倒なので、use utf8 した方がいいだろう。

さて、LINE がらみの提案をしたいお客さんのサーバでは PSGI サーバが使えないので、CGI 版に直してみるかな。

<追記>
ちょっとソースを転記したとき、コピーミスがあったので修正した(2020/05/13 12:00)
いやあ、やっと LINE Messaging API を使った「オウム返し bot」がちゃんと動いた。

試しに Perl でテストプログラムを作ってみようと昨夜手をつけたんだけど、これがなかなかうまく行かなくて(^^;

公式 API リファレンスに載ってるスクリプト例が PSGI(Perl Web Server Gateway Interface)前提になってるんで、CGI 形式になおしてもよかったんだけど、まあ、せっかくなんで PSGI 使ってみようかなっと。その分よけいに時間がかかってしまった(^^;

やることは、

    1. CPAN から Perl モジュールを簡単にインストールするための cpanm のインストール
    2. Plack インストールの前準備(openssl-devel、expat-devel などを yum で入れておく)
    3. Plack(PSGI サーバソフトウェア)のインストール(cpanm で、Task::Plack、XMLRPC::Transport::HTTP::Plack をインストール)
    4. LINE API 関係のモジュールをインストール(cpanm で、LINE::Bot::API をインストール)
    5. Apache に PSGI サーバへのリバースプロキシ設定を追加(https://www.hoge.jp/line_api/ にアクセスがあったら、http://localhost:5000/ に転送・・・みたいな)
    6. API を使うチャンネルを LINE Developersコンソールで作成
    7. チャンネルの設定(基本設定、Webhook やチャネルアクセストークンなど Messaging API の設定)
    8. プログラム作成(GitHub 上の「LINE::Bot::API - SDK of the LINE Messaging API for Perl」にサンプルプログラムあり)
    9. Apache Web サーバ起動
    10. PSGI サーバ起動(例:plackup --max-workers 30 --port 5000 -a bot.psgi&)
    11. LINE でこのチャンネルと友達になる
    12. トーク画面で話しかけて、同じ言葉をチャンネル側が返してくるか確認

って感じ。けっこう色々あるっしょ?

20200511_line1.jpg
これがなかなか大変。Task::Plack のインストールはかなりの数のモジュールがインストールされるので時間がかかるし、「チャンネルの設定」って一行でさらっと書いているけど、アイコンとかチャンネル名とかの基本情報は LINE Official Account Manager で設定するし、Webhook やチャネルアクセストークンの発行などは LINE Developers で行う。どっちで何を設定できるのかよくわからんし、飛んだ先のページからの戻りリンクが無かったり、なんか手間取った。

結局、うまく行かなかったのも、チャネルアクセストークンの発行が正しく行われてなかったからのようだ。ずっとうまく行かなくて悩んでいたのだが、トークンを再発行してプログラムに設定したら、あっけなく上手く行った。

PSGI も初めてだったので、その仕組から調べたので時間がかかった。素直に PSGI のソースを CGI に書き直した方が早かっただろう(笑)
ググっても、ngrok を利用する記事が多くて、最初は PSGI のこともよくわからなかったので、何が何やら(^^;・・・

まあ、そのうち、ルータの内側の PSGI サーバへ外部から直接アクセスするために ngrok というトンネリングサービスを使っていることや、つまりは PSGI サーバは Java の Tomacat みたいなアプリケーションサーバ(のようなもの)なのか・・・とかそういうことがわかってきたので、「うちのテストサーバはグローバルIPアドレス空間にいるので ngrok なんか使わずに、Apache で Reverse Proxy 設定してやればいいだけじゃん」と。そこまで考えが至るにもけっこう時間がかかった(^^;

疲れた(^^;

具体的な設定やプログラムについては追々書いていこう(笑)
もう10年近く前に作ったシステムの移行をしているのだけど、その中に UDP パケットでデータを受け取っているプログラムがある。firewall の設定をしたり、ちょっとだけ新サーバに合わせてそのプログラムの受信部分を修正したので、疎通確認だけでもしときたいなっと。Perl で簡単なプログラムでも作ろうと思ったんだけど、念の為にググってみると、ちゃんとそういうプログラムが公開されているね。


もう、そこに載ってるソースそのまま(スコープがグローバルしかないので、変数宣言の my だけ外すという繊細さを見せてるが(笑)>俺)にコピー。

#!/usr/bin/perl

use Socket;

$ipstr = $ARGV[0];
$port = $ARGV[1];
$msg = $ARGV[2];

$ipaddr = inet_aton($ipstr);
$sockaddr = pack_sockaddr_in($port, $ipaddr);
socket(SOCKET, PF_INET, SOCK_DGRAM, 0);
send(SOCKET,$msg , 0, $sockaddr);

無事、テスト終了。

最近 Perl もあまり触ってないので、これだけのコード書くにも色々調べないと駄目だったと思うので、大変助かりました。ありがとうございます>ProjectLiliO
もう 8年前に作った Perl で書いたシステムを CentOS 9 サーバに移行する。

DBD/DBI を始め、色々と Perl モジュールをインストールしないといけないのだが、まあ、ほとんど yum で入れられるので大した手間ではない。

んが、日本語のコード変換に使用している、

Jcode;
MIME::Words

にはいつも苦労させられる。標準の yum リポジトリに含まれていないからだ。
(Jcode なんか、中で Encode 呼んでるだけなんだから入れなくてもいいやろみたいな素人意見は却下。use Jcode している全ソースを修正する暇も金もない。けっこう巨大なシステムなのである。個人が趣味で作っているシステムとは規模が違うのだよ)

CPAN からなら入れられるが依存関係を潰しながら入れるの大変なので、いつもは yum に RepoForge(旧RPMForge)リポジトリを追加してインストールする。んが、なんと 2016年で RepoForge リポジトリの提供は終わったそうな・・・
「え?この間、サーバ移行したときに使ったけど?」と思ったが、その作業をしたのは 2015年だった(^^;

というわけで、EPEL(Extra Package for Enterprise Linux)リポジトリを使って今回は入れてみる。EPEL は Fedora コミュニティの有志によって作成されたものだ。ありがたや、ありがたや。

・EPELリポジトリの追加

# yum -y install epel-release

・Jcode のインストール

# yum --enablerepo=epel -y install perl-Jcode

・MIME-Words のインストール

EPELリポジトリにも perl-MIME-Words のようなパッケージはない。でも、そう言えば CPAN でインストールするときは install MIME::Words ってやってたけど、MIME-tools-5.XXX.tar.gz とかが読み込まれていたな・・・と。

# yum --enablerepo=epel -y install perl-MIME-tools

ちゃんとインストールされたか確認してみる。

インストール前は use しようとすると、

# perl
use MIME::Words qw (:all);
Can't locate MIME/Words.pm in @INC (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at - line 1.
BEGIN failed--compilation aborted at - line 1.

のように「そんなモジュールは見つからない」と怒られていたが、

# perl
use Jcode;

# perl
use MIME::Words qw (:all);

どちらもエラーは出なくなった。ええがな、ええがな。

ちなみに、そのまま EPEL リポジトリを有効にしていると、標準リポジトリと競合して問題が発生することがあるので、また必要なときまで無効にしておく。

・EPELリポジトリの無効化

以前は直接設定ファイルを触っていたけど、便利なコマンドがあったのね。

# yum-config-manager --disable epel

もし yum-config-manager が入っていなかったら、yum -y install yum-utils で入れる。
リストリファレンス(参照配列)やハッシュリファレンス(参照連想配列)は Perl の鬼門だ。

リファレンス(参照)の考え方を学ぼうとした時、言語が Perl だったら多分理解する前にギブアップすると思う(笑)

Perl は変数の前にシジルと呼ばれる記号を付けて、その変数の種類(という言い方が正しいのかどうなのか)を指定する。これは Perl アンチにとっては「Perl の駄目なところ」だし、Perl 信者にとっては「Perl の良いところ」だ。
まあ、俺は好きだけどね。このお陰で、予約語と変数名がぶつかることがないので。

ちなみに、$ が付いているのがスカラー変数(文字や数値などの一つの値がセットされる変数)、@ が配列(リスト)、% が連想配列(ハッシュ)である。

しかし、これがまた Perl 初心者の人がソースを読む時の障害にもなるんだよねえ。特にリファレンスを使おうとすると、$、@、% などのシジルに加えて、リファレンスの \$、\@、\% や、デリファレンスする時の $$、@$、%$ のようなシジルも出てきてもうわやくちゃ(笑)
シジルだけで、それが配列なのか配列リファレンスなのか理解せえや!の世界だ。
リファレンスとデリファレンスの、どっちが $@ だったか \@ だったかもしばらく使ってないと忘れちゃうしね。

リファレンスの勉強がしたければ C言語とかで学ぶことをオススメします(笑)

で、いつも多重リファレンスの時の書き方アレコレを忘れてしまうので、このブログにメモっとく。

$oya ... 一番大きな配列リファレンス。つまり親。
$ko1 他 ... $oya の要素のひとつとなる配列リファレンス。つまり子。
$mago11 他 ... $ko の要素のひとつとなる連想配列リファレンス。つまり孫。

普通の配列とはリファレンスの宣言は以下のように異なる。

my @array = (); # リスト
my %hash = (); # ハッシュ
my $array = []; # リストリファレンス
my $hash = {}; # ハッシュリファレンス

各リファレンスへの値のセットと抽出の仕方を Perl のコードにしてみる。

    my $oya       = [];   # リストリファレンスの宣言

    my $ko1       = [];   # リストリファレンスの宣言
    my $mago11    = {};   # ハッシュリファレンスの宣言
    my $mago12    = {};   # ハッシュリファレンスの宣言

    my $ko2       = [];   # リストリファレンスの宣言
    my $mago21    = {};   # ハッシュリファレンスの宣言

    $mago11->{'01'} = 'abc';   # ハッシュリファレンス mago11 に値をセット
    $mago11->{'02'} = 'def';   #  〃
    $mago11->{'03'} = 'ghi';   #  〃

    $mago12->{'01'} = 'jkl';   # ハッシュリファレンス mago12 に値をセット
    $mago12->{'02'} = 'mno';   #  〃

    push @$ko1, $mago11;       # 子リストリファレンスに孫ハッシュリファレンスを push
    push @$ko1, $mago12;       #  〃

    $mago21->{'01'} = 'pqr';   # ハッシュリファレンス mago21 に値をセット
    $mago21->{'02'} = 'stu';   #  〃
    $mago21->{'03'} = 'vwx';   #  〃

    push @$ko2, $mago21;       # 子リストリファレンスに孫ハッシュリファレンスを push

    push @$oya, $ko1;          # 親リストリファレンスに子リストリファレンスを push
    push @$oya, $ko2;          #  〃

    # 親リストリファレンスから子リストリファレンスの抽出
    # リファレンスの要素数を確認するには、デリファレンスしてスカラー値を取得
    for ($i = 0; $i < scalar(@$oya); $i++) {

        # 一時リストリファレンスに子リストリファレンスをセット
        my $array    = [];
        $array       = $oya->[$i];

        # 子のリストリファレンスから孫ハッシュリファレンスを抽出
        # リファレンスの要素数を確認するには、デリファレンスしてスカラー値を取得
        for ($j = 0; $j < scalar(@$array); $j++) {

            # 一時ハッシュリファレンスに孫ハッシュリファレンスをセット
            my $hash    = {};
            $hash       = $array->[$j];

            # keys でハッシュキーを抜き出すには、デリファレンスする
            foreach $key(keys %$hash) {

                print "キー=" . $key . " 値=" . $hash->{$key} . "\n";

            }

        }

    }

ちなみに、上記コードではリファレンスしか使っていないが、通常の配列(リスト)に連想配列(ハッシュ)をセットするには、セットするハッシュをリファレンス化する。

    my @ko1       = ();   # リストの宣言
    my %mago11    = ();   # ハッシュの宣言
    my %mago12    = ();   # ハッシュの宣言

    $mago11{'01'} = 'abc';   # ハッシュ mago11 に値をセット
    $mago11{'02'} = 'def';   #  〃
    $mago11{'03'} = 'ghi';   #  〃

    $mago12{'01'} = 'jkl';   # ハッシュ mago12 に値をセット
    $mago12{'02'} = 'mno';   #  〃

    push @ko1, \%mago11;     # ハッシュリファレンスとしてセット
    push @ko1, \%mago12;     # ハッシュリファレンスとしてセット

    foreach $ko(@ko1) {      # リストからハッシュリファレンスを1件読み出し

        # keys でハッシュキーを抜き出すには、デリファレンスする
    foreach $key (keys %$ko) { 

            print "キー=" . $key . " 値=" . $ko->{$key} . "\n";

    }

    }

こんな感じ。

俺的には最初から最後までリファレンスで処理するのが好み。リファレンスにしたりデリファレンスしたりしてるとわけわかんなくなる(^^;
UTF-8 で入出力している Web システムがあるんだけど、最終的に Winodows PC ベースのシステムにデータ持ち込んで印刷してるんで、Shift_JIS(てか、CP932だな)に変換できない文字は入力エラーにしてほしいという要望が。

元々、UTF-8 の 3バイト文字で 0xE28480 から 0xE38FBE までの文字(例外あり)は入力制限してたんだけど、もう少し厳密に・・・という話。

予算的に自前の変換表作ってというのは厳しいので、なんか良いものがないかなあと探してたんだけど、Perl の Encode::from_to メソッドが使えそう。

これ、Encode モジュールのメソッドで、

Encode::from_to( $text, "UTF8", "Shift_JIS");

と書けば、変数 $text の内容を UTF-8 から Shift JIS に変換してくれるんだけど、ここにオプション XMLCREF をつけると、変換できなかった文字(UTF-8 に有って、Shift JIS に無い文字)を数値文字参照コードで出力してくれる。

例えば「ハシラダカ」と呼ばれる「髙」の文字は Shift JIS には無いので、「髙林」を

Encode::from_to( $text, "UTF8", "Shift_JIS", Encode::XMLCREF );

という具合に変換してやれば、

&#x9ad9;林

という結果が $text にセットされる。&#x9ad9; が数値文字参照コードね。
ちなみに、Windows 拡張版の Shift JIS(Windows-31j)であれば「ハシラダカ」も文字セットに含まれているので、

Encode::from_to( $text, "UTF8", "CP932", Encode::XMLCREF );

であれば、そのまま「髙林」が結果に返ってくる。
もちろん、Windows-31j に含まれていない文字は数値文字参照コードで返ってくる。

もう、これでいいんじゃね?(笑)

変換後の文字を↓こんな風にチェックして、'OK'、'NG' を返してやる API を作れば、多言語で作成した Web システムからも呼べるしね。

if ($text =~ /\&\#[^\;]+\;/) {
    return('NG');
}
return('OK');

いやあ、Perl 良いわあ。
セキュリティとか考えても、実際、こういう枯れた技術を使うのは '吉' なんだけど、ま、チーム開発のやりやすさとか、メーカーからの公式サポートとか、他にも理由があって Java とか VB.NET とかになっちゃうんだろうけど。
久しぶりに DB データが「ハッシュの配列」にセットされまくってる感じの Perl プログラムのメンテを行うことになったので、ハッシュ(連想配列)のリファレンスなどについてメモ。

まあ、Perl の多次元配列については、木本裕紀さんの「Perl学習サイト - サンプルコードPerl入門」サイトの中の「配列とハッシュで多次元データ構造を自由に操る」がそのまま参考になる。

なので、ここで書いているのはその補足。

ハッシュ(連想配列)を配列にセットした、いわゆる「ハッシュの配列」を扱う場合。

下のコードは、PostgreSQL から取得したデータをセットしてる例(余分な処理は削ってるので、「例外に対する処理が甘い」とか、そういうツッコミはなしで(笑))

@persons = ();

# DB から $sql の条件でデータ取得(例えば、クラス名簿とか)
$result = $Conn->exec($sql);
if (!$result->resultStatus eq PGRES_TUPLES_OK) {
# DB エラーなら処理を抜ける
exit;
}

# 人数分データを読み込む
for ($i = 0 ; $i < $result->ntuples ; $i++) {
# DB から取得した名前、性別、年齢をハッシュにセット
my %person = ();
$person{'name'} = $result->getvalue($i, $result->fnumber(name));
$person{'sex'} = $result->getvalue($i, $result->fnumber(sex));
$person{'age'} = $result->getvalue($i, $result->fnumber(age));
# ハッシュを配列にセット
push @persons, \%person;
}

これで、クラス名簿が「ハッシュの配列」にセットされる。

全員のデータを読みだそうとしたら、

foreach $person (@persons) {
foreach $key (keys %$person) {
$value = $person->{$key};
print "$key : $value\n";
}
}

こうすれば抜き出せる。

結果は、

name : Masunori
sex : m
age : 23
name : Beiko
sex : f
age : 44
.....
name : Taro
sex : m
age : 18

こんな風に表示される。

では、全件出力するのではなく、最初の人のデータだけ読み出したいって場合。
例えば、一人目の人の性別を確認とか。

ポイントは、「ハッシュの配列」はただの配列ではなく、実際は「ハッシュのリファレンス」を要素に持つ「配列のリファレンス」ということ。
そのため、@persons を参照するには @$persons のように配列のデリファレンスを行なう必要あり。

print @$persons[0]->{'sex'};

このように書けばいいのね。これで「m」という結果が表示される。
以前、俺が Perl で書いた API プログラムについて「別サーバに移したら DBI モジュールが無くて動かないみたいなのでヨロシク」・・・という指示がお客さんからあったので対応。

CentOS サーバなのだが、

# perl
use DBI;
Can't locate DBI.pm in @INC (@INC contains: /usr/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi /usr/lib/perl5/site_perl/5.8.8 <略> .) at - line 1.
BEGIN failed--compilation aborted at - line 1.

確かに DBI モジュールがインストールされていないようなので入れる。

このサーバ、ローカルネットワークの外には出れないようになっているので、インターネットに接続できる Windows PC でダウンロードしたファイルをサーバに SFTP アップして作業をする。

取ってくるファイルは、最新のアーカイブ。
CPAN サイト
から、DBI-1.636.tar.gz をダウンロードし、サーバに上げて以下作業を行った。

# tar xvfz DBI-1.636.tar.gz
DBI-1.636/
DBI-1.636/Changes
DBI-1.636/dbd_xsh.h
DBI-1.636/DBI.pm
<略>
DBI-1.636/ex/corogofer.pl
DBI-1.636/ex/perl_dbi_nulls_test.pl
DBI-1.636/ex/profile.pl
# cd DBI-1.636
# perl Makefile.PL

*** Your LANG environment variable is set to 'ja_JP.UTF-8'
*** This may cause problems for some perl installations.
*** If you get test failures, please try again with LANG unset.
*** If that then works, please email dbi-dev@perl.org with details
*** including the output of 'perl -V'

Your perl was compiled with gcc (version 4.1.2 20080704 (Red Hat 4.1.2-55)), okay.
Creating test wrappers for DBD::Gofer:
t/zvg_01basics.t
<略>
Checking if your kit is complete...
Looks good
Warning: prerequisite ExtUtils::MakeMaker 6.48 not found. We have 6.30.
Warning: prerequisite Test::Simple 0.90 not found. We have 0.62.

    I see you're using perl 5.008008 on x86_64-linux-thread-multi, okay.
    Remember to actually *read* the README file!
    Use  'make' to build the software (dmake or nmake on Windows).
    Then 'make test' to execute self tests.
    Then 'make install' to install the DBI and then delete this working
    directory before unpacking and building any DBD::* drivers.

Writing Makefile for DBI

ExtUtils::MakeMaker
Test::Simple
この2つのバージョンが古いって警告(Warning)が出てるけど、この2つを入れ直そうとすると依存関係すごそう(^^;
上に書いたように、依存関係のあるモジュールについても一個一個手動インストールするしかないんで、「ま、Warning なんで・・・」と、とりあえず無視してインストールしちゃう。

# make
<略>
Manifying blib/man3/DBI::DBD.3pm
Manifying blib/man3/Win32::DBIODBC.3pm
Manifying blib/man3/DBI::DBD::SqlEngine.3pm
Manifying blib/man3/DBI::PurePerl.3pm
Manifying blib/man3/DBI::ProfileData.3pm

特にエラーは出てない。問題なく make できたっぽいなあ。
まあ、make test は予想どおりボロボロですけど。

# make test
<略>
Failed Test                    Stat Wstat Total Fail  Failed  List of Failed
-------------------------------------------------------------------------------
t/06attrs.t                     255 65280    ??   ??       %  ??
t/08keeperr.t                   255 65280    ??   ??       %  ??
t/10examp.t                     255 65280   238  476 200.00%  1-238
t/42prof_data.t                 255 65280    31   58 187.10%  3-31
t/48dbi_dbd_sqlengine.t         255 65280    ??   ??       %  ??
<略>
t/zvxnp_52dbm_complex.t         255 65280    ??   ??       %  ??
t/zvxnp_85gofer.t               255 65280    ??   ??       %  ??
32 tests and 225 subtests skipped.
Failed 74/194 test scripts, 61.86% okay. 1010/4579 subtests failed, 77.94% okay.
make: *** [test_dynamic] エラー 255

ずいぶんエラーが発生しているけど、

t/zvp_10examp.t                 255 65280   238  476 200.00%  1-238

のように、全テスト件数が 238 なのに、faild になったエラーが 476件あって、エラー発生率 200%というおかしなものも混ざっているので、とりあえず無視。

インストールしてみる。

# make install
Installing /usr/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi/auto/DBI/DBIXS.h
Installing /usr/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi/auto/DBI/Driver.xst
Installing /usr/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi/auto/DBI/DBI.bs
<略>
Installing /usr/bin/dbiprof
Installing /usr/bin/dbilogstrip
Writing /usr/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi/auto/DBI/.packlist
Appending installation info to /usr/lib64/perl5/5.8.8/x86_64-linux-thread-multi/perllocal.pod

まあ、インストールはファイルのコピーするだけだからイクわな。

# perl
use DBI;

とりあえず、エラーは出なくなった。
次は DBD::Pg モジュールのインストール。
PostgreSQL インストールして DBI と DBD::Pg の2つの Perl モジュールをインストール。

もちろん cpan でささっと・・・と行きたいが、相変わらず DBD::Pg は cpan じゃ make test が引っかかってうまくいかないな(^^;

これ、うまくいくケースってあるの?

もう、20年近く(Pg.pm の時代から)DBD::Pg インストールしてきたけど、一回もすんなり cpan コマンド一発でインストールに成功したことないんだけど(^^;
多くの人の環境でエラーになるような test なら意味ないと思うんだけど?
少なくとも、cpan の手順からだけでも make test なんか抜いてしまえばいいんじゃないかと・・・

ま、そりゃ無理なんだろうけどさ。

というわけで、いつものように make test だけ吹っ飛ばすよう手作業でインストール。

# cp /root/.cpan/sources/authors/id/T/TU/TURNSTEP/DBD-Pg-3.5.3.tar.gz ~postgres
# chown postgres ~postgres/DBD-Pg-3.5.3.tar.gz
# su - postgres
$ tar xfzp DBD-Pg-3.5.3.tar.gz
$ cd DBD-Pg-3.5.3
$ perl Makefile.PL
$ make
$ exit
# cd /usr/local/pgsql/DBD-Pg-3.5.3
# make install

で、OK。

パスを通して、一般ユーザで試しに使ってみる。

$ PATH=$PATH:$HOME/bin:/usr/local/pgsql/bin
$ export POSTGRES_HOME=/usr/local/pgsql
$ export PGDATA=$POSTGRES_HOME/data
$ export PGLIB=$POSTGRES_HOME/lib
$ export LD_LIBRARY_PATH=$POSTGRES_HOME/lib
$ perl
use DBD::Pg;
Can't load '/usr/local/lib64/perl5/auto/DBD/Pg/Pg.so' for module DBD::Pg: libpq.so.5: 共有オブジェクトファイルを開けません: そのようなファイルやディレクトリはありません at /usr/lib64/perl5/DynaLoader.pm line 190.
 at - line 1.
Compilation failed in require at - line 1.
BEGIN failed--compilation aborted at - line 1.

あかんやん。「libpq.so.5: 共有オブジェクトファイルを開けません」でググったら、俺のこのブログが最初にヒットした(^^;


毎回、同じことで引っかかとるんやあ(^^;;

root で、

# chmod 755 /usr/local/pgsql

として、

$ perl
use DBD::Pg;
^D

なんのエラーも出ない。ばっちりやん(笑)

手動インストールに使ったファイル消しとこ。

$ \rm -R DBD-Pg-3.5.3
rm: 書き込み保護されたファイル 通常ファイル `DBD-Pg-3.5.3/blib/lib/DBD/Pg.pm' を削除しますか?y
rm: 書き込み保護されたファイル 通常ファイル `DBD-Pg-3.5.3/blib/lib/Bundle/DBD/Pg.pm' を削除しますか?y
$ \rm DBD-Pg-3.5.3.tar.gz

いやあ、今回は、shinodaさんの「電気ウナギ的○○」というサイトがすごく役に立った!!(笑)
先月から今月にかけて、夜間や休みの日に、古い(それこそ10年くらい前に作ったものとか)Perl CGI のソースの修正をしてて、まあ、自分で作ったものはなんとかなるんだけど、外注さんに頼んで作ったものとか、自分のやり方とは違ってたりしてハマるわぁ(^^;

例えば、俺はテンプレートの HTML ファイルに動的な値を貼り付ける時に自前で処理を書くんだけど(まあ、正規表現で値を書き込む箇所のマーカーになる文字列見つけて置換するだけだし)、以前よく使っていた外注さんは HTML::Template モジュールを使っていた。
PHP の Smarty みたいな高機能テンプレートエンジンね。

テンプレートエンジンを使うと、ちょっとした HTML のデザイン変更の時にプログラムソースに手を入れなくても HTML テンプレートだけ直せばどうにかなるので便利なことも多いんだけど、うちの仕事だと「どっちみちプログラムも直さないといけないケース」が多いんで、結局「プログラム修正」「HTML::Template のルールに沿ったテンプレートの修正」の両方が発生しちゃうからあんまり工数の削減や修正のしやすさにつながらないんだよね。
テンプレートエンジン厨の怨嗟の声が聞こえてきそうだけど(笑)

テンプレートエンジンに限らず、こういうのを使う/使わないはケース・バイ・ケースなのよ。使った方がいいのに使わないのも愚かだけど、どんなケースでも、常に HTML::Template モジュールを使うというのも愚かなこと。

ま、そういうわけで、俺自身は「別に使わなくていいんじゃないの」というケースが多いから、今まで使ったことがほとんどなくて(まったく無いわけじゃないけど)、たまに使うと(って、ほとんど他人が作ったもののメンテナンスだけど)下らないことでハマっちゃうんよね(^^;

今日も、仕様変更にともなってテンプレート HTML の不要な部分をバサッと削ったら、いきなり Internal Server Error が出始めて、なんじゃ?とログを見たら・・・

[Sat Feb 13 18:13:42 2016] [error] [client 202.XXX.XXX.XXX] HTML::Template->new() : found </TMPL_LOOP> with no matching <TMPL_LOOP> at template.html : line 133! at HTML/Template.pm line 1558., referer: http://exsample.co.jp/cgi-bin/hogehoge.cgi
[Sat Feb 13 18:13:42 2016] [error] [client 202.XXX.XXX.XXX] Premature end of script headers: hogehoge.cgi, referer: http://exsample.co.jp/cgi-bin/hogehoge.cgi

ああ・・・<TMPL_LOOP> と </TMPL_LOOP> がアンマッチだとおっしゃってる(^^;

確かに、

<!--tmpl_loop name="hogehoge_list"-->
 ~ほげほげ~
<!--/tmpl_loop-->

の、

<!--tmpl_loop name="hogehoge_list"-->

だけ消して、

<!--/tmpl_loop-->

が残ってるわぁ(^^;気づかんかった(^^;

で、素直に修正すればよかったんだけど、あんま日頃 HTML::Template モジュール使わないんで、Template クラスをインスタンス化する時、

my $template = new HTML::Template(
filename => $filename,
die_on_bad_params => 0,
path => DEF_TMP_DIR
);

みたいに die_on_bad_params オプションに 0 を与えておけば、エラーは全て無視をしてベストエフォートな実行をしてくれるのだと思い込んでて、なんかインスタンス化のオプションの組み合わせがおかしいんじゃないかとか、変なところで悩んでハマってしまった(^^;

die_on_bad_params は読んで字のごとく、「テンプレートで定義していないパラメータを処理しようとしても無視する」ってだけのことなのね(^^;
つまり、hoge というパラメータで指定された部分を置換しようとした時、実際にはテンプレート上に

<!--tmpl_var name="hoge"-->

という記述がなければエラーになるけど、それを無視するってだけのオプション・・・
さすがに、「ループの終了はあるのに、ループの開始は無い」ようなエラーまでは無視してくれんか(^^;

エラーメッセージやマニュアルの記述は、素直に言葉通りに解釈せよということですな(^^;

という反省エントリーでありました(笑)

このアーカイブについて

このページには、過去に書かれたブログ記事のうちPerlカテゴリに属しているものが含まれています。

前のカテゴリはAIR/Flexです。

次のカテゴリはPHPです。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。


月別 アーカイブ

電気ウナギ的○○ mobile ver.

携帯版「電気ウナギ的○○」はこちら