トップページ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/
0622nobodyさん2006/10/26(木) 22:26:27ID:???
>>621
そこはやめとけ。ネタ?

0623nobodyさん2006/10/26(木) 22:44:18ID:???
>>622
ロックファイルでググったら、これがトップだったからどうなのかな?と思って。
0624nobodyさん2006/10/26(木) 22:48:56ID:???
【Perl】ファイルロック(排他処理)について語ろう
http://pc8.2ch.net/test/read.cgi/php/1024795138/

こっちは参考にならナイン?
0625nobodyさん2006/10/27(金) 00:05:23ID:???
とりあえずflockしとけばいい
06266152006/10/27(金) 00:30:08ID:???
レスありがとうございます。
自分ではif文が程度の知識しかないのでとりあえず
>>616さん参考になんとかできないか考えて見ます。
0627nobodyさん2006/10/27(金) 00:46:20ID:???
大学の課題で、「ある言葉を入力したらこれこれこういう言葉を返すようにしたい」プログラムを作りたいのですが上手く行きません。
サンプルはこんな感じです。

#!/usr/bin/perl
@a = ('kon','hazimemasite','gennki','gennkidesu','baka','bakatohananiyo','sayonara','jaane');

for(;;){
print "Please input sentences :";
chomp($n=<STDIN>);
if($n eq $a[0]){
print $a[1],"\n";
redo;
}elsif($n eq $a[2]){
print $a[3],"\n";
redo;
}elsif($n eq $a[4]){
print $a[5],"\n";
redo;
}elsif($n eq $a[6]){
print $a[7],"\n";
exit;
}else{
print "What is 「$n」?\n";
exit;
}
}
06286272006/10/27(金) 00:47:04ID:???
で、これをハッシュを使って上のプログラムと同じ実行結果にしたいのですが・・・
指定された文字を入力しても上手くいきません。

#!/usr/bin/perl
%a = ('kon','hazimemasite','gennki','gennkidesu','baka','bakatohananiyo','sayonara','jaane');

for(;;){
print "Please input sentences :";
chomp($n=<STDIN>);
if($n eq $a[0]){
print $a{kon},"\n";
redo;
}elsif($n eq $a[2]){
print $a{gennki},"\n";
redo;
}elsif($n eq $a[4]){
print $a{baka},"\n";
redo;
}elsif($n eq $a[6]){
print $a{sayonara},"\n";
exit;
}else{
print "What is 「$n」?\n";
exit;
}
}

自分ではif文内の「$a[x]」がおかしいのかなとは思ったりしてますが・・・
どなたかご教授お願いします。
0629nobodyさん2006/10/27(金) 01:17:45ID:???
>>628
配列をハッシュにしてるんだから、
$a[0]は未定義を参照しようとしてる。
use strictすればすぐ分かる間違いなので、使い慣れておくことお勧め。
で、書き直すならこんな感じ。
#!/usr/bin/perl
%a = ('kon','hazimemasite','gennki','gennkidesu','baka','bakatohananiyo','sayonara','jaane');

while (1) {
  print 'Please input sentences :';
  chomp ( $n = <STDIN> );
  print "$a{$n}\n" if $a{$n};
  exit if $n eq 'sayonara';
  unless ($a{$n}) { print "What is 「$n」?\n" }
  redo;
}
exit;
0630nobodyさん2006/10/27(金) 01:19:02ID:????BRZ(5753)
if (exists $a{$n}){ print $a{$n},"\n"; }
else { print "What is [$n]?\n"; }
0631nobodyさん2006/10/27(金) 01:19:03ID:???
こっちがスマートだったか。
while (1) {
  print 'Please input sentences :';
  chomp ( $n = <STDIN> );
  print "$a{$n}\n" if $a{$n};
  unless ($a{$n}) { print "What is 「$n」?\n" }
  exit if $n eq 'sayonara';
}
0632nobodyさん2006/10/27(金) 01:30:03ID:???
>>621
うわ。。。 いつの間にかterra大先生復活してたのか。
セキュリティホール開けっ放しのCGI配って逃亡した前歴のある人ね。
0633nobodyさん2006/10/27(金) 03:06:18ID:???
>>629-631
ありがとうございます。usetstrict参考にします。

ですが実行するとコマンドプロンプトが終了されてしまいます。

何より、>>630
  print "$a{$n}\n" if $a{$n}; #ここと
  exit if $n eq 'sayonara';  
  unless ($a{$n}) { print "What is 「$n」?\n" } #この行

が理解できませんf- -;)

『print "$a{$n}\n";』は
「配列aの$n番目?を参照する」という意味でしょうか?
0634nobodyさん2006/10/27(金) 04:04:22ID:???
print "$hoge{$foo}\n";

print $hoge{$foo}, "\n";

print $hoge{$foo};
print "\n";
と同じ。

print "$name君はオナニー大好き";

print $name, "君はオナニー大好き";

print $name;
print "君はオナニー大好き";
が同じであるように。
0635nobodyさん2006/10/27(金) 09:43:28ID:???
@aは配列
%aはハッシュ
書き直したほうが見やすいかも
%a = (
  kon => 'hazimemasite',
  gennki => 'gennkidesu',
  baka => 'bakatohananiyo',
  sayonara =>'jaane'
);
$a{$n}はchomp($n=<STDIN>)より、
入力された文字をキーにしてハッシュを参照する。
06366332006/10/27(金) 10:25:36ID:???
>>634-635
ありがとうございます。

ですが、「chomp($n=<STDIN>)」で文字を入力する画面にすら行かず終了してしまいます
コマンドプロンプトだからいけないのでしょうか?
06376332006/10/27(金) 12:32:36ID:???
全角じゃ駄目なんですね・・・勉強になります


exit if $n eq 'sayonara';  
  unless ($a{$n}) { print "What is 「$n」?\n" }

この部分をもう少し無駄のある(これなら省略できるだろうってくらい)表現にするには
どうすればいいでしょうか?
出きればunlessを違う形に出来たらいいなとは思ってますが・・・

0638nobodyさん2006/10/27(金) 13:59:20ID:???
セミコロンを省略しちゃ駄目でしょ
0639nobodyさん2006/10/27(金) 14:18:36ID:???
>>637
if(!$a{$n}){}
>>638
{}の中では省略可能
0640nobodyさん2006/10/27(金) 15:10:04ID:???
while (1) {
print 'Please input sentences :';
chomp ( $n=<STDIN> );
if ( $a{$n} ) { print "$a{$n}\n" }
else { print "What is 「$n」?\n" }

if ( $n eq 'sayonara' ) { last }
}
0641nobodyさん2006/10/27(金) 16:13:39ID:???
>>639
> {}の中では省略可能
正確にはブロックの最後のステートメントな
0642nobodyさん2006/10/27(金) 16:27:26ID:???
気持ち悪い
0643nobodyさん2006/10/27(金) 17:02:56ID:???
大丈夫?吐いたほうが楽だよ
0644nobodyさん2006/10/27(金) 17:07:42ID:???
初心者の俺から見ても、これ以上ないぐらいわかりやすい書き方なんだけど・・・
06456332006/10/27(金) 21:25:59ID:???
できました!!

>>640のがすさまじくわかりやすかったです。
最終的に
------------------------------------------------------------
%a = qw( kon konnnichiwa
gennki gennkidesu
baka bakatohananiyo
sayonara jaane
);

while (1) {
print "Please input sentences :";
chomp ( $n=<STDIN> );
if ( $a{$n} ) { print "$a{$n}\n" }
else { print "What is 「$n」?\n" }
exit if ($n eq "sayonara");
}
--------------------------------------------------------------------
と、しました。
色々と教えてくださった方、本当にありがとうございました。
0646nobodyさん2006/10/27(金) 21:43:39ID:???
ハッシュの書き方例
%a = (
kon => 'konnnichiwa',
gennki => 'gennkidesu',
baka => 'bakatohananiyo',
sayonara => 'jaane',
);
0647nobodyさん2006/10/27(金) 21:51:05ID:???
決して間違った書き方じゃないからいいじゃん
0648nobodyさん2006/10/27(金) 22:27:39ID:???
他の書き方の"例"を書いただけど?
0649nobodyさん2006/10/28(土) 00:54:50ID:???
csvからユーザIDと情報を読み込んで、自分のサーバ領域内のユーザ名.txtに反映させる
cgiを作ろうと思うのですが。

(1)forかwhileで中でcsvの一行ずつopen関数で書き込む
(2)ハッシュに一度格納しておいて後で書き込むか(foreachを使いますが)
どちらの方がサーバに負担が少ないでしょうか?

ユーザが重複している場合、後ろのやり方の方がopen関数を使うのが少なくて済みます。
0650nobodyさん2006/10/28(土) 01:13:11ID:???
残念ながら、openでは書き込めない。
0651nobodyさん2006/10/28(土) 02:53:28ID:???
ユーザーが何万も居て、秒間何回も実行するわけじゃないんだから好きに組めばいいじゃん
0652nobodyさん2006/10/28(土) 12:09:18ID:???
ハッシュに格納しておいてDBI使って書き込むのがいいんじゃないでしょうか
06536332006/10/28(土) 15:46:29ID:???
ゼミの先生に提出したら
「お前、どっかのサイト見たんちゃうか?」って言われました・・・
まあ、その通りなんですがorz
>>627を素直に配列二つ使って表してみろといわれました。
んで、一応
----------------------------------------------------
@a = ('kon','gennki','baka','sayonara');
@b = ('hazimemasite','gennkidesu','bakatohananiyo','jaane');

for(;;){
print "Please input sentences :";
chomp($n=<STDIN>);
if($n eq $a[0]){
print $b[0],"\n";
redo;
}elsif($n eq $a[1]){
print $b[1],"\n";
redo;
}elsif($n eq $a[2]){
print $b[2],"\n";
redo;
}elsif($n eq $a[3]){
print $b[3],"\n";
exit;
}else{
print "What is 「$n」?\n";
exit;
}
}
----------------------------------------------------------
に、したのですが、もう少しまとめた感じにするにはどうすればいいでしょうか?f- -;)
0654nobodyさん2006/10/28(土) 15:56:42ID:???
@a = qw/kon gennki baka sayonara/;
@b = qw/hazimemasite gekkidesu bakatohananiyo jaane/;

OUTER: while (1) {
print 'Please input sentences: ';
chomp($n = <STDIN>);
for ($i; $i <= @a ; $i++) {
if ($n = $a[$i]) {
print $b[$i];
redo OUTER;
}
}
print "What is $n?\n";
exit;
}

がんばって自分で書けよ。そのほうがお前のためだ。
0655nobodyさん2006/10/28(土) 15:58:05ID:???
>>653
宿題だったのかよw 金輪際きくなw

ヒントとしては、@a と @b から %a 作ればおk
0656nobodyさん2006/10/28(土) 19:05:34ID:???
>>655
>>627

それでもヒントを出すお前が好きだ。
0657nobodyさん2006/11/01(水) 03:26:38ID:???
ttp://www.dab.hi-ho.ne.jp/sasa/biboroku/perl/session.html
を参考にして、CGI::Sessionを使用したシステムを組んでるのですが、
.sessionフォルダのcgisess_セッションidファイルがたまっていく一方です。
これをうまく消す方法は無いのでしょうか?
0658nobodyさん2006/11/01(水) 11:24:25ID:???
cronか必ずアクセスするcgiから時間見て消す
06596572006/11/01(水) 12:17:05ID:???
>>658
うーん やっぱり、そういう手法しかないんですかねー
0660nobodyさん2006/11/01(水) 13:05:08ID:???
ぐぐれ
0661nobodyさん2006/11/01(水) 21:01:16ID:???
コマンドプロンプトから環境変数を見てもIPアドレスが出てこない
のはなぜなんでしょうか?
0662nobodyさん2006/11/01(水) 21:22:05ID:???
氏ねよお前www
0663nobodyさん2006/11/01(水) 21:46:50ID:???
>>661
スタンドアロンでの起動って事?
端末間の通信って事ならソケットに何かあったような希ガス
06646572006/11/01(水) 23:34:18ID:???
opendir(SESSDIR, "./.session");
my @filelist = readdir(SESSDIR);
closedir(SESSDIR);

foreach (@filelist) {
if (/^cgisess_(\w)+$/ && $1 ne $sid) {
unlink("./.session/$_");
}
}

多分これで解決しました
06656572006/11/01(水) 23:35:57ID:???
あ、同時にログインするユーザーは1人だけのものを想定してたので……
0666nobodyさん2006/11/02(木) 00:17:07ID:???
え?CGI::Sessionってセッションファイルの後始末しないの?
クソじゃん
0667nobodyさん2006/11/02(木) 01:22:11ID:???
>>664
今回は確認が不要だったようだけれど、
ちゃんと有効期限を管理するなら、掃除するためのモジュールもあるよん
http://search.cpan.org/~rsavage/CGI-Session-ExpireSessions-1.08/lib/CGI/Session/ExpireSessions.pm
0668nobodyさん2006/11/02(木) 14:41:12ID:CDbXzZTv
一日以上更新されてないディレクトリとそのディレクトリに入ってるファイルを一括して削除するperlスクリプトが欲しいんですが、
どういう風に書いたらいいのか全く想像も付きません。どうか作っていただけないでしょうか?
0669nobodyさん2006/11/02(木) 14:52:52ID:???
ここは質問スレ
0670nobodyさん2006/11/02(木) 15:06:31ID:???
>>668
Perlでリクに答えるスクリプトを作るスレ
ttp://pc8.2ch.net/test/read.cgi/tech/1086143976/
0671nobodyさん2006/11/02(木) 15:14:36ID:???
作っていただけないでしょうか? ってのが質問なんだろ。
0672nobodyさん2006/11/02(木) 15:25:31ID:???
ここは質問スレ?ってのが質問なんだろ。
06736612006/11/02(木) 21:04:15ID:???
>>662
 すみませんわかりにくくて。

ttp://pc8.2ch.net/test/read.cgi/php/1137614836/l50#tag230

これをローカルで実験したくてperl5.6.1をダウンロードしてきてまず
while(($key,$value)=each(%ENV)){print "$key=$value\n";}
をコマンドプロンプトで実行したのですがIPアドレスとかが出ません。
web上でやったらうまくいったのですが、関数に制限があるらしく
BBQの方は試せません。どうやったらローカルでできるのでしょうか。
0674nobodyさん2006/11/02(木) 22:00:31ID:???
>>673
>>663を無視するな

というか、押したら開かないドアを引いたら開きました。どうやれば押したら開きますか?って質問してるんだぞ。
06756612006/11/02(木) 23:06:07ID:???
>>674
いまだに例えの意味がわかっていないのですが
use strict;
use Socket;
を入れたらBBQが動くのを確認できました。ヒントありがとうございました。
0676nobodyさん2006/11/02(木) 23:39:27ID:???
>>675
自分で出来ない理由をしっかり書いておいて、なぜ出来ないかを聞いてたから。

まぁ、動いたなら一歩前進だ。乙。
0677nobodyさん2006/11/03(金) 19:30:08ID:4xbbPPPU
こんばんは。質問です。
現在ホームページを作っていて、CGIでHTMLとCSSとJavaScriptを出力しようと思っているんですが。
何故かエラーが出ます。
因みに出力の方法はヒアドキュメントでくくって出力しています。
エスケープの問題でしょうか?
それともCGIスクリプトの中にJavaScriptを記述すること自体が不可能なんでしょうか?
どなたか教えてください。
0678nobodyさん2006/11/03(金) 19:51:29ID:???
>>643
これでいいんか?

open my $fh, ">>count.dat";
print $fh "\n";
close $fh;
print "Content-Type: text/plain\n\n";
print -s "count.dat";
0679nobodyさん2006/11/03(金) 19:52:45ID:???
>>678は誤爆スマヌ
0680nobodyさん2006/11/03(金) 19:59:44ID:???
>>668
sub{$_[0]->(@_)}->(sub{
my($code,$path,$del)=@_;
if(-d $path){
my $del2 = time-(stat$path)[9]>60*60*24;
opendir my $dh,$path;
while(my $dir = readdir $dh){
if($dir ne '.' && $dir ne '..'){
$code->($code,"$path/$dir",$del2);
}
}
closedir $dh;
rmdir $path if $del2;
}else{
unlink $path if $del;
}
},$_) for @ARGV;
0681nobodyさん2006/11/03(金) 20:11:29ID:???
>677
とりあえずコード晒してみ?
0682nobodyさん2006/11/03(金) 20:19:39ID:4xbbPPPU
>>681
長すぎてここには貼れません。
とりあえずCGIでJacaScriptが出力可能かどうか教えてください。
0683nobodyさん2006/11/03(金) 20:25:52ID:QgsncqtF
>>682
Javascriptといってもただのテキストデータだろ
もちろん可能
0684nobodyさん2006/11/03(金) 20:37:01ID:???
どうせ単にエスケープのミスしてるだけだろ。
$とか@とか%とか\とか。全部確認してみな。
0685nobodyさん2006/11/03(金) 23:05:08ID:???
>>677
エラーというのが、perl実行時のエラーなのか。
ブラウザに出力はされるが、javascriptの実行エラーなのか。
どんなエラーなのか。エラーメッセージはなにか。
ヒアドキュメントの内部で出ているエラーなのか。
などをまずは書きなされ。
「なぜかエラーが出る」といいなさるが、
プログラムは、意図したとおりにではなく、書いたとおりに動くのじゃ。
0686nobodyさん2006/11/04(土) 00:20:52ID:h08SADSk
意図した通りに動かない。これを「なぜか」と表現。
エラーメッセージはline5に書かれたヒアドキュメント
print >>END;
の部分。恐らく既に上がっているがエスケープをしてない文字列によるもののエラー。
実はエスケープは全くしてなかったのでerrorになるのは必然。
今回ここで聞きたかったのはそこではなくCGIでもJavaScriptは動くだろうというあやふやな知識を
確立しはたかった為。
問題は解決された。協力してくれた諸君に感謝する。
0687nobodyさん2006/11/04(土) 03:39:17ID:P6wQxe1H
sjisに変換する処理なのですが、Jcodeを使って下記のようにしています。

$value2 = Jcode::convert(\$value1, 'sjis');

これを、Encodeを使って書き直したいのですが、上記のように変換前の文字コード
を指定せずに処理する方法がわかりません。
検索して探したりしてみると、たとえば、utf8からeuc-jpに変換するコードとして、
Encode::from_to($text, "utf8", "euc-jp" );
などといったものがありますが、第一引数(この場合utf8)を省略しての記述方法
はありませんでしょうか?
0688nobodyさん2006/11/04(土) 03:51:21ID:???
>>687
Encode::Guess
省略というかエンコーディング名に"Guess"を指定する
0689nobodyさん2006/11/04(土) 04:26:21ID:???
>>688
とりあえずうまくいったようです。
ありがとうございました!
0690nobodyさん2006/11/04(土) 13:39:03ID:???
php で HTMLのヘッダーなどを require_once するようなことを、Perl でやりたいと考えています。
理由は、今まで Perl + SSI でやっていたので、2重に実行環境が呼び出されて負荷が高いと思われるので、(SSIの負荷はPerlに比べれば少ないですが) Perlのみでやってみたいからです。

----- test.cgi -----
#!/usr/bin/perl
print 'Content-Type: text/html' . "\n\n";
require 'test.html';
exit;

----- test.html -----
print << '_HTML_';
<html>
<head>
<title>テスト</title>
</head>
<body>
<h1>テスト</h1>
<p>ちゃんと表示されるかな。</p>
</body>
</html>
_HTML_
1;

ヒアドキュメント部分を print << "_HTML_"; では無く、print << "_HTML_"; にしたら、
文字コードが Shift_JIS であっても、駄目文字が使えてこのままでも結構いいのですが、
test.html に HTML以外のPerl命令 (上1行と下2行) をいれないといけないのが、
美しくないかなーと思いまして。

綺麗なコードでこのようなことをやる方法をご存知の方がいたら教えてください。
0691nobodyさん2006/11/04(土) 13:52:42ID:???
HTML::Templete
0692nobodyさん2006/11/04(土) 13:58:02ID:???
>>690
意図が今一つかめんのだが以下の方法じゃあかんのか?
----- test.cgi -----
#!/usr/bin/perl
print 'Content-Type: text/html' . "\n\n";
print <DATA> ;
__DATA__
<html>
<head>
<title>テスト</title>
</head>
<body>
<h1>テスト</h1>
<p>ちゃんと表示されるかな。</p>
</body>
</html>
06936902006/11/04(土) 14:05:18ID:???
>>691
ありがとうございます。
そのモジュールにも興味が出てきたので、機会があったら使ってみます。

>>692
多数のCGI (とHTMLファイルに含まれるSSI) から include したいので、別ファイルにしたいと思ってたんです。
教えていただいた通りのコードで、やりたいことができそうです。
ありがとうございました。

----- test.cgi -----
#!/usr/bin/perl
print 'Content-Type: text/html' . "\n\n";
open DATA "test.html";
print <DATA>;
exit;

----- test.html -----
<html>
<head>
<title>テスト</title>
</head>
<body>
<h1>テスト</h1>
<p>ちゃんと表示されるかな。</p>
</body>
</html>
0694nobodyさん2006/11/04(土) 14:09:19ID:???
そういや、ファイルを開く目的では open じゃなくて sysopen 使えって話もあるんですが、どうなんでしょう。

http://www.ipa.go.jp/security/awareness/vendor/programming/a04_01_main.html

負荷が同じ程度なら sysopen でもいいですが、OSの関数ダイレクトってことなので
sysopenのが重いんじゃないかな、と思ったんだけどちゃうかな
06956902006/11/04(土) 14:44:33ID:???
実行したらエラーにorz
test.cgi のソースに問題があったようです。

修正版は次の通りです。

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

print 'Content-Type: text/html' . "\n\n";

open(DATA, "< test.html");
print <DATA>;
close(DATA);

exit;

0696nobodyさん2006/11/04(土) 17:03:05ID:???
>>694
結局どちらもOSのopenに行くところは一緒で余計な機能がない分
sysopenの方が軽いともいえるが普通は気にするほどの差はない。

しかしこれ書いた人3引数open知らないのだろうか?
0697nobodyさん2006/11/04(土) 21:40:25ID:foW9asSJ
ホームページをcgiで全てのページを表示していますが、
mixiのようにhttp://〜.plの様にしたいのです。
そのままperlを表示しようとするとダウンロードになったしまいます。
よろしくお願いいたします。
0698nobodyさん2006/11/04(土) 21:54:00ID:???
>>697
それはPerlではなくサーバー側の設定によります。
例えば Apache の場合 .htaccess で設定できる可能性があります。
詳しい方法は、検索するなり、お使いのサーバーソフトウェアのスレにいくなり、
借りているウェブスペースの管理者に問い合わせるなりしましょう。
0699nobodyさん2006/11/04(土) 22:59:12ID:foW9asSJ
>>698 さん
有難うございます。
結構調べたんですが、全く出てきませんでした。
サーバーはApacheなんで調べてみます。
0700nobodyさん2006/11/04(土) 23:31:40ID:???
つ AddHandler cgi-script .cgi .pl
0701nobodyさん2006/11/06(月) 14:38:08ID:???
アクセスの多いサイト (10万PV/day) で CGI のマルチバイトXSS対策したらその時期から負荷(uptime) が一気に倍近くなりました。
(因果関係はまだはっきりしていませんが、時期が一致したし、CGIの負荷が増えたと思われるので、その可能性が高いと考えてます。)
Perl のバージョンは v5.8.6 で OS は Fedora Core 4 です。

CGI に加えたコードは、モジュール "Encode" の読み込み (use Encode;) と、
POST時に送信されたデータに対して "$_ = encode('sjis', decode('sjis', $_));" を加えたぐらいです。
後者のロジックではせいぜい10程度のデータに対して encode と decode をしているだけだし POST数はそんな多くないんで、
"use Encode;" が負荷の原因だと思われます。

DoCoMoのケータイからのアクセスで最後の方に Shift_JIS として不正なデータが含まれてしまったりすることもあるんで、(DoCoMoのブラウザのバグか電波が不安定なのかは知りません。)
Shift_JISとして不正なデータが含まれた場合にも「エラー処理」でなく「不正な文字列の削除(エスケープ)」としての対処を行いたいです。

"use Encode;" を使わずに、低負荷でこの処理を行う方法はないでしょうか?
>>116 で大丈夫ですかね。
0702nobodyさん2006/11/06(月) 15:51:19ID:???
>>701
> CGI のマルチバイトXSS対策
前スレか前々スレでその話題があったので参考にするとよろし
0703nobodyさん2006/11/06(月) 16:04:47ID:???
>>701
たとえ10万PV/dayであろうとも、POST数がそんなに多くないのならCGIの負荷が
多少かわったところで影響は大きくなさそうなものだ。それともPOST以外でも
CGIがkickされまくっていて不要なuse Encodeをしているという話だろうか??

性能問題は本当に性能のボトルネックになってるところを突き止めて対策しないと
骨折り損になるよ。
0704nobodyさん2006/11/06(月) 16:18:18ID:???
「不正な文字コードが見つかれば、以降の文字はすべて無効」でOKなら116で問題ないかと。
場合によっては \t \r \n も不正な文字として扱う必要があるかもしれないけど。

use Encodeって結構コストが高いからなぁ。
まぁ、因果関係がまだはっきりしてないんだったら、もう少し調べてみたほうがよいかもね。
0705nobodyさん2006/11/06(月) 16:30:09ID:???
ちょいと調べてみたがuse EncodingはうちのP3-1GHzといういささか時代遅れなPCで50msぐらい
CPU食うようだ。これはちょうどuse CGIと同じぐらい。無視できる量ではないがとてつもなく大きい
わけでもないな。もとがぎりぎりならきびしいかもしれないが。
0706nobodyさん2006/11/06(月) 16:30:59ID:???
ごめん、use Encodingじゃなくてuse Encode。
0707nobodyさん2006/11/06(月) 16:51:09ID:???
Win+Active Perlで、コマンドプロンプトを開いて、
Encode、Jcode、CGI、GD、IO::Handle、Time::HiRes…
とどんどんuseしていくと一気に遅くなるのが分かる
0708nobodyさん2006/11/06(月) 17:10:00ID:???
これでTemplate Toolkitなんか使った日にはCGIじゃ重すぎなわけだが、
モジュール削って不便なプログラミングで苦労するよりはmod_perlなり
fastcgiなり使ったほうが幸せになれる気がする。
07097012006/11/06(月) 17:45:18ID:???
>>702
このスレにあったようなので読みました。

>>703
> それともPOST以外でもCGIがkickされまくっていて不要なuse Encodeをしているという話だろうか??
#!/usr/bin/perl の次の行で use Encode; をしています。(10万PV/日の CGIで)

マルチバイトXSSの対策前の部分で use Encode; しても大丈夫なんでしょうか? 試してみます。
use は一番上でやるもんだと思ってました。

ただ、ループ内でやると、use Encode が何度も実行されることになるので、変数でフラグたてて1回のみやるようにしてみますね。
それでうまく動かなかったら正規表現でやってみます。


> 性能問題は本当に性能のボトルネックになってるところを突き止めて対策しないと
> 骨折り損になるよ。
ですね。
さっき当該部分(マルチバイトXSS対策)のコードを消してしばらく動かしているんですが、負荷は少し減っているような気がします
グラフのデータが少なくてまだ確実とはいえないので、1日ぐらいこのまま動かしてMRTGのグラフで比較してみますね。

>>705
もとがぎりぎりではないんですが、MRTGのグラフ (Load Average 5min 15min) でいままでピークでも60%ぐらいが上限だったのに、
ピークで100%ぐらいにいくようになったんです。面積をよくみると、2倍まではいってなくて、もとの1.5倍ぐらいかも。

>>707
なるほど

>>708
自分が作ったのではないコードが含まれていてぐちゃぐちゃなので mod_perl はきびしそうです
グローバル変数多用、同じようなコードを関数を使わずに何度もかいていたり同じエスケープ処理を何箇所かでやってたりで
とにかくぐちゃぐちゃです;;
0710nobodyさん2006/11/06(月) 17:58:01ID:???
>>709
CGIはたくさん起動されているが本当にEncodeモジュールを必要とする場合が少ないのならば、
確かにもったいないね。可能なら機能ごとに別のプログラムに分離したほうがいいんじゃないか
とも思うが、いまさらそれも無理なら小手先の対策として、Encodeモジュールを必要とするとき
のみuseするのがいいだろう。

ただし普通にuse書いてしまうとどこに書いてあっても最初にプログラム読み込むときにuseされて
しまうので、必要なときだけ eval 'use Encode;';するのがいいと思われる。ブロックではなく
文字列のevalを使うのが肝。
0711nobodyさん2006/11/06(月) 20:29:39ID:???
>>701
これはPHPの中の人のブログだが、一度読んでおくことを勧める
ttp://blog.ohgaki.net/index.php/yohgaki/2006/06/12/
07127012006/11/06(月) 20:56:58ID:???
>>711
レスありがとうございます。
教えていただいたサイトを読ませていただきました。

不正なデータを 「サニタイズ」 した結果、他の有害なデータになってしまうということは良くありますね。
上位のファイルの読み出しを禁止するために 「../」 を削除するコードにしたら、「..././」 → 「../」 となってしまうというのが有名な例です。
こういった問題が発生しないよう良く考えてみることにします。

不正な文字コードが含まれていたらエラーを返す、というのが理想かもしれませんが、それをやるとアクセシビリティ上の問題が発生してしまいます。
例えば、そのサイトで推奨している mb_check_encoding 関数の場合でもそうですが、「@」とか「T」が含まれていただけでも、エラーになりますし、
ケータイからですと顔文字が1つ含まれただけでエラーになります。(Shift_JISの場合に確認、他の文字コードでも発生すると思われます。)

データベースは使っていないし、データベースについての知識はないのでそれについては分かりませんが、HTMLとして出力したりファイルに出力したりする
普通のCGIで入力段階 (他のチェック前) で不正な文字列を 「削除」 した場合には、発生するおそれのある脆弱性がおもいあたりません。
勿論、他のチェックのあとでやればそれによって、他のチェックが無効になり危険ですが…。
0713nobodyさん2006/11/06(月) 21:21:16ID:???
壊れた文字は「絶対」に削除しない。ってのは誤解を招きそうな表現だね。
正常な文字以外は通すな。
削除しただけで正常な文字になると思うな。
って、言いたかったんでないかの。

文字コードのチェック→(不正文字は排除済みとみなした上で)サニタイズ。
この流れで十分でしょう。
07147012006/11/06(月) 21:31:38ID:???
>>713
解説ありがとうございます

UTF-8 の構造は複雑でまだ理解できていませんが、Shift_JIS や EUC-JP の場合には
バイナリレベルで 「2バイトで1文字となる範囲のバイナリデータが1文字目にある(単独で存在する)」 場合にそれを削除すれば、
マルチバイトでのXSS問題に限れば完璧に回避できますね。(2バイト連結文字の1バイト目の文字がなければ問題は発生するわけがないので。)
また、1バイト=8bit を区切りにして操作を行えば、削除によってまた他の不正なマルチバイト文字列ができあがることはないはずです。

0715nobodyさん2006/11/06(月) 22:54:18ID:???
eucには3バイト文字もあるわけだが
0716nobodyさん2006/11/07(火) 00:30:07ID:???
○の1をEUCにすると3バイトじゃなかったか

XSS脆弱性はそんなに単純じゃない。たとえば、0x5Cの問題。
0717nobodyさん2006/11/07(火) 20:13:30ID:???
>>716
> たとえば、0x5Cの問題。
それについて興味があるので詳細を教えていただけないでしょうか?
もし、無理ならば Shift_JIS の問題か EUC-JP の問題かだけでも教えていただけたらさいわいです。
0718nobodyさん2006/11/07(火) 20:50:37ID:???
0x5C でググれ
0719nobodyさん2006/11/07(火) 22:21:56ID:???
ありえないぐらい低レベル
0720nobodyさん2006/11/07(火) 23:25:16ID:???
初心者質問スレなんだからイインダヨ
07217012006/11/08(水) 00:25:38ID:???
>>715-716
EUC-JPには3バイト文字もあったんですか・・・。
EUC-JPに関する知識が不十分で申し訳ありませんでした。
お詫び申し上げます。
■ このスレッドは過去ログ倉庫に格納されています