Perl−Tips

ホーム(戻る) 最終更新日H11.09.17
目  次
はじめに
パールのインストール
自動リロードのためのメタタグの設定
配列のソート
テキストブロックの効果的な使い方
ファイルのパーミッション
パール慣用句・使用例一覧
CGICONST cgiconst.pl の説明
CGISUBS cgisubs.pl の説明
全環境変数の表示
ファイルのアップロード

▲ 頁トップ  ホーム
はじめに
 このページでは、パールスクリプトについて気が付いたことをその都度書き加えていく予定です。

▲ 頁トップ  ホーム
パールのインストール
  1. パールのサポートページにジャンプし pl32b316.zip またはそれ以降の最新版をダウンロードします。

  2. ダウンロードした pl32b316.exe をダブルクリックし、インストールを開始します。

  3. 途中でインストール先等を聞いてきますから、質問に答えて適当な解凍先(インストール先フォルダ)を指定します。デフォルトの設定(c:\perl)が一番楽です。

  4. Apache のサーバを用いるときは Apache をインストールしたドライブ(例えば C: )に C:\usr\local\bin というディレクトリを作り、そこに perl.exe と perl300.dll の二つのファイルをコピーしておきます。

  5. OmniHPTTd のサーバを用いるときは global settings 中の external を開き、perl.exe のパスを以下のように書き換えます。(Perl が実際に存在するパスを記述して下さい。)

     c:/perl/bin/perl.exe

     パールのインストール先にデフォルトを指定してる場合はここでの処理は不要です。

▲ 頁トップ  ホーム
自動リロードのためのメタタグの設定
 ページを自動更新するメタタグのサンプル(例えば15秒後に new_page.html にジャンプする)は以下の通りですが、

<html>
<head>
<META HTTP-EQUIV = "Refresh" CONTENT= "15;URL=new_page.html">
<title>FayWay/CGI-Tips</title>
</head>
<body>

この記述をCGIで自動作成するときは注意が必要です。下のサンプルを参考にして下さい。

$time =15;
$metastr = "<META HTTP-EQUIV = \"Refresh\" CONTENT= \"$time;URL=$cgi_url?$hikisuu\">";


▲ 頁トップ  ホーム
配列のソート
  1. ファイル名をソートするときの基本構文は<サンプル1>のようになります。しかし、この構文を用いると、UNIXは一般的に大文字と小文字を区別しますから、Zのほうがaよりも先になり、ソートした意味が半減してしまいます。

     <サンプル1>

     @result = sort @fnames;


  2. そこで、大文字と小文字を区別せずにソートを行うときは次の構文を使います。$a と $b を細工して、両者を比較するときだけ大文字揃えを実行しています。

    by_name はソート手法を定義するサブルーチンで、名前(by_name)は各自自由に付けます。

    引数 $a と $b はデフォルトであり変更できません。

     <サンプル2>

     @result = sort by_name @fnames;

     sub by_name {
     "\U$a\E" cmp "\U$b\E";
     }

    なお、$a と $b を入れ替えれば("\U$b\E" cmp "\U$a\E")逆順のソートとなります。

    また、単に逆順でソートしたい場合等サブルーチンを作る必要もないときは以下のように簡略化した記述もできます。

     @result = sort {$b cmp $a;} @fnames;

  3. 数の大小でソートを行うときは次の構文を使います。

    by_num はサブルーチンで、名前は適当で構いません。

     <サンプル3>

     @result = sort by_num @log1;

     sub by_num {
     $a <=> $b;
     }

    この場合も、$a と $b を入れ替えれば逆順のソートとなります。



▲ 頁トップ  ホーム
テキストブロックの効果的な使い方

(1)一行づつプリント命令を記述する

print "Content-type: text/plain\n\n";
print "サンプル\n";
print "・・・\n";

(2)一度変数に代入して、一気にプリント

$outstr = <<EMARK;
Content-type: text/plain

ここから本文
Content と本文の間には空行が必要です。(改行を2回行うルールです)
・・・
EMARK
print "$outstr";

(3)プリントコマンドに直接使う

print <<END_;
Content-type: text/plain

ここから本文
Content と本文の間には空行が必要です。(改行を2回行うルールです)
・・・
END_


▲ 頁トップ  ホーム
CGICONST
cgiconst.plダウンロード表示

 この cgiconst.pl ファイルは各ウェブサーバ毎に異なる広域固有変数をセットし、一般のパールスクリプトでは変数(例えば $homeURL )の方を使用します。

 この例では自宅のローカルホスト用設定値が有効になっていますが、プロバイダ(Hi−Ho)のサーバにアップロードするときは、注釈行化されているプロバイダ用の設定値を有効にしてください。

 この設定により、パールの記述は統一され、各ウェブサーバ間で共用できるようになります。

 すなわち、一般のパールスクリプトで例えば $homeURL を参照していれば、ローカル、Hi−Hoのそれぞれのホストで適切な値を自動設定でき、ローカルでテストしたファイルをそのままHi−Hoにアップロードできます。


▲ 頁トップ  ホーム
CGISUBS
cgisubs.plダウンロード表示

 この cgisubs.pl ファイルはパールでよく使うサブルーチンを集めたものです。

<サブルーチンコールの書式>

(1)一般のフォームデータ取得

%form = &getFormData;

  • 変換後の漢字コードは”EUC”

  • マルチセレクトのセパレータは "\0" (アスキーコードがゼロの文字)

  • 1999/05/05 マルチパート用フォームデータの読込機能を追加

     アップロードしたファイルの名称(不定、例えば sample.gif)はファイルフォームの名称(既知、例えば 'file1')をキーとする $form{'file1'}に代入され、ファイルの内容はフォーム名称にアンダースコアを付けた $form{'file1_'} に代入される。以下のサンプル参照
      $file1_name = $form{'file1'};
      $file1_data = $form{'file1_'};

     ファイルデータ $file1_data はバイナリデータの場合があるので \n \r の処理には注意を要する。これらはフォームデータを受け取った側で処理する。

  • マルチパートフォームデータの送信時の書式は以下の通り

    <form method=post enctype="multipart/form-data" action="???.pl">

(2)HTMLタグを排除したフォームデータの取得

%form = &getReplacedFormData;

  • 変換後の漢字コードは”EUC”

  • <は&lt;に置換されます。

  • 入力データの最大値も設定されています。
    ( $max = 4096; # 最大受信データ量(バイト数))

(3−1)一般のエラー表示

&errorDisp( $str[, $title]);

  • $str:表示用文字列

  • $title:表示用文字列のタイトル、省略可(デフォルトは”エラー”)

(3−2)エラー表示2

&errorDisp2( $title, $errorMsg);

  • $errorMsg:表示用エラーメッセージ

  • $title:表示タイトルの一部、省略不可

    「$titleできませんでした。」と表示される

     $title の例:読込、処理、変更・・・

(3−3)メッセージ表示

&showResult(@list);

  • @list:表示用メッセージのリスト(配列)

(4−1)10進数のOCT(8進)表記

$result = &octstr( $num [, $keta [, $fillchar]]);

  • $num:変換前の10進数

  • $keta:変換後の文字桁数

  • $fillchar:指定文字桁数の前部空白を埋める文字、0又はスペース、その他、省略可(デフォルトは”0”)

(4−2)10進数のHEX(16進)表記

$result = &hexstr( $num [, $keta [, $fillchar]]);

  • $num:変換前の10進数

  • $keta:変換後の文字桁数、1バイトの数値は2文字、2バイトの数値は4文字に変換される、省略可(デフォルトは2文字)

  • $fillchar:指定文字桁数の前部空白を埋める文字、0又はスペース、その他、省略可(デフォルトは”0”)

(5)完全ファイル名をパス名、基本ファイル名、拡張子名に分解する

@result = &splitFileName($fullname);

  • $fullname : 完全ファイル名

  • @result は("パス名=$path ","基本ファイル名=$base ","拡張子名=$ext ") からなる配列。

(6)配列を検索し最初に見つけた配列要素のインデックス(序数)を返す

$result = &listIndex('$target', @list);

  • $target : 検索式、正規表現をシングルクォーテーションで挟む。例 '^abc' 

  • @list : 被検索リスト

  • 見つからないとき、及びエラーのとき -1 を返す。

(7)バイナリ時刻データを所定フォーマットのテキストデータに変換する

$result = &getTimeStr($time [,$pattern]);

  • $time : バイナリ時刻データ

  • $pattern : セパレータセット(サンプル "/"、"-")

(8−1)テキストファイル保存

$result = &saveTextData($filename, @data);

  • $filename : ファイル名

  • @data : 書込データリスト

(8−2)テキストファイル読込

@lines = &readTextData($filename);

  • $filename : ファイル名

  • @lines : 読込テキストデータ

(9)HTTP用URLをホスト名、ポート番号、ファイル名に分解する

($host, $port, $file) = &splitURL($URL);

  • $URL : URL

  • $host : ホスト名

  • $port : ポート番号

  • $file : ファイル名

(10−1)フォームデータのURLエンコード

$result = &encodeUrlData($data);

  • $data : エンコード前のURLデータ

(10−2)フォームデータのURLデコード

$result = &decodeUrlData($encodedData);

  • $encodedData : URLエンコードされたデータ


▲ 頁トップ  ホーム
全環境変数の表示
 環境変数はホストコンピュータ毎に異なりますから(例えば契約プロバイダ毎に、またはローカルホスト毎に、利用できる環境変数は異なります)、CGIで環境変数を利用するときは予めそのホストコンピュータで利用できる環境変数を確認しておく必要があります。

<サンプル>利用できる全環境変数の表示

#!/usr/local/bin/perl
# 全環境変数表示
print "Content-type: text/plain\n\n";
while (($key,$value)=each %ENV) {print "$key = $value\n";}
print "\n\n";



▲ 頁トップ  ホーム
ファイルのアップロード
(1)アップロード表示テスト

 <スクリプト1>はアップロード用のフォームがどのようなデータをCGIに送るのかを表示するテストプログラムです。また、<サンプル1>はこのテストプログラムを呼び出すフォームサンプル、<HTML1>はそのHTMLスクリプトです。このフォームはひとつの hidden タイプとふたつの file タイプから構成されています。

 <スクリプト1>

#!/usr/local/bin/perl
# 漢字コード:EUC
#==========================================================
# FileUploadTest (upldtest.pl) written by T.Hamano 1998
# 更新履歴
# 1998/09/28 ver1.00 最終テスト終了
#==========================================================

# データ読込 ==========================================
binmode(STDIN);
read(STDIN, $data, $ENV{'CONTENT_LENGTH'});

# データ表示
print <<_TEXT_;
Content-type: text/plain

$data
_TEXT_
exit;
# end of script

<サンプル1>


 File 1:

 File 2:

 


<サンプル1スクリプト>

<form method=post enctype="multipart/form-data" action="/cgi-bin/user/hamano/upldtest.pl">
 <input type=hidden name=pass value=$pass>
 File 1: <input type=file name="file1" size=50><br>
 File 2: <input type=file name="file2" size=50><br>
 <input type=submit value=" Upload "></form>

<アップロードデータサンプル>
-----------------------------95331376226751
Content-Disposition: form-data; name="pass"

012345
-----------------------------95331376226751
Content-Disposition: form-data; name="file1"; filename="C:\OHTTPD\CGI-BIN\UPLOAD\TEST.TXT"
Content-Type: text/plain

line1
line2
-----------------------------95331376226751
Content-Disposition: form-data; name="file2"; filename=""


-----------------------------95331376226751--

(2)データのデコード
 最新 cgisubs.pl を使えば普通のフォームデータと同一手続きでファイル名とファイルデータを取得できるようになりました。CGISUBSの説明参照

 データはひとつの input コマンドに対し、対応するファイル名等の識別データ(ヘッダ)およびファイルのボディ(または value )を一組とし、所定の複数組がセパレータで挟まれた状態で送られてきます。そしてヘッダとボディの区切りは例により「連続する2つの改行」(\n\n)です。

<スクリプト2>はデコード、パスワードチェック、ファイル書込、パーミッションの設定を一気に行うサンプルスクリプトです。

 hidden データはアップロード先の指定に割り当てるのも有用だと思います。

<スクリプト2>

# データのデコード ====================================
$line_end_code = "\n";
$len = index($data, $line_end_code);
$separator = substr($data,0,$len);
if ($separator =~ /\r$/) {
$line_end_code = "\r\n";
chop($separator);
}
$header_end_code = $line_end_code x 2;
@files = split(/$separator/,$data);
pop(@files);
shift(@files);

# パスワードを取得
$file = shift(@files);
$len = index($file,"$header_end_code");
$code_len = length($header_end_code);
$pass = substr($file,$len+$code_len);
chop($pass);
if ($code_len >2){chop($pass);}

# タイムオーバ&パスワードチェック
if (time > (stat("$datafile"))[9]+60*60*1) {&error_disp("認証","タイムオーバ、ログイン画面に戻って下さい。");}
if ($pass ne $pass2) {&error_disp("認証","パスワードが不正です。");}

# ファイル転送実行
foreach $file(@files) {
$len = index($file,"$header_end_code");
$header = substr($file,0,$len);
if ($header =~ /\\/) {
@temp = split(/\\/,$header);
$temp = pop(@temp);
@fname= split(/\"/,$temp);
$fname= shift(@fname);
$fname= "\L$fname\E"; # ファイル名の強制小文字化
$code_len = length($header_end_code);
$fdata = substr($file,$len+$code_len);
chop($fdata);
if ($code_len >2){chop($fdata);}
# ファイルデータを書込
open(F,">$curr_dir$fname");
binmode(STDOUT);
binmode(F);
print F "$fdata";
close(F);

# ファイルのパーミッション設定
$mode = "0644";
if (($fname =~ /.pl$/) || ($fname =~ /.cgi$/)) {$mode = "0755";}
chmod(oct($mode),"$curr_dir$fname");
}
}
print "Location:$ENV{'HTTP_REFERER'}\n\n";
exit;


▲ 頁トップ  ホーム
ファイルのパーミッション
 <サンプル1>はファイルのパーミッションを変更するときの基本的なサブルーチンです。

 引数として、ファイル名リスト(@fnames)、新パーミッション($newmode)を与えて、処理を行います。

 特に注意すべきことは、引数として与える新パーミッションの数値はFTPと同様に3桁の8進数ですが、パールの chmod($mode,$file) コマンドにおける $mode は8進表記を10進に変換した後の値であるということです。

 また、プロバイダ側で自動的にパーミッションを設定するところでは誤動作の原因になりますから、使用しないようにします。

<サンプル1>

# ファイル属性変更サブルーチン
# sub chmod_file {
local(@fnames) = split(/\0/,$fname);
if ($newmode eq "") {&error_disp("変更","新モードが未記入です。");}
if ($newmode eq !~ /0[0-7][0-7][0-7]/) {&error_disp("変更","新モードは頭に0を付けた3桁の8進数で入力して下さい。例 0755、0644");}
if (@fnames == 0) {&error_disp("変更","変更対象が未選択です。");}
foreach $file(@fnames) {
chmod(oct($newmode),"$curr_dir$file") || &error_disp("変更","$!");
}
exit;
}

 次のサンプルはファイルをアップロードしたとき、そのファイルがCGIスクリプトであればそのパーミッションを自動的に0755に設定するものです。

<サンプル2>

# ファイルのパーミッション設定
$mode = "0644";
if (($fname =~ /.pl$/) || ($fname =~ /.cgi$/)) {$mode = "0755";}
chmod(oct($mode),"$curr_dir$fname");



 質問・疑問などがありましたら、 フォーラム にてお受けいたします。

▲ 頁トップ  ホーム