第3回

Text：情報技研

柔軟なファイル処理を実現する
File::モジュール
CPAN（Comprehensive Perl Archive Network）
は、Perlプログラムとドキュメントの膨大なコレクシ
ョンである。プログラミングに便利な機能を寄せ集めたもので、さしずめ知恵の宝庫といえよう。
本連載では、CPANで4,000個以上提供されているPerlモジュールから便利なものを厳選し、その機能を自分のPerlプログラムから使い、効率よくプログラミングする方法を解説する。

実用的なCGIに必要なファイル処理

http://www.cpan.org/

ォームにメッセージを入力して「書き込み」ボタンをクリックすると、新規メッセージの入力フォームとその下に書き込まれたメッセージ

第2回では、CGI.pmを使ってフォーム入力画面の生成を行い、が表示される。メッセージは新しい順に表示される。メッセージをCGI.pmとJcode.pmモジュールを使ってフォーム入力された結果削除したり、スレッドを立ててツリー表示をさせたりするといった表示をさせるという、フォーム処理の基本を実際に行った。しかし、ことはできないが、サンプルプログラムを拡張すればもちろん対応

CGIプログラムを作成するときには、フォームの作成やパラメータできる。

ーの処理だけでなく、各種のファイル操作なども必要になってくる。そこで、今回はCGI.pmとファイル操作などのモジュールを組サンプルプログラムの構造み合わせて簡易掲示板を作ることで、実用的なCGIプログラミングについて解説していく。

ここで、サンプルプログラムの動作の概略を説明しておく。このサンプルプログラムは、大きく分けると、新規メッセージ入力フ

サンプルプログラム：簡易掲示板

ォームの表示部分、保存されているメッセージ一覧の取得部分、新規メッセージが書き込まれたときの処理部分、メッセージ表示

それでは早速、これまで学んできたCGI.pmやJcode.pmを使処理部分となる。書き込まれたメッセージはメッセージ番号をファった簡易掲示板のサンプルコードを見てみよう（コード1）。

イル名とするファイルとして、「$msgdir」で指定されるディレクトリ

「えっ、これだけ？」と思う読者もいるかもしれない。しかし、実ー内に保存される。4つの処理部分の処理内容を具体的に説明際にこれだけのコード量で掲示板ができる。そして、これまで説明しよう。

してきたとおり、モジュールをうまく使うことで、HTMLタグが入り乱れて非常に見づらいコードになることが避けられている。さらに今回の目玉として、ファイルのパスの指定が異なるウィンドウズ／・新規メッセージ入力フォームの表示部分
前回説明したCGI.pmモジュールによるフォーム表示そのものである。

Unix／Mac OSといった違いも吸収できるようになっている。
実際にサンプルコードの動作例を見よう。初めてこのindex.cgi

・メッセージ一覧の取得部分を実行すると、新規メッセージの入力フォームと「現在のところメメッセージを保存する$msgdirディレクトリーが存在しない場合にはッセージはありません」というメッセージが表示される。ここで、フ新規に作成する。$msgdirディレクトリーの中にあるファイルの一覧を取得し、それを番号の大きい順にリストとして読み込む。

・新規メッセージの入力処理部分
フォーム変数Messageの内容がある場合には、メッセージ書き込みの処理を行う。書き込み処理としては、各変数の文字コードをJcode.pmモジュールを使って統一し（ここではEUCコード）、HTML形式で番号の一番大きいファイル名にメッセージを保存する。

・メッセージ表示処理部分
メッセージを表示する場合は、番号の大きい順に$msgdirの各メッセージを読み出して表示する。メッセージが書き込まれるときにあらかじめHTMLのタグを付けてファイルに保存してあるので、表示するときにはファイルから読み込むだけでいい。
図1

サンプルコードの実行結果

196 +++ iNTERNET magazine 2003.05 +++インターネットマガジン／株式会社インプレスR&D©1994-2007 Impress R&D

コード1

簡易掲示板のサンプルコード（index.cgi）#!/usr/local/bin/perl$title = jcode(param('Title'))->euc;

use CGI qw(:standard);$email = jcode(param('EMail'))->euc;

use CGI::Pretty;
use Jcode;$filename =use File::Spec;

File::Spec->catfile(($msgdir), $msgs);

use File::Path;

open (FILE, ">$filename");use Date::Format;
print FILE##変数設定##/home/www/cgi-bin/msgsを使う

table({border=>1, width=>'90%',$msgdir =bgcolor=>"#F0F0F0"},

File::Spec->rootdir.File::Spec->catdir(

Tr(['home','www','cgi-bin','msgs');td([table(##

入力フォームの表示{border=>0},##

このサンプルプログラムではシンプルな投稿のみを扱う

Tr([printtd([header(-charset=>'x-euc-jp'),"[No.$msgs]",

start_html,$title,h2('簡易掲示板のサンプルプログラム'),'投稿者:'

start_form(-action=>'index.cgi'),.a({-href=>"mailto:$email"},table("$name"),{border=>0},'投稿日:'

Tr([.time2str('%Y/%m/%d %T',time)td(['お名前:',textfield('Name','', 30)]),td(['題 名:',textfield('Title', '', 30)]),])])

td(['E-Mail:', textfield('EMail', '', 30)]),),]),

]),

),

# /td

# /tr

# /table# /td

td(["$msg"]),br('メッセージ:'),]),

textarea('Message', '', 5, 60),),

p,

# /tr

# /table"\n";submit('書き込み'),}reset('リセット'),
end_form,##

メッセージ表示処理

hr;##

メッセージがある場合には単純にファイルを読み込んで表示する

if (!$msgs){##

メッセージ一覧の取得

print h3('現在のところメッセージはありません。');

if (!(-e $msgdir)){mkpath($msgdir, 0, 0755)}}else{

opendir (DIR, $msgdir);for ($i = $msgs; $i > 0; $i--){@filelist =$filename =sort {$a<=>$b} grep (/\d+/, readdir(DIR));

File::Spec->catfile(($msgdir), $i);

$msgs = scalar(@filelist);

open (FILE, $filename);print p,<FILE>;##

書き込み処理}## （フォーム変数 Message が存在するときに処理）}$msg = jcode(param('Message'))->euc;if ($msg){

print end_html;$msgs++;$name =

jcode(param('Name'))->euc;

以上の動作を行うことで簡易掲示板を実現している。HTMLの存しないパスの指定を可能にするFile::Spec.pm、ファイル操作

出力とフォーム変数の処理を楽にするCGI.pm、出力するHTMLを行う F i l e : : P a t h . p m 、日付 文 字 列 の 取 得を簡 単 に 行えるを見やすくする CGI::Pretty.pm、文字コードの変換を行う

Date::Format.pmというモジュールが登場している。それでは、まJcode.pmについてはこれまで説明したが、今回新たに、OSに依ずそれぞれのモジュールについて説明していこう。

インターネットマガジン／株式会社インプレスR&D©1994-2007 Impress R&D+++ iNTERNET magazine 2003.05 +++197

File::Spec.pmモジュール
OS環境に依存しないファイル名操作を行う【カテゴリー】Perlの標準モジュール【バージョン】0.82【作者】Barrie Slaymaker氏【URL】http://search.cpan.org/author/RBS/File-Spec0.82/Spec.pm

File::Spec.pmのココがスゴイ！
updirメソッド
File::Spec.pmは、OSなどの環境に依存せずにパス名の処理親ディレクトリーを表す文字列を返す。

を行うモジュールである。たとえば、Unixではディレクトリー指定【構文】

は「/」で行うが、ウィンドウズでは「¥」となる。こういったOSによFile::Spec->updir

るパスの指定方法の違いを吸収するのがFile::Specモジュールだ。異なるOS間での移植性を高めるときに重宝する。
たとえば、サンプルプログラムでは次のようにしている。
File::Spec->catdir('home','www','cgi-bin','msgs')

これは、Unixでは「home/www/cgi-bin/msgs」に、ウィンドウズ

abs2relメソッド
あるパス（ベースパス）から見た、別のパス（絶対パス）への相対パス名を返す。
【構文】

では「home¥www¥cgi-bin¥msgs」になる。

File::Spec->abs2rel(ベースパス,絶対パス)

File::Spec.pmのメソッド

rel2absメソッド
あるパス（ベースパス）
から相対パス名で示される別のパスを絶対パス名にして返す。

canonpathメソッド
パス名を整形する。たとえば Unix 上の「/root///Mail」を「/root/Mail」に整形できる。

【構文】
File::Spec->rel2abs(相対パス,ベースパス)【構文】

no̲upwardsメソッド

File::Spec->canonpath(path)

ファイル名のリストから、親ディレクトリーとカレントディレクトリーを表すファイル名を取り除く。Unixの場合「..」と「.」が取り除

catdirメソッド
2つ以上のディレクトリー名をディレクトリー区切り文字列で連かれる。

結してパスを生成する。

【構文】

【構文】

File::Spec->no_upwards(files)

File::Spec->catdir(dir[,dir...])

file̲name̲is̲absoluteメソッド
パス名が絶対パスの場合には真、相対パスの場合には偽を返catfileメソッド
1つ以上のディレクトリー名と1つのファイル名をディレクトリーす。

区切り文字列で連結してファイルのパスを生成する。

【構文】

【構文】

File::Spec->file_name_is_absolute(path)

File::Spec->catfile(dir[,dir...], file)devnullメソッド
NULLデバイスを表す文字列を表示する。

rootdirメソッド
ルートディレクトリーを表す文字列を返す。
【構文】

【構文】
File::Spec->devnull

File::Spec->rootdir

tmpdirメソッド
一時ディレクトリー名を返す。

curdirメソッド
カレントディレクトリーを表す文字列を返す。
【構文】

【構文】
File::Spec->tmpdir

File::Spec->curdir

198 +++ iNTERNET magazine 2003.05 +++インターネットマガジン／株式会社インプレスR&D©1994-2007 Impress R&D

File::Path.pmモジュール
ディレクトリーの作成と削除を行う【カテゴリー】Perlの標準モジュール【バージョン】1.05【作者】Tim Bunce氏、Charles Bailey氏【 U R L 】h t t p : / / s e a r c h . c p a n . o r g / a u t h o r / J H I / p e r l 5.8.0/lib/File/Path.pm

File::Path.pmのメソッド

rmtreeメソッド

mkpathメソッド

べて削除する。

ディレクトリーとその中のファイル／ディレクトリーを再帰的にすディレクトリーを作成する。

【構文】

【構文】

rmtree(root,prt,skip)

mkpath(path,prt,perm)

【引数】

【引数】

・root
削除するディレクトリー。その中のファイルとディレクトリーも対象となる。

・path

・prt

作成するパス名

ブール値を指定する。真の場合、削除する個々のファイル名が表示される。デ・prt
ブール値を指定する。真の場合、ディレクトリーを作成するたびにその名前を出フォルトは偽。
・skip

力する。デフォルトは偽。

ブール値を指定する。真の場合、ユーザーが削除権限のあるディレクトリーのみ

・perm
ディレクトリー作成時に使用するパーミッション。デフォルトは0777。

を削除する。デフォルトは偽。

Date::Format.pmモジュール
timeやlocaltimeで得られるデータを任意の文字列形式にフォーマットする

Date::Format.pmモジュールは、timeやlocaltimeなどの関数から得られた時間情報を任意の書式の文字列に変換できる便利な【カテゴリー】データタイプユーティリティー
【バージョン】1.14【作者】Graham Barr氏【URL】http://search.cpan.org/author/GBARR/TimeDate1.14/lib/Date/Format.pm

time2strメソッド
テンプレートに合わせてtime関数の結果をフォーマットする。

モジュールである。Perlの標準モジュールでないため、自分でイ【構文】ンストールする必要がある。

time2str(template,time[,timezone])【引数】

Date::Format.pmのメソッド

・template
フォーマットを指定する。フォーマットの詳細についてはこのモジュールの解説ctimeメソッド

ページを参照。

time関数の結果を"%a %b %e %T %Y¥n"にフォーマットする。このフォーマットの表示例は「Thu Mar 6 04:00:00 2003」
。
【構文】

・time
時間を取得するtime関数を指定する。
・timezone
タイムゾーンの指定。デフォルトはシステムのタイムゾーン。

ctime(time,timezone)

asctimeメソッド

strftimeメソッド

localtime(time)関数の結果を"%a %b %e %T %Y¥n"にフォテンプレートに合わせてlocaltime(time)関数の結果をフォーマーマットする。

ットする。書式はtime2strとほぼ同じ。

【構文】

【構文】

asctime(localtime(time),timezone)

strftime(template,localtime(time),timezone)

インターネットマガジン／株式会社インプレスR&D©1994-2007 Impress R&D+++ iNTERNET magazine 2003.05 +++199

File::Copy.pmモジュール
Unixのcpコマンドやmvコマンドと同様の処理を行う【カテゴリー】Perlの標準モジュール【バージョン】2.05【作者】Aaron Sherman氏【 U R L 】h t t p : / / s e a r c h . c p a n . o r g / a u t h o r / J H I / p e r l 5.8.0/lib/File/Copy.pm

・dest

File::Copy.pmモジュールはサンプルプログラムでは利用していないが、使い慣れた便利なファイル操作の機能を提供するものなのでここで紹介しておこう。

コピー先のファイルを指定する。
・buffersize
コピーに使用するバッファーサイズを指定する。

File::Copyモジュールのメソッド

moveメソッド

copyメソッド【構文】

sourceファイルをdestに移動する。
sourceファイルをdestにコピーする。

move(source,dest)

【構文】

【引数】

copy(source,dest[,buffersize])・source【引数】

移動元のファイルを指定する。
・dest・source

移動先のファイルを指定する。

コピー元のファイルを指定する。

その他の代表的なファイル関連モジュール

これまでに紹介したもの以外にも、ファイル操作関連のモジュFile::Tempモジュールールとして便利なものがいくつかあるので紹介しておこう。どれも一時ファイルや一時ディレクトリーを作る。一時ファイルを作るときにはファイルPerlの標準モジュールなので、ファイル関連の操作をする場合に名とファイルハンドルが同時に返されるのが特徴だ。一時ファイル名をテンプは必要に応じてこれらのモジュールを検討するべきだろう。

レートから作ることもできる。
各メソッドの具体的な動作の違いについては、モジュールの解説ページを参照。

File::Basenameモジュール【 メ ソ ッド 】

ファイル名を解析する。

・tmpdir([template[, option => value])【 メ ソ ッド 】

一時ディレクトリーの作成

・fileparse($fullname,@suffixlist)

・tmpfile([template[, option => value])

File::Compareモジュール

・mkstemps(template);

一時ファイルの作成

2つのファイルの内容を比較する。

一時ファイルの作成【 メ ソ ッド 】

・mktemps(template[, $suffix]);
一時ファイルの作成

・compare_text($file1, $file2)

・mkdtemp(template[, $suffix]);

File::Findモジュール

一時ディレクトリーの作成指定されたディレクトリーからファイルを検索する。
【 メ ソ ッド 】
・find(\&wanted,

・mktemp(template);
一時ファイルの作成
・tmpnam()@directories);

一時ファイルの作成

find(\%options, @directories);・finddepth(\&wanted,@directories);

finddepth(\%options, @directories);

200 +++ iNTERNET magazine 2003.05 +++・tmpfile()
一時ファイルの作成

インターネットマガジン／株式会社インプレスR&D©1994-2007 Impress R&D

Perlモジュールのユーザー環境へのインストール

CPANなどからダウンロードしたPerlモジュールを利用したいホ

すでにCPANの初期設定が済んでいる場合でも、CPANのシストが自分の管理下にない場合（管理者権限を持っていない場ェルを起動してo conf initと入力することで再度初期設定を実行合）があるだろう。サービスプロバイダーのウェブホスティングを利できる。

用している場合など、特にウェブ関係の場合には必ずしも管理者

また、これらのパラメーターは、CPAN.pmモジュールの初期設権限でモジュールのインストールや管理ができるとは限らない。そ定時だけでなく、CPAN.pmモジュールをインタラクティブモードでの場合には、アクセス権限のあるディレクトリー（ユーザーのホー実行して、次のように入力することでも設定できる。具体的には、ムディレクトリーなど）内にモジュールをインストールすることにな「o conf makepl̲arg」で値を設定し、「o conf commit」でオプショる。ここでは、その方法とその場合のモジュールの使用方法につンパラメーターの設定を保存するのだ。
実際に入力するのは太字で示した部分だ。

いて触れておく。
ポイントは、CPANで「perl Makefile.pl」が実行されるときにユーザーのディレクトリーを使うようにパラメーターを設定しておくこと

user@hostname% perl -MCPAN -e shellだ。
第1回では、CPAN.pmモジュールを使ってモジュールのインス

cpan shell -- CPAN exploration and modules

トールを行う方法を説明した。これをユーザー環境で行うために、

installation (v1.48)

CPAN.pmをユーザー環境で実行して初期設定を行う。

ReadLine support available (try ``installuser@hostname% perl -MCPAN -e shell

Bundle::CPAN'')

第1回で解説した初期設定が始まり、ユーザーのホームディレ
クトリー（この例では/home/user）にその設定が保存される。第1cpan> o conf makepl_arg "PREFIX=/home/user

回の解説のとおりに初期化を行うと、システム共通のディレクトリ

LIB=/home/user/lib/perl \ーにダウンロードしたモジュールをインストールする設定になってINSTALLMAN1DIR=/home/user/man/man1 \しまうので、インストール先をユーザーのホームディレクトリー（もINSTALLMAN3DIR=/home/user/man/man3"

しくは書き込み権限のあるディレクトリー）に設定する必要がある。

makepl_arg

PREFIX=/home/user LIB=/

CPAN.pmでの初期設定の途中で次に示すようにMakefile.PL実

home/user/lib/perl INSTALLMAN1DIR=/home/user

行時のパラメーターを設定するところがある。

/man/man1 INSTALLMAN3DIR=/home/user/man/man3

Parameters for the 'perl Makefile.PL' command? []ここで、次のように入力する。

cpan> o conf commit
commit: wrote makepl_arg

PREFIX=/home/user \LIB=/home/user/lib/perl \INSTALLMAN1DIR=/home/user/man/man1 \これで、ユーザー環境へのPerlモジュールのインストールはでINSTALLMAN3DIR=/home/user/man/man3

きた。しかし、各Perlスクリプト中で利用するモジュールを「use」

ここでは、ユーザー「user」のホームディレクトリー「/home/user」

を使って宣言した場合、モジュールの検索は標準のライブラリー下にインストールすることを想定している。それぞれのパラメータパスから行われるため、そのままではユーザー環境にインストール

ーの意味は次のとおりである。

したモジュールは利用されない。そこで、作成する各Perlスクリプ
トについて、明示的にライブラリーのパスを指定する必要がある。
ユーザー環境のパスは次のように行う。ただし、このライブラリー

・PREFIXのパス指定は利用するモジュールのuse宣言の前に置かなけれインストールの基本ディレクトリーばならないということに注意してほしい。

・LIB

モジュールがインストールされるディレクトリー
・INSTALLMAN1DIR##セクション1のマニュアルがインストールされるディレクトリー
・INSTALLMAN3DIR##セクション3のマニュアルがインストールされるディレクトリー

上記LIBで指定したパスを指定する

use lib ('/home/user/lib/perl');
ライブラリーパスの指定の後でuseを指定する

use CGI;

インターネットマガジン／株式会社インプレスR&D©1994-2007 Impress R&D+++ iNTERNET magazine 2003.05 +++201

［インターネットマガジン バックナンバーアーカイブ］ ご利用上の注意
この PDF ファイルは、株式会社インプレス R&D（株式会社インプレスから分割）が 1994 年～2006 年まで発行した月刊誌『インターネットマガジン』の誌面を PDF 化し、「インターネットマガジン バックナンバーアーカイブ」として以下のウェブサイト「All-in-One INTERNET magazine 2.0」で公開しているものです。

http://i.impressRD.jp/bn
このファイルをご利用いただくにあたり、下記の注意事項を必ずお読みください。
z 記載されている内容（技術解説、URL、団体・企業名、商品名、価格、プレゼント募集、アンケートなど）は発行当時のものです。
z 収録されている内容は著作権法上の保護を受けています。著作権はそれぞれの記事の著作者（執筆者、写真の撮影者、イラストの作成者、編集部など）が保持しています。
z 著作者から許諾が得られなかった著作物は収録されていない場合があります。
z このファイルやその内容を改変したり、商用を目的として再利用することはできません。あくまで個人や企業の非商用利用での閲覧、複製、送信に限られます。
z 収録されている内容を何らかの媒体に引用としてご利用する際は、出典として媒体名および月号、該当ページ番号、発行元（株式会社インプレス R&D）、コピーライトなどの情報をご明記ください。
z オリジナルの雑誌の発行時点では、株式会社インプレス R&D（当時は株式会社インプレス）と著作権者は内容が正確なものであるように最大限に努めましたが、すべての情報が完全に正確であることは保証できません。このファイルの内容に起因する直接的および間接的な損害に対して、一切の責任を負いません。お客様個人の責任においてご利用ください。

このファイルに関するお問い合わせ先
All-in-One INTERNET magazine 編集部
im-info@impress.co.jp
Copyright © 1994-2007 Impress R&D, an Impress Group company. All rights reserved.