• 締切済み

cgiのログの書き方

ここで教えてもらってログファイルの書き方(挿入のようなカンジで)をやってみたんですが、どうしても思い通りの動きをしません。 希望としては、IDが一緒なら、その同じIDの下に書き込みを行う。同じIDが見つからなければ、一番上に書き込みを行う。 というようにしたいのです。 上記のことを行うために以下のコードを書きました。 --------------- for ($w=0;$w<$gyou+1;$w++){ @log3 = split(/&/,$log2[$w]); foreach(@log3){ ($keyw,$valuew) = split(/=/,$_); $FORMw{$keyw} = $valuew; }#foreach open(FH3,">>log.log"); if ($ID == $FORMw{'ID'}){ print FH3"ID=$ID&COUNT=$COUNT&TITLE=$TITLE&NAME=$NAME&PASSWORD=$PASSWORD&NAKAMI=$NAKAMI&COLOR=$COLOR&TIME=$year/$m on/$day $hour:$min:$sec&SEARCHKEY=$year$mon$day$hour$min$sec\n"; last; } else { if($w+1 == $gyou){ print FH3"ID=$ID&COUNT=$COUNT&TITLE=$TITLE&NAME=$NAME&PASSWORD=$PASSWORD&NAKAMI=$NAKAMI&COLOR=$COLOR&TIME=$year/$m on/$day $hour:$min:$sec&SEARCHKEY=$year$mon$day$hour$min$sec\n"; close(FH3); } } }#for --------------- どうしてもログファイルの最新情報としてしか書き込みがされません。 また、最新ログを1番上に書き込む、ということをしたいのですができますか? 日付順などで並べ替えをしてしまうと、ぐちゃぐちゃになってしまうので、並べ替えを行わずに、です。 またこのような書き込みの仕方をしなくても、 例えば並べ替えで、Excelみたいに、1番目と3番目を基準に並べ替え、とかでできますか? (私は1つの方法でしか知らないので、どうしても意図する順番になりません。)

  • Perl
  • 回答数5
  • ありがとう数10

みんなの回答

  • estea
  • ベストアンサー率44% (39/87)
回答No.5

はい。ごめんなさい。バグってます。 > 4.追加したいIDかを判断する。追加したいのであれば 5、そうでなければ 6 へ。 >5.まず $lines[$a] を書き出し。 で、次に%FORMを整形して書き出し。 >6.$lines[$a]を書き出し。 ># 4. 5. 6. は まとめると以下の4行.... >  print $line; >if( $ID == $FORMw{ID} ){ >   print LOG "ID=$ID&COUNT=$COUNT&TITLE.... とあるうちの >  print $line; は   print LOG $line; の誤りでした。

  • feininger
  • ベストアンサー率41% (74/180)
回答No.4

> しかし、「同じIDがあった場合、それの下に書き込む」ができません。 フラグが必要かと。こんな感じ↓ $insert_line = 挿入したい行; $flag = 0; foreach (読み込んだログ) {  $current_line = $_;  if ($flag == 0) {IDが一致したら$flag = 1;}  if ($flag == 1) {IDが異なったら$insert_lineをログに書き込み; $flag = 2;}  $current_lineをログに書き込み; } if ($flag < 2) {$insert_lineをログに書き込み;} 終了;

KODAMAR
質問者

お礼

みなさま回答ありがとうございました。 自分なりのやり方でなんとかできました。 (大分遠回りのやり方ですが、こうでもしないと自分でわからないので) 方法としては、 ●IDが一致したものの前までのログ ●IDが一致したものの親ログ ●IDが同じ書き込み(実際の入力) ●それ以降のログ にわけ、それぞれを書き込むようにしました。

  • estea
  • ベストアンサー率44% (39/87)
回答No.3

全体的なソースが出てきて全容がつかめそうなのですが、何がしたいかふめいでつ。何処と聞かれれば全体ですと答えるしか・・・ 私が全部書き直していいのですか? 先にも書きましたが、流れに沿ってもう少し具体的に書きましょう・・・。 1.ログファイルを全部 @lines に読み出す。  open(LOG,"log.log");  @lines = <LOG>;  close(LOG); 2.読み出しに開いたファイルを閉じて書き込み用に開ける( ">>" では無く ">" です。)  open(LOG,">log.log"); 2.foreach などで @lines を順番に以下のことを行なう foreach $line(@lines){ #foreach1 3.$lines[$a] などに対して各データに分ける( split ~ ってやつ。)   foreach(split(/&/,$line)){ #foreach2 >  ($keyw,$valuew) = split(/=/,$_); >  $FORMw{$keyw} = $valuew; > } #foreach2 #↑一応こんなのでいいはずだが <> や タブ なんかで分けてると #ココがもっと楽。 4.追加したいIDかを判断する。追加したいのであれば 5、そうでなければ 6 へ。 5.まず $lines[$a] を書き出し。 で、次に%FORMを整形して書き出し。 6.$lines[$a]を書き出し。 # 4. 5. 6. は まとめると以下の4行....   print $line; if( $ID == $FORMw{ID} ){    print LOG "ID=$ID&COUNT=$COUNT&TITLE....   } } #foreach1 clsoe(LOG); ########################################## ・・・大分変わっちゃいました。上記ソースは当然動作未確認... で、示していただいたソースの問題点は以下のとおり。 1. if($ID=.... の扱い。 if で囲まれた中にしか print 命令が無い 2. split で & や = を切っているが一考の余地あり。データのフォーマットを再考してください。 3. last が不明。 for の中の if の中の for といったネストが微妙。 ##################################### で、今になって誤解が発覚したのだが、 追加したデータって $ID とか $COUNT だったのな。 %FORMw だと思ってた。 なもんで、以前までの投稿は微妙に間違ってた。すまぬ。

KODAMAR
質問者

お礼

回答ありがとうございます。 ログファイルを開く時に>(書き込み)で開くと、どうしてもすべてのログが消えてしまうのですが。 それとご指摘の通り、ログファイルを<>で区切るようにしました。 ($ID<>$COUNT<>$TITLE…というカンジです。) これですとどんなカンジになりますか? 今自分でつくった流れとしては トップページ(新規入力→Aへ。 返信入力→Bへ) A フォームを表示。 ログファイルを開き、すべてのIDを調べ、1番大きなIDに1を足したものをIDとしてわりあてる。 ログファイルの中身が空っぽならそのままログファイルへ書き込み。 すでにログファイルの中身があれば、現在入力されたデータ+すべてのログファイルという形で書き込みを行う。 ($COUNTはすべて1) B 返信入力なので、親書き込みのIDをわりあて。 $COUNTは親IDの$COUNTに1を足す。(なので2となる) ログファイルを開き、同じID(親書き込み)を探す。 同じIDがみつかったらその下の行へ書き込みを行う。 親IDが1番下とは限らないので、真ん中だったり一番下への書き込みとなる。 (返信なので1番上はありえない。) となってます。 Aはすべてできました。 Bの4行目でひっかかっています。 教えていただいたものを実行してもログが消えてしまいます。 どうぞよろしくお願いします。

  • estea
  • ベストアンサー率44% (39/87)
回答No.2

どもも。 ログってことですが、何を目的にしているかにもよりますが余りいただけない書式ですな・・・ ファイルに記述する場合は、 form から取るときと違って、& で区切られた各値が前後することは絶対にありませんので。 ID=$ID&COUNT=$COUNT..... というのは、それはそれで目的があるならいいのですが単にデータを記録するだけなら たとえば <> や , や タブ符で各値を区切って、 $ID<>$COUNT..... とするほうが良いかもしれません。何かと楽ですす。 で、何が楽かってと、最初の部分でやってる split とか for で回してる部分がもっと効率的に欠けます。 で、話を戻して、追加の方法ですが簡単には以下のようになります。 1.ログファイルを全部 @lines に読み出す。 2.読み出しに開いたファイルを閉じて書き込み用に開ける( ">>" では無く ">" です。) 2.foreach などで @lines を順番に以下のことを行なう 3.$lines[$a] などに対して各データに分ける( split ~ ってやつ。) 4.追加したいIDかを判断する。追加したいのであれば 5、そうでなければ 6 へ。 5.まず $lines[$a] を書き出し。 で、次に%FORMを整形して書き出し。 6.$lines[$a]を書き出し。 見たところ、 $FORMw の書き出しが含まれていませんな。これを"追加"すればいいと思われ。 あと、ログの最初に追加するってのはもっと楽で、全ファイル内容を @lines に読み取ってそこに整形した $FORMw のデータを unshift して、 @lines を書き出すのが一番楽かと。 (seek はめんどくさい...) まだまだ続いて... 複数値によるソートですが、可能です。が、少々面倒で ハッシュを用いたソートでしょうか。

KODAMAR
質問者

お礼

回答ありがとうございます。 どうにか新規書き込み(ログの一番上に書き込む)はできました。 しかし、「同じIDがあった場合、それの下に書き込む」ができません。 下記のようにしてみたのですが…。 open(FH2,"log.log"); @log2 = <FH2>; close(FH2); $gyou = @log2; for ($w=0;$w<$gyou+1;$w++){ @log3 = split(/&/,$log2[$w]); foreach(@log3){ ($keyw,$valuew) = split(/=/,$_); $FORMw{$keyw} = $valuew; }#foreach if ($ID == $FORMw{'ID'}){ open(FH3,">>log.log"); @loglog2 = <FH3>; for($r=0;$r<$gyou+1;$r++){ if($r == $w){ print "wは?$w<BR>\n"; print "rは?$r<BR>\n"; print FH3"ID=$ID&COUNT=$COUNT&TITLE=$TITLE&NAME=$NAME&PASSWORD=$PASSWORD&NAKAMI=$NAKAMI&COLOR=$COLOR&TIME=$TIME&S EARCHKEY=$SEARCHKEY\n"; #print FH3"$ID<>$COUNT<>$TITLE<>$NAME<>$PASSWORD<>$NAKAMI<>$COLOR<>$TIME<>$SEARCHKEY\n"; close(FH3); last; }# if }#for last; : : どこを直せばいいのでしょうか?

回答No.1

ぱっと見た感じですが、 おそらく@log2(にデータが入っていて)を分解、 そのIDと今回投稿されたID比較してるのですよね? いくら途中で振り分けても、 print FH3 ~~ と同じように両方とも書き込んでいるので、 両方とも同じくなるのは当然かと思います。 既に@log2にデータが丸ごと入ってるなら、 それに新しいデータを追加して、 全体を書き込んだ方が処理は楽だと思いますよ。 (新しいデータを途中に埋め込む場合は) >最新ログを1番上に書き込む、ということをしたいのですができますか? seek をキーワードに検索してみてください。 >1番目と3番目を基準に並べ替え これももちろんできますが、結構面倒です(^^; sort関数を調べてみると色々例がのっています。 ところで、 何回もファイルが重ねて開かれてるような・・ しかもきちんと閉じてないような・・(苦笑) open~closeとそれにともなうseek/truncateなどや、 ファイルロックについてもう一度確認されてみるといいと思います。 #蛇足ですが、print @sort と print "@sort" "@sort"はPerlが自動的に半角のスペースをいれるのです。 @data = qw(this is useful); print "@data"; #this is useful print @data; #thisisuseful となります。 (つまり、特別に配慮されているということでしょうか) なお、$" で変更できます。

KODAMAR
質問者

お礼

回答ありがとうございます。 ちょっと今すぐに全部には答えられないので、さしあたって少しだけ補足させていただきます。 >>最新ログを1番上に書き込む、ということをしたいのですができますか? >seek をキーワードに検索してみてください。 はい、seek関数に私も行き着きました。 それでつかってみたのですが…どうもちゃんとしてないみたいなんですけど…。 seek(FH3,0,0); print FH3"ID=$ID&COUNT=$COUNT&TITLE=$TITLE&NAME=$NAME&PASSWORD=$PASSWORD&NAKAMI=$NAKAMI&COLOR=$COLOR&TIME=$TIME&SEARCHKEY=$SEARCHKEY\n"; でログファイルの1番最初に入力される(はず)なんですよね? 1番最後に入力されてしまうのですが…。

関連するQ&A

  • ローカルだと改行されるのに、サーバーにアップすると半角・が…

    ローカルでテストすると、きちんとログファイルに改行と認識され、 NAME=***&……TIME=20040515 NAME=***&……TIME=20040516 のように書き込まれますが、サーバーにアップすると、 NAME=***&……TIME=20040515・NAME=***&……TIME=20040516・ のようになってしまいます。 書き込みは以下のようにしています。 open (FILE2,">>log.log"); @fw = "NAME=$FORM{'NAME'}&…&TIME=$year/$mon/$day $hour:$min:$sec&TIME2=$year$mon$day$hour$min$sec\n"; print FILE2 @fw; close(FILE2); なぜでしょうか? 解決策お願いします(><)

    • ベストアンサー
    • Perl
  • ログの記録方法について

    現在、以下のように記録する最大数を超えた場合、 古いデータは1行削除、新規データは追加するようにしてるのですが これを最大数を超えた場合にはfile.txtのすべてデータを 別に自動生成した過去ログファイルに記録し、 また過去ログファイルは最大5ファイルまで作成したいのです。 もしやり方が分かるようでしたらお手数ですがお教えいただけませんか? $maxlog = $logmax; #ログファイルの場所 $comment =~ s/\n//g; ($sec,$min,$hour,$day,$mon,$year,$wday,$dmy,$dmy) = localtime(time); $year = 1900 + $year; $mon++; if ($mon < 10) { $mon = "0$mon"; } if ($day < 10) { $day = "0$day"; } if ($hour < 10) { $hour = "0$hour"; } if ($min < 10) { $min = "0$min"; } $date = "$year\/$mon\/$day $hour\:$min"; # ログファイル読込 open LOG,$file; @log = <LOG>; close LOG; # 先頭に新規ログデータを追加 unshift (@log,"$date<>$mailto<>$comment<>$agent<>$host<>$toki<>\n"); # 保存行数を超える分末尾を削除 while(@log > $maxlog){ pop @log; } # 更新されたデータでログファイルに上書き open LOG,">$file"; print LOG @log; close LOG;

    • ベストアンサー
    • Perl
  • ログファイルに余計なスペース

    以前も同じような質問をして回答をいただいたのですが、 ちょっと状況がかわったので再度質問させていただきます。 以前は print FILE"@log"; とするとスペースが入る、としたところ print FILE @log; とすればOKという回答をいただき、解決していたんですが、 今回は print FILE"$ID<>$COUNT<>$TITLE<>$NAME<>$PASSWORD<>$COLOR<>$NAKAMI<>$TIME<>$SEARCHKEY\n@log_file"; としたいのです。 やはり半角スペースが行頭に入ってしまいます。 これを回避するにはどうしたらいいですか?

  • cgiログファイルの書き込みに余計なスペースが入る。

    ---------- #ここでログファイルに書き込みを行う。 open(FH,">>log.log"); print FH"ID=$ID&COUNT=$COUNT\n"; close(FH); #ログファイルをさらに開く。 open FILE, "<log.log"; flock(FILE,2); @log = <FILE>; flock(FILE,8); close FILE; ログファイルを並び替えてその順番で書き込み。 $gyou = @log; @sort=sort{(split(/&/,$b))[1] cmp (split(/&/,$a))[1];} @log; print "<FONT COLOR=RED>@sort</FONT><BR>\n"; open(FILE2, ">log.log"); print FILE2"@sort"; close (FILE2); ---------- というように行っていますが、一番最初のID=01&とかの前に半角スペースが入ります。 下の行に行くほどスペースが増えます。 どこが原因でしょうか?

    • ベストアンサー
    • Perl
  • CGIについて(時間表示)

    CGI初心者ですが、掲示板を作成中です。投稿するたびにメッセージの投稿時間がすべて現在時刻に書き換わります。 メッセージ毎に時間表示させたいのですが、いかのプログラムのどこを変更すればよいのでしょうか?宜しくお願いいたします。 # 時間処理 sub totime { ($sec,$min,$hour,$mday,$month,$year,$wday,$yday,$isdst) = localtime(time); $year +=1900; $month++; $year = sprintf("%04d", $year); $month = sprintf("%02d", $month); $mday = sprintf("%02d", $mday); $hour = sprintf("%02d", $hour); $min = sprintf("%02d", $min); $sec = sprintf("%02d", $sec); $date = "$month/$mday $hour:$sec"; }

    • ベストアンサー
    • CGI
  • setTimeout()が使えない

    今、JavaScriptでリアルタイムで動く時計を作ってるのですが、setTimeoutが動かないため使えません。 時刻は表示するのですが、自動更新してくれません。 JavaScriptのサイトの時計は動いているんですけど、自分の作ったのだと動いてくれません。 ---- function Clock() { dd = new Date(); Year = dd.getFullYear(); Mon = dd.getMonth()+1; Date = dd.getDate(); Days = new Array("日","月","火","水","木","金","土"); Day = Days[dd.getDay()]; AMPM = ""; Hour = dd.getHours(); Min = dd.getMinutes(); Sec = dd.getSeconds(); if (Hour > 12) { Hour = dd.getHours()-12; AMPM = "午後"; } else { AMPM = "午前"; } if (Hour < 10) Hour = "0"+Hour; if (Min < 10) Min = "0"+Min; if (Sec < 10) Sec = "0"+Sec; document.myForm.Time.value = Year+"年"+Mon+"月"+Date+"日("+Day+") "+AP+Hour+"時"+Min+"分"+Sec+"秒"; setTimeout("Clock()", 1000); } ---- 「<body onLoad="Clock()">」はしています。

  • CGIのライブラリ表示について。

    初心者で申し訳ございません。 今現在、参考書を読みながら時間を表示するCGIを作っています。 フォルダ"time1"に二つのファイル"time1.html"と"time1.pl"があります。 それぞれのファイルは、本を参考に次のように記述しています。 ===time1.html=== <html> <title>time1</title> <body> <h1>時間を表示する</h1> <hr /> <!--#exec cmd="./time1.pl"--> </body> </html> ====== ===time1.pl=== #!/usr/local/bin/perl ($sec, $min, $hour, $day, $mon, $year, $wdy, $yday, $isdst) = localtime(time); @youbi = ("日", "月", "火", "水", "木", "金", "土"); $year += 1900; $mon++; print "$year-$mon-$day, @youbi[$wdy], $hour:$min:$sec\n"; exit; ====== 以上をIE7で表示しますと、 「時間を表示する」は表示されるものの、.plファイル内の時間が表示されません。 何かやり残していることがありますでしょうか。 申し訳ございませんが、よろしくお願いいたします。

    • ベストアンサー
    • CGI
  • 次のカウンターのCGIプログラムで間違っているところはどこでしょうか?

    参考書を手にしながら次のようにCGIを作成しましたが、上手く動きません。 個人別カウンター(アクセスしてきた個人ごとにカウンターが変わる)CGIです。 いろいろ調べたのですが、どこが間違っているのか分からなくなりました。 どうぞお願いいたします。 ======= #!/usr/local/bin/perl $cookie = $ENV{'HTTP_COOKIE'}; @array = split(/; /, $cookie); foreach $tmp (@array){ ($key, $value) = split(/=/, $tmp); if($key eq 'count'){ $count = $value; } } if( $key == ""){ $count = 0; } $count++; ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = gmtime(time + 60*60*24*30); @day = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "sat"); @month = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Set", "Oct", "Nov", "Dec"); $expireDate = sprintf("%s\, %02d\-%s\-%04d %02d:%02d:%02d GMT", $day[$wday], $mday, $month[$mon], $year+1900, $hour, $min, $sec); print "Content-Type: text/html\n"; print "Set-cookie: count=$count; expires=$expireDate \n\n"; Print "<html>\n"; Print "<title>counter4</title>\n"; print "<body>\n"; print "<h1>個人別カウンター</h1>\n<hr />"; print "あなたは$count回目のご訪問です。\n"; print "</body>\n"; print "</html>"; exit;

    • ベストアンサー
    • CGI
  • Perlで日付を取得する

    Perlで日付を取得する perlで1週間分の日付を取得し、セレクトボックスに格納したいと思っています。 なるべくいま使っているサブルーチンを使いたいです。 # 現在日時を文字列化する sub get_date_string { # local(@week) = ("日", "月", "火", "水", "木", "金", "土"); local(@week) = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"); local($sec, $min, $hour, $day, $mon, $year, $weekday) = localtime(time); $year += 1900; $mon++; # 文字列化する if ($hour < 10) { $hour = "0$hour"; } if ($min < 10) { $min = "0$min"; } if ($sec < 10) { $sec = "0$sec"; } $weekstr = $week[$weekday]; return "$year-$mon-$day ($weekstr) $hour:$min"; # return "$year年$mon月$day日 ($weekstr) $hour時$min分$sec秒"; } これを別のルーチンで、 $today = substr(&get_date_string,0,10); $kinou = $today - 1; $ototoi = $today - 2; として、今日の日付だけでなく、昨日、おととい、その前の日を取得したいと試みましたが、今日は取得できても、$kinouや$ototoiは、すごい数字になってしまいます。 変わりに -24*3600と引いてみましたがダメでした。 文字列に変更されていないから引けないのでしょうか? かんたんに処理できそうでできないので、詳しいやり方を教えてください。

    • ベストアンサー
    • Perl
  • 「誕生日まであと○日です」

    <html> <head> <title>test</title> </head> <body> <SCRIPT LANGUAGE="javascript" TYPE="text/javascript"> <!-- var weeks = new Array('日','月','火','水','木','金','土'); var now = new Date(); var year = now.getYear(); // 年 var month = now.getMonth() + 1; // 月 var day = now.getDate(); // 日 var week = weeks[ now.getDay() ]; // 曜日 var hour = now.getHours(); // 時 var min = now.getMinutes(); // 分 var sec = now.getSeconds(); // 秒 if(year < 2000) { year += 1900; } // 数値が1桁の場合、頭に0を付けて2桁で表示する指定 if(month < 10) { month = "0" + month; } if(day < 10) { day = "0" + day; } if(hour < 10) { hour = "0" + hour; } if(min < 10) { min = "0" + min; } if(sec < 10) { sec = "0" + sec; } document.write('今日:' + year + '年' + month + '月' + day + '日'); // --> </SCRIPT> </body> </html> これで今日の日付けは表示できたのですが 誕生日が7/31なのですが document.writeで 「誕生日まであと○日です」 と表示するにはどうすれば良いでしょうか?

    • ベストアンサー
    • HTML

専門家に質問してみよう