#!/usr/bin/perl #------------------------------------------------------------------------------- # unico diary system v2.0.1 # (旧 PINKGUN DIARY から改称) # 19980413 first. 20010725 modified # script by az* http://www.azworks.org/~az/ #------------------------------------------------------------------------------- # 一行目の Perl のパスと必須設定を書き換えて、 # 適切なパーミッションを設定すればとりあえず動きます。 # 詳しい設置方法はマニュアル(配布アーカイブに同梱)をご覧ください。 #------------------------------------------------------------------------------- # 必須設定。 #------------------------------------------------------------------------------- $logfile = './u_diary.dat'; # ログ保存ファイル $template = './template.html'; # 表示用テンプレートファイル $script = './u_diary.cgi'; # このスクリプトのファイル名 $css = './unico.css'; # 管理画面等用CSSファイル $jcode = './jcode.pl'; # jcode.plの場所 $password = '840818'; # 管理者モードパスワード *必ず変更する!! #------------------------------------------------------------------------------- # 各種カスタマイズ項目 #------------------------------------------------------------------------------- $d_max = 10; # デフォルト表示件数 $max = 50; # 最大記録件数 $link = 'on'; # オートリンク機能のon/off $target = ' target="_blank"'; # オートリンク時のターゲット属性 $link_max = 40; # オートリンク時の見かけのURLの長さ制限 $w_reg = 'off'; # 二重書きこみ防止機能のon/off #------------------------------------------------------------------------------- # 日付時刻 #------------------------------------------------------------------------------- # 日付表示フォーマット(運用中でも変更が反映されます) $date ='%y.%m.%d'; # 詳細はマニュアル参照。 # 以前の設定はこうなります # en xxxx/xx/xx xx:xx:xx => $date ='%Y/%m/%d %H:%I:%S'; # en2 xxxx/xx/xx => $date ='%Y/%m/%d'; # jp xxxx年xx月xx日 xx時xx分xx秒 => $date ='%Y年%m月%d日 %H時%I分%S秒'; # jp2 xxxx年xx月xx日 => $date ='%Y年%m月%d日'; # pp xx月 xxにち (ポスぺ風)=> $date ='%m月 %dにち'; @month = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); # 月のテキスト形式指定 @week = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); # 曜日のテキスト形式指定 @m = ('am','pm'); # 午前/午後 #------------------------------------------------------------------------------- # セキュリティ関連 #------------------------------------------------------------------------------- @tag = ('b','font','img','a'); # 有効タグ。「'」でくくり「,」で区切る。<,>は不要。 $style = 'off'; # タグのstyle,class,id属性を有効にするとき on。 $jscript = 'off'; # タグのJAVAスクリプト属性(onClickとか)を有効にするとき on。 $max_length = 8192; # 最大入力バイト数。0だと無制限。 #------------------------------------------------------------------------------- # そのほか #------------------------------------------------------------------------------- $method = 'post'; # FORMのMETHOD属性を指定(通常はPOST) $form_html = './form.txt'; # 拡張フォーム設定ファイル $tz = 9; # 海外サーバなど時刻がずれる時のみ変更してください # 設定ここまで------------------------------------------------------------------ # ファイルチェック open(LOG,$logfile) || &error("$logfileが open できません。"); @lines = ; close(LOG); $log_lines = $#lines; @lines = (); open(IN,$template) || &error("$templateが open できません。"); close(IN); &readform; # 条件分岐 ® if $form{'action'} eq 'regist'; #書き込み &admin if $form{'action'} eq 'admin'; #管理者モード &log; sub reg{ # パスワードチェック $bad_pass = "パスワードが違います。"; &error($bad_pass) if $form{'password'} ne $password; &code_conv; # 呼び出し元エラー # $reffer = $ENV{'HTTP_REFERER'}; # $reffer =~ s/\%7E/\~/g; # &error('不正なアクセスです。') if ($URL ne '') and ($reffer !~ /$URL/); $form{'Write_Time'} = time; #日時取得 $form{ip} = $ENV{REMOTE_ADDR}; #IPアドレス &error('内容が未記入です。') if $form{'note'} eq ''; #内容なしエラー $form{'note'} = &change($form{'note'}); #保存に不要な値を削除 delete $form{'action'}; delete $form{'password'}; # ログに書き込む open(LOG, "+< $logfile"); # 読み書きモードで開く eval("flock(LOG, 2)"); # ファイルをロックする @data = ; # 二重書きこみチェック if($w_reg eq 'on'){ %log = split(/<>/,$data[0]); chomp(%log); if(($log{'ip'} eq $form{'ip'})and($log{'note'} eq $form{'note'})){ &error('同じ内容の投稿が連続しています。
二重書きこみは禁止されています。') ; } } $value = join("<>",%form); unshift (@data, "$value\n"); @data = splice(@data,0,$max); $log_lines = $#data; # 行数読みなおし truncate(LOG, 0); # ファイルの古い内容をクリア seek(LOG, 0, 0); # 書き込み位置を先頭に戻す print LOG @data; # 値を書き込む close(LOG); # ファイルを閉じる if($imode){&imode; }else{&log;} } # ログ表示 sub log{ $page{max} = $max; $page{script} = $script; $page{method} = $method; if(($form{start} =~ \D) or ($form{start} < 1)){ $page{start} = 1 ; }else{ $page{start} = $form{start}; } if(($form{d_max} =~ \D) or (!$form{d_max})){ $page{d_max} = $d_max ; $form{d_max} = $page{d_max}; }else{ $page{d_max} = $form{d_max}; } # NEXTのURL if ($page{'start'} > 1){ $page{'next'} = "$script"; if($page{'start'}-$d_max > 0){ $page{'next'} .= "?start=" . ($page{'start'}-$d_max); } } # PREVのURL if($page{'start'} + $d_max <= $log_lines +1){ $page{'prev'} = "$script?start="; $page{'prev'} .= $page{'start'}+$d_max; } print "Content-type: text/html\n"; print "Pragma: no-cache\n\n"; # テンプレート読みこみ $. = 0; # 行数初期化 open(IN,$template); $locate = \@header; while(){ if (//) { $locate = \@table; next; } if (//) { $locate = \@footer; next; } s/\$(form|page)\{(.+?)\}/${$1}{$2}/g; # 変数置き換え s/<(a|A) (href|HREF)="".*?>(.*?)<\/(a|A)>/$3/g; # 空Aタグ削除 push(@$locate,$_); } close(IN); print @header; # ログの値をからまでに代入 $. = 0; # 行数初期化 open(LOG,$logfile); while(){ next if($. < $page{'start'}); %log = split(/<>/,$_); chomp(%log); $log{'date'} = &date($log{'Write_Time'}); $table = join('',@table); $table =~ s/\$log\{(.+?)\}/$log{$1}/g; $table =~ s/<(a|A) (href|HREF)="(|mailto:)".*?>(.*?)<\/(a|A)>/$4/g; print $table; last unless(-- $form{d_max}); } close(LOG); print @footer; exit; } # 管理者モード sub admin{ #携帯書き込みフォーム if($imode){&imode_form;} # パスワードチェック $bad_pass = <
END &no_pass if(!$form{'password'}); &error($bad_pass) if $form{'password'} ne $password; if($form{mode}){ &error('ログが選択されていません。') if(!$form{'Write_Time'}); open(LOG, "+< $logfile"); # 読み書きモードで開く eval("flock(LOG, 2)"); # ファイルをロックする @data = ; my $check = ''; foreach(@data) { %log = split(/<>/,$_); chomp(%log); if ($log{'Write_Time'} eq $form{'Write_Time'}){ $check = 'ok'; if($form{'mode'} eq 'del'){ }else{ &error('内容が未記入です。') if $form{'note'} eq ''; #内容なしエラー $form{'note'} = &change($form{'note'}); delete $form{'action'}; delete $form{'password'}; delete $form{mode}; $value = join('<>',%form) . "\n"; push(@new,$value); } }else{push(@new,$_);} } &error('該当するログが見つかりません。') if $check ne 'ok'; $log_lines = $#new; # 行数読みなおし truncate(LOG, 0); # ファイルの古い内容をクリア seek(LOG, 0, 0); # 書き込み位置を先頭に戻す print LOG @new; # 値を書き込む close(LOG); # ファイルを閉じる #ファイルロックの方法は「とほほのWWW入門」の「ファイルのロックに関する基礎知識」 #(http://wakusei.cplaza.ne.jp/twn/wwwcgi8.htm)を参考にさせていただいてます。 #非UNIX系サーバでのロック方法はイロイロ模索中… } if(($form{start} =~ \D) or (!$form{start})){ $page{start} = 1 ; }else{ $page{start} = $form{start}; } if(($form{d_max} =~ \D) or (!$form{d_max})){ $page{d_max} = $d_max ; $form{d_max} = $page{d_max}; }else{ $page{d_max} = $form{d_max}; } $log{'date'} = &date(time); $title = 'GanganSearch 更新履歴'; $body = '

管理者専用モード。記事の新規書きこみ・修正・削除が実行できます。

' . "\n"; $body .= qq|
\n|; $body .= qq|\n|; $body .= qq|\n|; if(-r $form_html){ open(IN,$form_html); while(){ $body .= $_; } close IN; } $body .= qq|

|; $body .= '


'; $. = 0; # 行数初期化 open(LOG,$logfile); while(){ next if($. < $page{'start'}); %log = split(/<>/,$_); chomp(%log); $log{'date'} = &date($log{'Write_Time'}); $body .= < HTML # 逆オートリンク。試行錯誤中 $log{note} =~ s/\1<\/A>/$1/gi; $log{note} =~ s/\1\@\2<\/A>/$1\@$2/gi; $log{note} =~ s/
/\n/g; $log{note} =~ s//>/g; $body .= "\n"; $body .= "\n"; $body .= "\n"; $body .= "\n"; delete $log{note}; delete $log{date}; delete $log{Write_Time}; delete $log{ip}; foreach (keys %log){ $body .= "\n"; $body .= "\n"; } $body .= "
日時$log{date}
内容
$_

\n"; $body .= <


END last unless(-- $form{d_max}); } close(LOG); $body .= <
最新件目から 件分

初期画面に戻る

HTML &print_html($title,$body); } # 携帯からの書き込みフォーム sub imode_form{ if($jsky){$method = 'get';} print "Content-type: text/html\n"; print "Pragma: no-cache\n\n"; print < unico

pass :
END exit; } # 携帯からの書き込み完了画面 sub imode{ $form{note} = substr($form{note},0,50); print "Content-type: text/html\n"; print "Pragma: no-cache\n\n"; print < 書き込み完了 以下の記事を書き込みました。
$form{date}
$form{note} .... END exit; } # HTML出力 sub print_html{ ($title, $body) = @_; print "Content-type: text/html\n"; print "Pragma: no-cache\n\n"; print < $title

$title

$body

unico by az*

END exit; } # 書き込み内容の変換 sub change{ my ( $msg, $new, @tmp, $tmp, @options, $options, @text, $text,); $msg = $_[0]; #改行処理 $msg =~ s/\r\n/\n/g; $msg =~ s/\r/\n/g; $/ = ''; chomp $msg; $/ = "\n"; # 行末の空行を除去 $msg =~ s/\n/
/g; # タグ処理 ($new,@tmp) = split(/</,$msg); $new = &autolink($new); foreach $tmp (@tmp){ # >がなければタグじゃないとみなしてテキスト処理 if($tmp !~ />/){$tmp = &autolink('<' . $tmp); next;} ($options,@text) = split(/>/,$tmp); $text = &autolink(join('>',@text)); # >より右はテキスト処理 ($tag,@options) = split(/\s|
/i,$options); # タグとオプションを分割 # 許可タグ if(grep(/^$tag$/i,@tag)){ # JavaScript, stylesheet 関連オプションを削除 foreach(@options){ if($style ne 'on'){ if($_ =~ /^(style|class)/i){$_ = '';} if($jscript ne 'on'){ if($_ =~ /^id/i){$_ = '';}} } if($jscript ne 'on'){ if($_ =~ /^on/i){$_ = '';}} } $tmp = '<' . join(' ',$tag,@options) . '>' . $text; # 閉じタグ }elsif($tag =~ m!^/!){ $tag =~ s!^/!!; if(grep(/^$tag$/i,@tag)){ # 許可 $tmp = '' . $text; }else{ $tmp = '</' . &autolink($tag) . '>' . $text;} # 禁止閉じタグ # 禁止タグ }else{ $tmp = '<' . &autolink(join(' ',$tag,@options)) . '>' . $text;} } $new .= join('',@tmp); # タグ処理ここまで return $new; } # テキスト部の処理(オートリンク) sub autolink{ if($link ne 'on'){return $_[0];} # URLのマッチングは「Perlメモ」http://www.din.or.jp/~ohzaki/perl.htm を参考にさせていただきました。 # …というかそのまんまです。ありがとうございました!! $_[0] =~ s/(s?https?:\/\/[-_.!~*'()a-zA-Z0-9;\/?:\@&=+\$,%#]+)/&url($1)/gie; $_[0] =~ s/([\w\.\-]+)\@([\w\.\-]+)/$1\@$2<\/A>/ig; return $_[0]; } sub url{ $short = substr($_[0],0,$link_max); return qq|$short...<\/A>|; } # 日付表示 sub date{ $log_date = $_[0]; ($sec, $min, $hour, $mday, $mon, $year, $w) = gmtime($log_date + $tz*60*60); $log_date = $date; $log_date =~ s/%Y/$year + 1900/ge; $log_date =~ s/%y/substr($year + 1900,-2)/eg; $log_date =~ s/%M/$month[$mon]/g; $log_date =~ s/%m/sprintf("%02d",$mon + 1)/eg; $log_date =~ s/%n/$mon + 1/g; $log_date =~ s/%d/sprintf("%02d",$mday)/eg; $log_date =~ s/%j/$mday/g; $log_date =~ s/%D/$week[$w]/g; if($hour >= 12){ $hhour = $hour-12; $m = 1;}else{$hhour = $hour;} $log_date =~ s/%h/sprintf("%02d",$hhour)/eg; $log_date =~ s/%H/sprintf("%02d",$hour)/eg; $log_date =~ s/%g/$hhour/g; $log_date =~ s/%G/$hour/g; $log_date =~ s/%a/$m[$m]/g; $log_date =~ s/%I/sprintf("%02d",$min)/eg; $log_date =~ s/%i/$min/g; $log_date =~ s/%S/sprintf("%02d",$sec)/eg; $log_date =~ s/%s/$sec/g; return $log_date; } sub readform{ if ($ENV{'REQUEST_METHOD'} eq "POST") { if(($ENV{'CONTENT_LENGTH'} > $max_length)and($max_length)){ &error("入力文字数が多すぎます。");} read(STDIN, $formdata, $ENV{'CONTENT_LENGTH'}); } else { if(($ENV{'QUERY_STRING'} > $max_length)and($max_length)){ &error("入力文字数が多すぎます。");} $formdata = $ENV{'QUERY_STRING'}; } @pears = split(/&|;/,$formdata); foreach (@pears) { ($name,$value) = split(/=/,$_); $value =~ tr/+/ /; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C",hex($1))/eg; $name =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C",hex($1))/eg; $value =~ s//>/g; $form{$name} = $value; } if($ENV{HTTP_USER_AGENT} =~ /^DoCoMo/){ $imode = 1; }elsif($ENV{HTTP_USER_AGENT} =~ /^J-PHONE/){ $imode = 1; $jsky=1; } } sub code_conv{ require $jcode; while (($key, $value) = each(%form)) { #絵文字除去コードは「CGIぽん」サマ(http://specters.net/cgipon/)を参考にさせていただきました。 if($imode){ if($jsky){$value =~ s/\x1B\$(?:..)+\x0F//g; # j-sky絵文字除去 }else{ my $sjis = '[\x80-\x9F\xE0-\xF7\xFA-\xFC][\x40-\xFF]|[\x00-\x7F]'; my $emoji_i = '[\xF8\xF9][\x40-\x7E\x80-\xAF]'; $value =~ s/\G((?:$sjis)*?)(?:$emoji_i)/$1/go; # i-mode絵文字除去 } &jcode'h2z_sjis(*value); }else{ &jcode'convert(*value,'sjis');} $form{$key} = $value; } } sub no_pass{ $title = 'unico [management]'; $body = <パスワードを入力してください。

END &print_html($title,$body); } # エラー処理 sub error { $title= 'Error!'; $body = <$_[0]

END &print_html($title,$body); }