Perl CGI 再入門 : 開発環境・変数・use strict・コメント・文字列結合・ヒアドキュメント
大昔にいじっていた Perl CGI スクリプトを発掘した。当時はプログラミングの知識がないまま、色々な CGI スクリプトをコピペして適当に改造していたので、今更ながら Perl の復習をしようかと思う。
目次
開発環境
Perl CGI をコーディング、動作させる環境は以下のとおり。
- MacOS High Sierra
- Apache v2.4.33 (Unix) … MacOS に付属のモノ・Apache で Perl CGI を実行する
- Perl v5.18.2 … MacOS に付属のモノ
- VSCode … エディタ。perl-syntax という拡張機能を入れておくと構文チェックしてくれる
VSCode 拡張機能の perl-syntax と、Apache の error_log
を $ tail -f
で見ながらデバッグすることにし、Chrome ブラウザで実際に動かしながら動作確認することにする。
Apache の設定は以前紹介した記事のとおり。ドキュメントルート直下に CGI ファイルを置いたら、http://localhost/hoge.cgi
とアクセスして動作する前提とする。
まずはとりあえず動かしつつ、変数を使ってみる
まずはとりあえず動かしてみよう。Apache の CGI が動作するディレクトリ配下に test.cgi
というファイルを作り、以下のように書く。
#!/usr/bin/perl
# ↑ Shebang
# HTML として表示させるために書いておく
print "Content-type: text/html; charset=UTF-8\n\n";
# 変数宣言
$text = "ほげほげ";
# 変数を出力する
print $text;
Shebang は MacOS での指定。Linux とかだと #!/usr/local/bin/perl
などだったりするかも。
CGI ファイルには実行権限を付けておく。$ chmod 777 test.cgi
などとしておこう。
このようにコーディングし、ブラウザで http://localhost/test.cgi
にアクセスすれば、ほげほげ
というテキストが出力されるはずだ。
とりあえず $text
と、ドル記号 $
を付けて変数を宣言することは確認できたと思う。コレが配列や連想配列になるとまた記号が変わってくるので、別途説明する。
use strict
で構文チェックを厳格にする
Perl スクリプトの先頭に use strict;
と書くと、厳格な文法チェックが有効になる。コレを入れると、変数宣言を強制し、変数のスコープが厳格になる。
例えば以下のようなコードは、use strict;
なしだと正常に動く。
#!/usr/bin/perl
# eval-if は try-catch 的なモノ。ディレクトリを指定して開く処理
eval {
opendir($dir, "./") or die "Can't open the directory.";
};
if($@) {
print("MyError : $@");
exit 1;
}
# 正常時の処理 : opendir で開いたディレクトリからファイル一覧を取得する
@files = readdir($dir);
# ファイル一覧は配列で取れるので、1つずつ取り出して出力する
foreach $file (@files) {
print $file;
}
# ディレクトリをクローズする
closedir($dir);
このようなスクリプトファイルの先頭に use strict;
を追加すると、次のようなエラーが出る。
Global symbol "$dir" requires explicit package name at /Library/WebServer/CGI-Executables/test.cgi line 18.: /Library/WebServer/CGI-Executables/test.cgi
Global symbol "@files" requires explicit package name at /Library/WebServer/CGI-Executables/test.cgi line 26.: /Library/WebServer/CGI-Executables/test.cgi
Global symbol "$dir" requires explicit package name at /Library/WebServer/CGI-Executables/test.cgi line 26.: /Library/WebServer/CGI-Executables/test.cgi
Global symbol "$file" requires explicit package name at /Library/WebServer/CGI-Executables/test.cgi line 27.: /Library/WebServer/CGI-Executables/test.cgi
Global symbol "@files" requires explicit package name at /Library/WebServer/CGI-Executables/test.cgi line 27.: /Library/WebServer/CGI-Executables/test.cgi
Global symbol "$file" requires explicit package name at /Library/WebServer/CGI-Executables/test.cgi line 28.: /Library/WebServer/CGI-Executables/test.cgi
Global symbol "$dir" requires explicit package name at /Library/WebServer/CGI-Executables/test.cgi line 30.: /Library/WebServer/CGI-Executables/test.cgi
Execution of /Library/WebServer/CGI-Executables/test.cgi aborted due to compilation errors.: /Library/WebServer/CGI-Executables/test.cgi
End of script output before headers: test.cgi
何やら登場する変数全てに対して Global symbol ... requires explicit package name
というエラーが出ている。
Perl で明示的に変数宣言する場合は、my
という予約語を使う必要があるので、次のようなコードに直すと正常に動作するようになる。
#!/usr/bin/perl
use strict;
# ↑ 指定しておく
my $dir;
eval {
opendir($dir, "./") or die "Can't open the directory.";
};
if($@) {
print("MyError : $@");
exit 1;
}
# 正常時の処理
my @files = readdir($dir);
# ファイルを出力する
foreach my $file (@files) {
print $file;
}
closedir($dir);
my @files
や、foreach my $file
などが分かりやすいところだが、変数のスコープでいうと my $dir;
の宣言位置が重要。コレは eval {}
ブロック内で内容を代入後、eval {}
ブロック外にある readdir
や closedir
で使用するので、eval {}
ブロックの外、手前で宣言だけしているというワケ。
この辺は ES2015 以降の const
・let
がスコープを持つようになったのと似ているかな。
- 参考 : 技術的雑談-use strictを使いましょう - Tsubasa's HomePage
use strict;
について
- 参考 : Global symbol "・・・" requires explicit package name at ・・・ - 元気よく。
- 参考 : 第135回 Perlに true, falseなんてない - bingo_nakanishiの他言語出身者のためのPerl入門
true
・false
という Boolean 値がない Perl において、うっかりfalse
とか書いちゃった時に変数扱いせずエラーにしてくれる方法として、use strict;
の使用。
同様に、use warnings;
というモノもあるみたい。コチラは警告を出してくれるようだ。
コメントの書き方2つ
Perl の単一行コメントはシャープ #
記号。記号以降のテキストがコメントとして解釈されるので、コード行の行末に使っても良い。
# 年齢を示す変数です
my $age = 21;
my $name = 'おなまえ'; # ← 名前の変数です
複数行は Perl の POD 機能というモノを使って以下のように実現できる。
=pod
ココに
複数行コメントが
書ける
=cut
たまに記号文字が誤解釈されたりするので、多用はできない。
- 参考 : Perlでの複数行コメント
変数を挟んだ文字列結合のやり方2つ
Perl における文字列結合と、変数の組み合わせ方について。
Perl での文字列は、シングルクォートで囲むモノと、ダブルクォートで囲むモノがある。ダブルクォートの方は変数が展開される。
my $test = 180;
# シングルクォートで囲むと変数展開されない
print '身長は$testセンチです。';
# → 「身長は$testセンチです。」と表示される
# ダブルクォートで囲むと変数展開される
print "身長は$testセンチです。";
# → 「身長は180センチです。」と表示される
通常は上の2つ目の例のように書けばよいが、例えば、変数 $test
の直後に繋がる文字列が英数字だった場合、変数名と誤解釈されてしまう。
print "身長は$testcm です。"
# 「$testcm」という変数を探してしまい、「180cm」とは表示されない
コレを解決するには、文字列結合を使う。
my $test = 180;
print '身長は' . $test . "cm です。";
このように、ピリオド .
で繋げると、文字列と変数を結合できる。JavaScript でいう +
演算子に近い。「身長は」はシングルクォート、「cm です。」はダブルクォートで囲んだ文字列であるが、変数展開されるか否かの違いでしかないので、連結自体には影響がない。
my $test = 180;
print "身長は${test}cm です。";
もう一つのやり方は、変数展開させるためダブルクォートを使い、変数を $test
の形式ではなく ${test}
と書くと、うまくバインドできる。ES2015 でいうテンプレートリテラルに近い。
- 参考 : Perl基礎入門 | KentWeb
ヒアドキュメントを書く方法
Perl でヒアドキュメントを書く方法。
例えば以下のように書いていたモノも…
print "Content-Type: text/html; charset=UTF-8\n\n";
print "Hello <abbr title=\"Common Gateway Interface\">CGI</abbr>";
以下のように書ける。
print <<EOL;
Content-Type: text/html; charset=UTF-8
Hello <abbr title="Common Gateway Interface">CGI</abbr>
EOL
EOL
部分は好きな識別文字に変えられる。
そういえば、Content-Type: text/html; charset=UTF-8
の直後は改行を2つ、空行を開けないといけないのね〜。
変数にヒアドキュメントを入れて print
する時はこんな感じ。
my $test = <<EOL;
<strong>hoge</strong>
<em>fuga</em>
EOL
print $test
# もしくは
print "$test"
割と Bash 風に書けるが、<<EOL;
と、識別文字の宣言直後にセミコロン ;
を付与して print()
関数を閉じる必要がある点に注意。今度また説明するが、関数呼び出しにはカッコを付けても変わらないので、print(<<EOL);
と書いても動作する。だからセミコロンが必要なのだ。
以上
今回はココまで。
自分が経験のある言語と比較すると、Perl は Bash の雰囲気に近く、でも if
ブロックの構文なんかは VBA にも近い感じがあるかな、と思った。配列の操作などは JavaScript にも通じるモノがあり、比較的とっつきやすい感じ。勿論、どっちが先とか、全ての源流の話をし始めると別なのだが、自分が経験してきた順番からこのような比較になっているだけ。
use strict
によって変数宣言やスコープが厳格になるので、自分で書く際には間違いが少なくなる一方、世間的に流通している CGI スクリプトの多くは use strict
が書かれておらず、読みづらいコードが多いなと思う。Strict モードでないことで動いているコードの書き方も多いので、コードの読み方も変わってくるし、参考にしづらい。だからといって Strict モードにしないと、自分が書くコードも分かりづらくなるので、やっぱり Strict は必須かな、と思う。