トップページphp
1001コメント360KB

Perlコーディング初心者質問スレ Part 52

■ このスレッドは過去ログ倉庫に格納されています
0001nobodyさん2006/09/15(金) 14:01:51ID:gobry0n2
Perlのコーディングで困ってる人のスレです。

【投稿する際の注意】
質問するときは内容をよく吟味してから投稿してください。
「コマンドの意味がわかんない」とかはマニュアル見ましょう。
回答者さんは何でも屋じゃありません。

1: 自分はこういう事がしたい。
2: それでこんな風にやってみたが・・・
3: こんなエラーが出て上手く行かなかった。

最低でも1と3が無いと誰も答えられないよ。
ソース貼る時は、全角スペースでインデント忘れずに。
良い回答は良い質問から。一緒に勉強しましょう。

お勧めサイトは >>2-10

前スレ http://pc8.2ch.net/test/read.cgi/php/1153987463/
過去ログ倉庫 ttp://user.ftth100.com/mirrorhenkan/perl/
0726nobodyさん2006/11/08(水) 03:11:43ID:Z752EjWS
>>725
すまん。質問の意味わかんね
0727nobodyさん2006/11/08(水) 04:32:08ID:CtUHOCOJ
$string =~ /NAME=huga\sVALUE="(.*?)"/;
%formdataはhugeが入ってるんじゃね?
07287252006/11/08(水) 04:32:26ID:x1PlsJ4C
>>726
submitボタンが複数ある時の選択方法を教えてください。
07297252006/11/08(水) 04:33:59ID:???
>>727
はい。そうです。
0730nobodyさん2006/11/08(水) 04:38:11ID:???
>>728
prog板から来たよんw

submitも普通のエレメントと一緒だよ。
nameがあってvalueがある。
submitの場合は押された部品のname&valueが渡される。
押されていないsubmitは渡されない。

この説明で分かるかしら。
07317252006/11/08(水) 04:43:05ID:x1PlsJ4C
>>730
できましたw
ありがとうございました。
0732nobodyさん2006/11/08(水) 04:46:44ID:???
ある画像掲示板に画像を自動アップロードするスクリプトを作っています。

例として、http://some.kind.of.uploader/upload.phpのページにある
<form enctype="multipart/form-data" action="upload.php" method="post">
<input type="file" name="userfile" size=50>
<input type="submit" value="SUBMIT">
</form>
というフォームに対して、ローカルの/path/to/file/にあるtest.jpgをアップロードす
るとします。
my $url = 'http://some.kind.of.uploader/upload.php';
my $ua = LWP::UserAgent->new();
my $response = $ua->post($url, ['userfile' => '/path/to/file/test.jpg']);
としてみましたがうまくアップロードできません。
できない理由として考えられることは何がありますでしょうか?
また、同様の趣旨でもっといい方法がありましたら御教授お願いします。
0733nobodyさん2006/11/08(水) 05:34:44ID:???
どう、うまくないのかを書け。
つ php.ini
0734nobodyさん2006/11/08(水) 06:47:20ID:???
>>732
ファイルデータじゃなくて"/path/to/file/test.jpg"って文字列で飛んでるんじゃ
0735nobodyさん2006/11/08(水) 08:08:20ID:???
>>733
サーバーからのメッセージとしては、手動で行なった場合にファイル名を入力しなかっ
たのと同じ「アップロードするファイルを入力してください」というものです。

>>734
そんな感じですね。

と、言うわけで自己解決しました。requestを使用します。
my $file = '/path/to/file/test.png';
my $response = $ua->request(POST $url,
Content_Type => 'form-data',
Content => ['userfile' => [$file]]
);
0736nobodyさん2006/11/08(水) 22:57:15ID:???
特定のIPを拒否したい場合に以下を記述したら一応機能したんですけど、
何か問題ありますか?


@deny = ("0.0.0.0","1.1.1.1");
$addr = $ENV{'REMOTE_ADDR'};

foreach $ip (@deny) {
     if ($addr eq $ip) {print "エラー";
     last;}
}
0737nobodyさん2006/11/08(水) 23:08:19ID:???
my $addr = $ENV{'REMOTE_ADDR'};
my @deny = (
"0.0.0.0",
"1.1.1.1",
);

foreach my $ip (@deny) {
if ($addr eq $ip) {
print "error";
last;
}
}
0738nobodyさん2006/11/08(水) 23:17:40ID:???
http://www.futomi.com/lecture/local/ これですな

Perl5以降は local でなくて my を使うのが推奨されているようだ
07397362006/11/08(水) 23:41:20ID:???
|
|⌒σ   / ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄\
|冫、) < >>737-738 ありがとう。 |
|` /    \_________/
|  |
|/| |
| ∪
|

|  / ̄ ̄ ̄ ̄\
|<  さらばじゃ |
|  \____/
|)彡 サッ
|
|
|
|
0740nobodyさん2006/11/08(水) 23:51:59ID:???
禁止IPが多いなら、ハッシュ使った方がよさそう

my %deny = (
  "0.0.0.0" => 1,
  "1.1.1.1" => 1,
);
if ($deny{ $ENV{'REMOTE_ADDR'} }) {
  print "error";
  last;
}
0741nobodyさん2006/11/08(水) 23:57:39ID:???
ハッシュだとlast;が不要な予感。
0742nobodyさん2006/11/09(木) 00:02:09ID:???
exitと書きたかったんだろ
0743nobodyさん2006/11/09(木) 09:09:18ID:???
CGIでprint "error"だけなのには誰も突っ込まないのか?
0744nobodyさん2006/11/09(木) 10:28:57ID:???
そこまで面倒見きれんw
0745nobodyさん2006/11/09(木) 15:33:45ID:???
$deny = '0.0.0.0/1.1.1.1';
error() if index($deny, $ENV{REMOTE_ADDR}) >= 0;
0746nobodyさん2006/11/09(木) 18:25:08ID:???
|
|⌒σ  
|冫、)
|` / 
|  |
|/| |
| ∪
|
0747nobodyさん2006/11/09(木) 19:33:08ID:???
コーディングとはちょっと違うんですが・・・
WindowsでGDを使いたいのですが、同時にインストール必要なモジュールって他にありますか?
ppmでGDをインストールして、サンプルを参考に
画像を読み込んで表示するだけのスクリプトを書いてみたのですが
GD::Imageで指定したサイズの黒い四角は表示されるものの、画像そのものは表示されません。
UNIXでは他にも複数のライブラリのインスコが必要という記事を見つけたので調べているんですが
Windows(ActivePerl)ではどうなんでしょうか。
0748nobodyさん2006/11/09(木) 19:36:56ID:???
確かMRTGはGD突っ込んで難なく動いてたから、それを参考にしてみれば?
0749nobodyさん2006/11/09(木) 19:37:47ID:???
あっ、ごめん。
MRTGでグラフを書いてるのはEXEバイナリだったorz
0750nobodyさん2006/11/09(木) 20:23:24ID:???
うちでは普通に動いてるし、入れ方かサンプルソースが悪いんじや?
07517012006/11/09(木) 20:52:58ID:???
ご回答いただきありがとうございます。

use Encode; と $_ = encode('sjis', decode('sjis', $_)); を外しただけで、
サーバ全体の負荷(5min, 15min uptime) が MRTG のグラフで目視して明らかに分かる程度に減ったので、
CGI負荷の増大の原因はそれにあったことがほぼ決定しました。

>>116 の方法を採用してみます。
07527472006/11/09(木) 20:56:36ID:???
>>748-749
どもです。余裕見て参照してみます。

>>750
ホントですかー。動いてるんですね。
でもそれがわかっただけでも大助かりです。
おかげで絞り込めてきましたので、なお見直してみます。
ありがとうございました!
07537012006/11/09(木) 21:29:43ID:???
実際に >>116 の方法を実装してみました。

>>704
> 「不正な文字コードが見つかれば、以降の文字はすべて無効」でOKなら116で問題ないかと。
とありましたが、

116の方法では、不正な文字列(マルチバイト文字列の1バイト目が単独で存在) が 文の中央付近に入っていた場合でも、
その不正な文字列の除去のみが行われて、それ以降の文字列は正常に受け取れました。
(※不正な文字列はきちんと除去されていました。)

ちなみに、$_ = encode('sjis', decode('sjis', $_)); 方式と違って、丸付き文字 @AB なども正常に受け取れるようです。
(よいか悪いかは別にして…)

負荷の問題はもうちょっと運用してみて結果が出たら報告させていただきます。

回答してくださったみなさまありがとうございました
0754nobodyさん2006/11/09(木) 22:17:24ID:3KxQ4Dio
すでに動作しているコードを、-wオプションをつけて修正してるのですが、
local宣言して別パッケージから参照している変数がtypoと言われて
しまいます。

現在、
> local $main::upload_dir = './attach_file/';

と書いてあるものを

> local $main::upload_dir;
> $main::upload_dir = './attach_file/';

とすると警告が出なくなります。typoだけ警告をきるようなことは可能でしょうか。
よろしくお願いします!
0755nobodyさん2006/11/09(木) 22:18:46ID:???
>>752
ごめん、>>748-749は本当に無視して〜orz 時間ももったいないし。
0756nobodyさん2006/11/10(金) 05:24:46ID:???
perlで会員全員にメールを送信したいのですが、sendmailで送信した場合負荷はどのくらいかかるのでしょうか。

プログラムの概要は、
フォルダ内の「会員ID.txt」(中身はメールアドレス)をopendirで会員IDの配列を作る。
forの中で、open(会員ID)→メールアドレス格納→sendmailで送信。
会員IDの配列分だけ繰り返し。

といった感じです。

メールの内容にも会員IDを埋め込みたいのでこのような方法にしています。

ブラウザからアクセスして実行してみましたが、現在会員数は20人足らずにもかかわらず
少し重そうだったので他にいい方法はないかと質問させていただきました。
0757nobodyさん2006/11/10(金) 08:34:04ID:???
それは負荷がかかってるわけじゃない 時間がかかってるだけ
送信先メールサーバの名前解決をしてユーザがそんざいするかとか
今送れるかどうか問い合わせたり
相手が忙しいと待たされたり
とにかくメール送信が負荷よりも時間のほうがかかる
もし自サーバになんらかの負荷がかかってればsendmailは自動的に待ち状態になる設定になってるはず
0758nobodyさん2006/11/10(金) 09:16:39ID:???
>>754
no warnings 'once';
0759nobodyさん2006/11/10(金) 15:57:59ID:???
>>757
なるほど。ありがとうございました。
0760nobodyさん2006/11/10(金) 23:09:40ID:???
>>758 ありがとうございます!!
0761nobodyさん2006/11/11(土) 17:04:01ID:jBOZHEcG
ファイルハンドルからファイル名をgetする方法を押しててください。
0762nobodyさん2006/11/11(土) 18:16:33ID:???
うんとこしょー!(押
0763nobodyさん2006/11/11(土) 18:37:34ID:???
そもそもファイル名もわからないファイルハンドル使う処理があるのか?
0764nobodyさん2006/11/11(土) 18:45:16ID:???
□ orz
0765nobodyさん2006/11/11(土) 19:51:38ID:???
どんなファイルを開いてるか不明になれるのか?
それはそれですげぇな
0766nobodyさん2006/11/11(土) 20:25:29ID:???
>>761
発想を変えて、open したファイル名を保存しておいてはどうかな。
うーん、ぼくってしんせつ!
07677662006/11/11(土) 20:43:59ID:???
で、それもやってくれる FileHandle::Deluxe を CPAN からインストール。
0768nobodyさん2006/11/11(土) 20:44:20ID:???
statすればデバイスとinode番号がわかるので、File::Findを使うなりして
探せばわからなくもない。ただしopenしたあとに削除されてたらアウト。
0769nobodyさん2006/11/11(土) 21:39:58ID:srC1L817
$foo->hoge(
   aaa => @aaa,
   bbb => @bbb,
   ccc => @ccc
);

のように、fooオブジェクトのhogeメソッドに配列を渡す時、

sub hoge {
   my $self = shift;
   my %args = @_;

   $self->{aaa} = ?; // @aaaを入れたい
   $self->{bbb} = ?; // @bbbを入れたい
   $self->{ccc} = ?; // @cccを入れたい
   ・
   ・
   ・
}

とした場合、%argsからどのようにして@aaa、@bbb、@cccを受け取るのでしょうか。
0770nobodyさん2006/11/11(土) 21:51:54ID:???
いや、それもう呼び出し方からしてダメだし。

$foo->hoge(
 {
  aaa => ¥@aaa,
  bbb => ¥@bbb,
  ccc => ¥@ccc
 }
);

sub hoge {
 my $self = shift;
 my $args = shift;
 $self->{aaa} = $args->{aaa};
 ・
 ・
}

まあ実際の処理ではこんな事しないと思うよ。
してたら設計ミスを疑った方が。
0771nobodyさん2006/11/11(土) 21:59:26ID:???
別にハッシュのリファレンスとして渡す必要はないような。

my $self = shift;
my %args = @_;
$self->{aaa} = $args{aaa};
0772nobodyさん2006/11/11(土) 22:01:07ID:srC1L817
>>770
ありがとうございます。
では、OOPにおいてメソッドの呼び出し時に配列を渡す場合の受け渡しはどうなるのでしょうか?m(_ _)m
0773nobodyさん2006/11/11(土) 22:04:15ID:srC1L817
>>771
ありがとうございます。
その方法は試しましたが、受け取り側($self->{aaa})が配列の要素数を受け取ってしまいました。。。
0774nobodyさん2006/11/11(土) 22:15:26ID:dAHcCPkr
残念だが>>771はうまくいかない。
>>772
>>770のとおりで良いと思う。
hashの要素としてlistを直接持てないから、listのリファレンスにするわけ。
0775nobodyさん2006/11/11(土) 22:25:12ID:srC1L817
>>774

$self = {
   aaa => undef
};

として受け取った場合、$self->{aaa}を配列として扱うことは可能なのですか?
0776nobodyさん2006/11/11(土) 22:26:23ID:???
ああ、ごめん、ちゃんと読んでなかった>< >>771 では
$self->{aaa} = @{$args{aaa}};
と配列変数のリファレンスを受け取るって書いたつもりでした。
そうすれば、引数のリストを>>770のように匿名ハッシュで囲わなくてもいいんじゃないか、と。
0777nobodyさん2006/11/11(土) 22:48:53ID:???
>>775 $self->{aaa}を配列として
配列として、は無理。配列のリファレンスとして、扱う。

ちなみに>>770氏は引数全体をhashのリファレンスにし、且つ個々のlist(@aaa とかの部分)も
listのリファレンスにしてるけど、後者は必須だが、前者はただのhashにもできるね。

$foo->hoge(
  aaa => ¥@aaa,
  bbb => ¥@bbb,
  ccc => ¥@ccc
);

sub hoge {
 my $self = shift;
 my %args = @_;
 foreach my $key (keys %args) {
  $self->{$key} = $args{$key};
 }
}
# @{$self->{$key}} で配列全体を、$#{$self->{$key}} で要素数-1を、$self->{$key}->[0] で個々の値を参照できる
>>776
I see.
0778nobodyさん2006/11/11(土) 22:55:37ID:???
>>769
@_ にはサブルーチンの引数がフラットなリストとして展開・格納されます。
また "=>" は本質的に "," のエイリアスに過ぎません。
すなわち @aaa = ( 'xxx', 'yyy', 'zzz' ) である時、hoge( aaa => @aaa ) は hoge( 'aaa', 'xxx', yy'y', 'zzz' ) と等価です。
さらには %args = ( aaa => @aaa ) とやってしまうと、

$args{aaa} == 'xxx'
$args{yyy} == 'zzz'

という内容のハッシュが出来上がります。これは恐らくあなたが望むものではないでしょう。

サブルーチン引数やハッシュ代入における配列 (より正確には全ての非スカラー) の独立性を保つには、偶然にも同じ解決策が使えます。
「リファレンス」がそれで、>>770 で実装の一例が述べられています。

perlref, perllol, perlsub などのマニュアルが役に立つでしょう。
# 他の言語から Perl に移行する場合は混乱するよな、実際。
0779nobodyさん2006/11/11(土) 23:07:00ID:5mpuYPBZ
なるほど・・・上記の方々、ご返信ありがとうございます!
理解するまでしばらくかかりそうなので、理解してまた返信させていただきますm(_ _)m
0780nobodyさん2006/11/11(土) 23:28:01ID:t9lEuzhq
つまり、ハッシュのvalueを配列として渡すと渡す側のkeyも渡ってしまい意図しない値を受け取ってしまう、という訳でしょうか。
(なんか良く分からなくなってきましたが・・・)
質問に答えていただいた方、ありがとうございました。

ところで、こういう細かいことが書かれているオンラインのマニュアルなどはあるのでしょうか?
0781nobodyさん2006/11/11(土) 23:44:57ID:???
>>780
>>779
特に perlref。ぐぐればいいよ。
listもhashも、複数の値でできてる。複数の値なんで、それを一つの値であるかのように、
$a{'aaa'} = @aaa;
とすることはできない。
しかし、リファレンスっていうのはそれ自体は一つ。なので、
$a{'aaa'} = ¥@aaa;
は可能なんですよ。

%aa = ('aa' => 'AA', 'aaa' => 'AAA');
%bb = ('bb' => 'BB', 'bbb' => 'BBB', 'bbbb' => 'BBBB');
hoge(%aaa, %bbb);
はhogeに10個の引数を渡していることになるけど、
hoge(¥%aaa, ¥%bbb);
は2個の引数を渡してるんですよ。
0782nobodyさん2006/11/11(土) 23:48:10ID:???
まちがった orz

%aa = ('aa' => 'AA', 'aaa' => 'AAA');
%bb = ('bb' => 'BB', 'bbb' => 'BBB', 'bbbb' => 'BBBB');
hoge(%aa, %bb);
はhogeに10個の引数を渡していることになるけど、
hoge(¥%aa, ¥%bb);
は2個の引数を渡してるんですよ。
0783nobodyさん2006/11/12(日) 01:13:46ID:???
質問

Perlで作られた日本語版のWEB CGIゲームを
英語版に改造しようとしているのですが、(作者の許可は取得済み)
作業の進め方がわかりません。

どうしたらいいですか?
二人のチームでやるのですが、
自分が翻訳担当で、もうひとりが技術担当です。

まず日本語の用語を全部リストに洗い出して、
それをかたっぱしから英語に直していって、
翻訳が終わった分から、技術者に渡して、
技術者はできあがった翻訳を受け取ったら、
正規表現か何かでガァーーっと
英語に置換していけばいいのですか?
0784nobodyさん2006/11/12(日) 01:19:07ID:???
てか英語版に改造するも何も翻訳するだけやん
0785nobodyさん2006/11/12(日) 01:34:08ID:???
>>784
ソースの中の日本語部分を英語に翻訳すればいいだけなのか。

あるいはCGIで生成される日本語も英語に翻訳しなければならないのか、

あと、一つの用語を翻訳して、それを28のファイル全部に
行き渡らせるにはどうしたらいいのか。
0786nobodyさん2006/11/12(日) 01:46:37ID:???
改造が許されてるなら、テンプレートシステムなりなんなり導入してリソースを分離したら?
それが難しいってなら、普通にソース中の文字列リテラルを地道に翻訳するしかないだろうね。
0787nobodyさん2006/11/12(日) 01:55:13ID:???
>>786
ようはいきなりソース中にべた書きされてる日本語を英語訳するよりも、
「言語パック」
みたいのをつくって、エンジン部分は翻訳者はまったくさわらずに
すむような状況を作ってから、翻訳者に仕事をさせたほうがいいと?
0788nobodyさん2006/11/12(日) 01:57:45ID:???
>>784
↑って>>783か?
なんか質問の仕方がなってない。
「〜いのか。」

> ソースの中の日本語部分を英語に翻訳すればいいだけなのか。

他に何かする必要あるのかよ。

> あるいはCGIで生成される日本語も英語に翻訳しなければならないのか

それって「ソースの中の日本語部分を英語に翻訳」じゃないの?

> あと、一つの用語を翻訳して、それを28のファイル全部に
> 行き渡らせるにはどうしたらいいのか。

行き渡らせるの意味が不明。
28のファイルなんて言われてもこっちは知らない。
もし、28個のファイルに同じ用語(日本語)があってそれを
英語に置き換えたいというのなら正攻法でひとつひとつ
やってけ。
もしくは http://akky.cjb.net/download/speeeeed.html みたいなソフト
使って置き換えれば?

> 技術者はできあがった翻訳を受け取ったら、
> 正規表現か何かでガァーーっと
> 英語に置換していけばいいのですか?

技術者なのにそんなことも分からんのかい。
日本語に依存する処理(例えばjcode.plやJcode.pmによる文字コード変換)
をしているところは削ったりとか英語用に変えるとかも必要になったりするでしょ。
0789nobodyさん2006/11/12(日) 02:06:52ID:???
>技術者なのにそんなことも分からんのかい
らめぇええええ

漏れ技術者じゃないぃいいいい
ただの翻訳者ぁああああ
0790nobodyさん2006/11/12(日) 02:09:52ID:???
>>789
技術者出てこい、じゃないかな。
ハードコードしてあるリテラルを翻訳者が訳して地道に修正するのか、
リソースとして外出しにするにか、ってのは技術者が判断しなきゃないんじゃ?
0791nobodyさん2006/11/12(日) 07:43:27ID:???
何で翻訳者がここに居るんだ?
0792nobodyさん2006/11/12(日) 09:13:18ID:???
plファイルについて質問です

使用中の掲示板のスクリプトに、ログ機能を追加するためplファイルを作り、
読み込み開始直前に require 'xx.pl '; を挿入しました

このままだと自分の記録も入ってしまうのでキャンセルするようにif条件で
ログ記録を部分を以下のようにしたところエラーが出てしまいました

if($name ne "自分"){
--ログファイルへの読み書き部分-- }

仕方なくjcode.plの最後を参考にし、

}
1;

としました、これで動作しました
この最後の1;はどうして必要なのでしょうか?
0793nobodyさん2006/11/12(日) 10:00:19ID:???
'〜が'.$n.'個あります'
みたいなのは順番も変えなくちゃだから、
ただリテラルを直すだけじゃ足りないかもしれない。
0794nobodyさん2006/11/12(日) 12:11:30ID:JI5vE2Zg
>>781-782
ありがとうございます!
本当にPerlって奥が深いですね・・・もっと勉強しますm(_ _)m
0795nobodyさん2006/11/12(日) 12:13:16ID:???
まずは翻訳してから改造しれや
ただそれだけだろ?
で、何人かが書いている通りリソースを分離できるなら

(1)分離できるところは分離する
(2)(1)の作業中に分離できないところを翻訳
(3)分離後ソースを改造開始し、(2)で分離したリソースの翻訳

これがベストか?
0796nobodyさん2006/11/12(日) 12:22:19ID:???
>>792

> ログ記録を部分を以下のようにしたところエラーが出てしまいました

Internal Server Errorだったら文法ミスとかでしょ。
鯖のエラーログ見るか文法チェックしてみ。
肝心な部分が省略されてるから答えられるのはこの程度しかない。

> この最後の1;はどうして必要なのでしょうか?

"requireしたファイルの最後"を明示しないとエラーになることがあるから。
1;がその役割。
0797nobodyさん2006/11/12(日) 13:02:21ID:???
>>796
if構文を入れなければ、「1;」を省略しても実行されるので
文法ミスではないと思いますが、if(){}を使ったことで
>ファイルの最後"を明示しないとエラーになる
が発生したものと思われます

有り難うございました
0798nobodyさん2006/11/12(日) 13:41:44ID:???
>>797
細かいとこなんだけれど一応。スルー力不足を露呈してみる。

>>796 の説明には若干の誤解があります。
require が読込むファイルは最後に真を返す必要があります。
より正確には、require されるコードが正しく実行されたかどうかの真偽を、そのコードから返す機能の名残ですが、今では誰も覚えていませんし、覚える必要もありません。
require はファイルが偽を返した場合、require されたコードの初期化に失敗したものと見なし、例外を吐いて死にます。
0799nobodyさん2006/11/12(日) 13:44:17ID:???
>>791
ここで解決できたら Perl のドキュメントを和訳して公開してくれるんだよ。
0800nobodyさん2006/11/12(日) 21:22:52ID:???
なんで1なんだろう?と思ってたけど納得できた。
ありがとう、胸がすっとしたぜ!
0801nobodyさん2006/11/13(月) 04:13:23ID:???
いつもお世話になっています。

CGI/Perl のデバッグをしたい (phpのWARNINGのような詳細なエラーを出したい) のですが、良い方法は無いでしょうか?

エラーが出たときにApacheのエラーログを見ても、「Premature end of script headers: example.cgi」 程度の記述しか表示されません。
サーバは、Fedora Core 4 + Apache 2.2.0 + Perl 5.8.6 (SuExecは使っていません。) と一般的な構成です。

ご教示お願いします。
0802nobodyさん2006/11/13(月) 04:19:09ID:???
次のようなスクリプトを実行すると、「CGI開始」 は出力されますが、「CGI終了」 は出力されません。

このCGIには問題点があり、if ("検索対象文章" =~ /$hoge/i) の $hoge が "+" なので、正規表現として不正になっています。
本来ならば、500 Internet Sever Error となるべきだと思うのですが、何故かエラーにならず、スクリプトが強制終了されるだけになります。
これは何故でしょうか?

if ("検索対象文章" =~ /+/i) と書けば、当然 500 Internet Sever Error になります。

--------------- test.cgi ---------------
#!/usr/bin/perl

print "Content-Type: text/html\n\n";
print "CGI開始";

$hoge = "+";
if ("検索対象文章" =~ /$hoge/i) {
print "マッチしました。";
} else {
print "マッチしませんでした。";
}

print "CGIエンド";
exit;
----------------------------------------

ちなみに、この $hoge は実際にはCGIのユーザ入力の値です。
OSインジェクションやSQLインジェクションは聞いた事がありますが、Perl正規表現インジェクションという話は聞いた事はありませんが、
もしこの実装に、スクリプトの強制終了以外のセキュリティ上の問題点がありましたら教えていただけたら幸いです。
また、ようするに検索エンジンのように文章の検索を行いたいわけですが、ユーザ入力の正規表現のメタ文字の無効化方法がありましたら
教えて下さい。

お願いします。
08038022006/11/13(月) 05:00:38ID:???
> ユーザ入力の正規表現のメタ文字の無効化方法

これに関しましては、自分で知っているメタ文字をエスケープするコードを書いてみました。
もし、エスケープ漏れがあったら教えて下さい。

$_ =~ s/\\/\\\\/g;
$_ =~ s/\^/\\\^/g;
$_ =~ s/\./\\\./g;
$_ =~ s/\$/\\\$/g;
$_ =~ s/\*/\\\*/g;
$_ =~ s/\?/\\\?/g;
$_ =~ s/\|/\\\|/g;
$_ =~ s/\(/\\\(/g;
$_ =~ s/\)/\\\)/g;
$_ =~ s/\[/\\\[/g;
$_ =~ s/\]/\\\]/g;
$_ =~ s/\{/\\\{/g;
$_ =~ s/\}/\\\}/g;
$_ =~ s/\+/\\\+/g;
0804nobodyさん2006/11/13(月) 05:01:40ID:???
>>801
use CGI::Carp qw(fatalsToBrowser);
をCGIファイルの先頭付近に。他にもKCatchとかあるから探してみそ

>>802
ヘッダを吐き出していればdieしようが何しようが表示されるのね。
/+/だと500エラーになるのは、解釈段階でエラーが発生するため。
対して/$hoge/だと$hogeの値は評価段階にならないと決定されないから
先にヘッダが出力される。よって500エラーにならない。

Perlは正規表現中に任意のコードを含めることが可能なのは事実だけれど(?{ ... })、
それなりに安全対策がしてあるので、許可しなければ外部コードが
実行されてしまうということは無いと思われる。
see also: perlre, ttp://search.cpan.org/~nwclark/perl-5.8.8/ext/re/re.pm
強制終了しないようにするためにはevalブロックを用いるといい。

そのユーザの入力というのは正規表現を期待してるのだよね?
正規表現的に意味のある文字を全てエスケープしてしまうという意味なら、
quotemeta関数なり、/\Q$hoge\E/なりがあるけれど。その場合ならindex関数を使う手もある。
08058042006/11/13(月) 05:12:29ID:???
>>801
スマソ、思いっきり勘違いした警告か。
use warnings;
もしくはShebang行にこのように-wをつける。
#!/usr/bin/perl -w

で、さっきのと組み合わせて
use CGI::Carp qw(warningsToBrowser fatalsToBrowser);
...
warningsToBrowser(1);
のようにすると出力上にコメントとして出てくる。
08068022006/11/13(月) 05:46:37ID:???
>>804-805
ご丁寧な回答ありがとうございます。
#!/usr/bin/perl -w
use CGI::Carp qw(warningsToBrowser fatalsToBrowser);
を試してみます。

また、evalブロックについてのページも参考になりました。

> Perlは正規表現中に任意のコードを含めることが可能なのは事実だけれど(?{ ... })、
これはちょっと気になるので、もしよろしければ参考URLを教えていただけたら幸いです。

> その場合ならindex関数を使う手もある。
結局それに気がついて index 関数使っちゃいました。
大文字小文字を区別することができなくなりましたが、そこは諦めます。
0807nobodyさん2006/11/13(月) 09:26:04ID:???
>>806
(?{ ... })については参考URLをさがすまでもなくperldoc perlreにちゃんと書いてあるが。
08088022006/11/13(月) 11:06:39ID:???
>>807
ありがとうございます。
見つかりました。
http://www.kt.rim.or.jp/~kbk/perl5.005/perlre.html

正規表現中でのコードの実行機能は use re 'eval'; と宣言しない限り、使用できないようです。
ってことでユーザ入力値の値をいきなり代入したところでセキュリティ上の問題は無さそうですね。

# ただし、処理に時間のかかる正規表現をいれることにより、
# DoSに使えるかも。
0809nobodyさん2006/11/13(月) 14:35:35ID:???
SQLインジェクションみたいな脆弱性?
0810nobodyさん2006/11/13(月) 14:40:31ID:???
>>801
てゆかapacheのログ見れる立場にいるならLogLevelの設定変えられないの?
0811nobodyさん2006/11/13(月) 14:52:19ID:???
apacheのエラーログみて「Premature end of script headers: example.cgi」 しかないのなら、
いくらwarningsToBrowserやfatalsToBrowserしてもやっぱり何もでないんじゃないか。
ログみられなかったり見るのが面倒な人がつかうもんだろ?

処理系が検出するようなエラーはないがそもそもロジックがおかしい予感。
0812nobodyさん2006/11/13(月) 14:54:42ID:???
>>809
ようするに任意のコマンドが実行できる脆弱性ってことでしょ

use re 'eval';
$a =~ /$GET['search']/

こういうことしていると、「(?{open("| cat /etc/passwd > hoge@example.com"})」 を送信されたときに
/etc/passwd がクラッカーに渡ってしまう。

正規表現インジェクションとでも呼べばいいだろうか
対策は正規表現のメタ文字のエスケープだね。

0813nobodyさん2006/11/13(月) 16:20:57ID:???
最新のActivePerlを入れたらppmがGUIになっててビビった。
コンソール版はなしですか?
0814nobodyさん2006/11/13(月) 17:01:43ID:???
>>813
以前の対話形式はppm-shell
コマンドラインなら
ppm command arg
でも行ける
# 殆どGUI版使ってないや
0815nobodyさん2006/11/13(月) 19:14:27ID:???
>>814
サンクス。
0816nobodyさん2006/11/13(月) 20:06:21ID:???
ppm ってインストール済のモジュールを一括してアップグレードできないんですか?
0817nobodyさん2006/11/13(月) 21:12:11ID:???
>>816
ppm upgrade -install
0818nobodyさん2006/11/14(火) 00:35:27ID:???
Perlは入門書を一冊読んで簡単な掲示板がやっと作れる程度のかなりの初心者なのですが、
CGIその1内のデータを、CGIその2に受け渡すにはどうしたらいいのでしょうか?

「アドレス?パラメータ」の形で、フォームのデータをやり取りするようにデータが渡せると
書いてあったので、「アドレス?a=$a&b=$b&c=$c」というようにすれば、CGIその1で
変数aに代入したデータをCGIその2に送ることが出来るかと思ったので、

require 'cgi-lib.pl';
&ReadParse( *form );
$a = $form{'a'};
$b = $form{'b'};
$c = $form{'c'};

として、

print "${a}${b}${c}\n";

と表示してみようとしても、どの変数も空のままなのか何も表示されません。

どうすれば、変数データ等はやり取りできるようになるのでしょうか?
0819nobodyさん2006/11/14(火) 01:02:20ID:???
>>818
<input type="hdden" name="a" value="value of a">
みたいにフォームに仕込むのが簡単かな。
クライアント側でいじれちゃうというデメリットがあるけどね。
0820nobodyさん2006/11/14(火) 01:58:17ID:???
>>819
早い回答ありがとうございます。
それでやってみます。
0821nobodyさん2006/11/14(火) 04:24:01ID:???
質問です
my $file = "no001.jpg";
print -s $file;
上記のようにファイルサイズを出力するスクリプトで
正規表現を用いて no???.jpg にマッチするファイルのサイズを表示させたいのですが
方法が思いつきません
分かるかたいましたらご指導お願いいたします。
0822nobodyさん2006/11/14(火) 07:25:09ID:???
言っとくがオレはopendir派だ
0823nobodyさん2006/11/14(火) 13:15:59ID:???
CGI出力時の改行コードは指定するにはどうすればよいのでしょう。
LFにしたいのですが、どうやってもCRLFになってしまいます。
自宅のwindows上でも、xreaでもCRLFで出力されてしまいます。
0824nobodyさん2006/11/14(火) 13:38:15ID:???
自己解決しました。
ちゃんと出力されていました。
ブラウザでの保存時に勝手に改行コードが変えられていたようです。
0825nobodyさん2006/11/14(火) 14:07:32ID:???
>>821
loopで回して同じことして加算すれば。loopは opendir 派でなければ
foreach $hoge (<no???.jpg>) {
}

コマンドラインでなら ls -l と awk で One Liner するけどね
■ このスレッドは過去ログ倉庫に格納されています