#┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #┃■C-BOARD Moyuku コマンド #┃ last modified 2011/02/11 #┠────────────────────────────────────── #┃投稿関係の関数が含まれています。 #┃ #┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ package POST; use File::Copy qw(move); require './app/lib/emoji.pl'; require './app/lib/etc.pl'; #┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #┃ 投稿画面表示 #┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sub input { do "$::FLAG{'template'}/psn.skin.pl"; #── 返信の場合 my($subject, $reference); my $body; if ($::FORM{'follow'}) { require './app/lib/file/msg.pl'; require './app/lib/htm.pl'; require './app/cmd/message.pl'; my $o_message = new FILE::MESSAGE($CNF::place{'data'}{'path'}); (my $r_MSG = $o_message->one($::FORM{'follow'})) or &::error(\'返信元の記事を読み込めませんでした。'); local *MSG = $r_MSG; $o_message->close(); #── レス数制限 if ($CNF::post{'resnumres'}{'mode'}) { if ($CNF::post{'resnumres'}{'max'} == 0) { # レス完全禁止 &::error(\'管理人により返信が禁止されています。'); } else { # レス数禁止(現在のレス数をチェックする−ファイルアクセスが増える) require './app/lib/file/tre.pl'; my $o_tree = new FILE::TREE($CNF::place{'data'}{'path'}); my $r_topic; $r_topic = $o_tree->one($MSG{'tree'}); my $r_MSG_tpc = ${$r_topic}[0]; ${$r_MSG_tpc}{'reply'} = $#{$r_topic}; local *MSG_tpc = $r_MSG_tpc; $o_tree->close; if ($MSG_tpc{'reply'} >= $CNF::post{'resnumres'}{'max'}) { &::error(\"返信記事数が管理人が設定した制限数($CNF::post{'resnumres'}{'max'})を越えています。"); } } } if ($CNF::post{'quot'}{'number'}{'mode'}) { if ($MSG{'subject'} =~ /^Re\((\d+)\):(.*)$/) { $subject = 'Re(' . ($1 + 1) . "):$2"; } elsif ($MSG{'subject'} =~ /^Re:(.*)$/) { $subject = "Re(1):$1"; } else { $subject = "Re(1):$MSG{'subject'}";} } else { $subject = ($MSG{'subject'} =~ /^Re(?:\(\d+\))?:(.*)$/) ? "Re:$1" : "Re:$MSG{'subject'}"; } #Moyuku凍結 #$::FLAG{'mobile'}{'hdml'} && ($subject =~ s/\$/&dol;/g); #── 引用の場合 if (!$::FORM{'no_quot'}) { $body = $MSG{'body'}; chomp($body); $CNF::post{'emoji'}{'mode'} && &EMOJI::cancel(\$body); &HTML::escape(&ETC::option_unlink(&HTML::auto_unlink(\$body))); $body =~ s/^/$CNF::post{'quot'}{'icon'}/gmo; $CNF::post{'quot'}{'name'}{'mode'} && ($body = join($MSG{'name'}, @{$CNF::post{'quot'}{'name'}{'icon'}}) . "\n" . $body); } #── 参照文 $MSG{'typewriter'} && ($MSG{'body'} = "$MSG{'body'}"); my $reference = $MSG{'body'}; $r_reference = &DESIGN::reference(&MESSAGE::quot_color(\$reference)); } #── 各種入力欄の設定 my $upload_input; if ( $CNF::upload{'mode'} ) { map($upload_input .= ${&DESIGN::upload_input}, (0 .. ($CNF::upload{'enable'}{'number'} - 1))); } $CNF::mail{'inform'}{'mode'} && (my $r_inform_mail_input = &DESIGN::inform_mail_input); $CNF::mail{'owner'}{'mode'} && (my $r_owner_mail_input = &DESIGN::owner_mail_input); $CNF::view{'genre'}{'mode'} && (my $r_genre_input = &DESIGN::genre_input); $CNF::view{'tree'}{'sort'}{'mode'} && $CNF::post{'sage'}{'mode'} && (my $r_sage_input = &DESIGN::sage_input); $CNF::view{'body_color'}{'mode'} && (my $r_body_color_input = &DESIGN::body_color_input); ##スパム対策系 #タイムキー my $r_timekey = ''; if( $::FORM{'cmd'} ne "mdt" ){ $r_timekey = &make_timekey($CNF::antispam{'timekey'}{'idseed'}); } #画像認証 my $r_numcrypted = ''; if( $CNF::antispam{'imagekey'}{'use'}==1 && $::FORM{'cmd'} ne "mdt" ){ $r_numcrypted = &make_imagekey_number( $CNF::antispam{'timekey'}{'idseed'} ); } #── 表示 &BASE::head('psn'); &DESIGN::post($r_genre_input, \$subject, \$body, \$upload_input, $r_sage_input, $r_inform_mail_input, $r_owner_mail_input, $r_reference, $r_body_color_input, $r_timekey, $r_numcrypted ); &BASE::foot('psn'); } #┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #┃ 画像認証キー作成 #┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sub make_imagekey_number { my ( $idSeed ) = @_; $num = int( rand(9998) ) + 1; require './app/extlib/RC4.pm'; my $rc4 = Crypt::RC4->new( $idSeed ); my $crypted = $rc4->RC4( $num ); $crypted =~ s/(.)/unpack('H2', $1)/eg; return $crypted; } #┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #┃ 画像認証キーチェック #┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sub check_imagekey { my ( $imagekey, $num_crypted, $idSeed ) = @_; my @error; if ( length($imagekey) <= 0 ) { push(@error, "画像認証キーが入力されていません。"); return(\@error); } require './app/extlib/RC4.pm'; my $rc4 = Crypt::RC4->new( $idSeed ); $num_crypted =~ s/([0-9A-Fa-f]{2})/pack('H2', $1)/eg; my $number = $rc4->RC4( $num_crypted ); if ( $imagekey != $number ) { push(@error, "画像認証キーが合致しません。"); } #push(@error, "test " . $number . ' -> ' . $imagekey); return(\@error); } #┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #┃ 投稿処理 #┃ スパム投稿などの関係で、かなり頻繁に呼ばれるはず。 #┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sub write { # require './app/lib/str.pl'; #── 投稿可能かどうかチェック $CNF::post{'stop'}{'mode'} && &::error(\$CNF::post{'stop'}{'caption'}); #── ロック開始 &::lock('msg') or &::error(\'混雑していて書き込めませんでした。'); #── 前準備 my $r_error = ¶meter; $r_error && &error($r_error); #── 各種チェック my $o_identify; ($r_error, $o_identify) = ✓ $r_error && &error($r_error, $o_identify); #── プレビューなら表示して終了 if ($::FORM{'preview'}) { #添付ファイル削除 if ($::FLAG{'file'}) { foreach (@{$::FLAG{'file'}}) { unlink("$::SYS{'path_tmp'}/${$_}{'name'}"); } } #ロック解除 &::unlock('msg'); #表示 &preview; return; } #絵文字の処理 if ( $::FLAG{'mobile'}{'mode'} || $::FLAG{'pda'} ) { if ( $CNF::post{'emoji'}{'mode'} == 0 ) { &EMOJI::to_string(\$::FORM{'body'}) } elsif ( $CNF::post{'emoji'}{'mode'} == 1 ) { &EMOJI::to_code(\$::FORM{'body'}) } else { } #$CNF::post{'emoji'}{'mode'} # ? &EMOJI::to_code(\$::FORM{'body'}) # : &EMOJI::to_string(\$::FORM{'body'}); } #── 添付ファイルの処理 delete $::FORM{'file'}; if ($::FLAG{'file'}) { $::FORM{'file'} = $::FLAG{'file'}; foreach (@{$::FORM{'file'}}) { #ファイルを移動 move( "$::SYS{'path_tmp'}/" . ${$_}{'name'}, "$CNF::place{'file'}{'path'}/" . ${$_}{'name'} ); (${$_}{'name'} =~ /\.(?:bmp|gif|jpe?g|png)$/i) or next; my $r_screen = &COMMON::get_image_size("$CNF::place{'file'}{'path'}/" . ${$_}{'name'}); if (!$r_screen) { push(@error, '画像のサイズの取得に失敗しました。'); last; } ${$_}{'screen'} = join('*', @{$r_screen}); } } #── 書き込み my @total = &write_total; my @tree = &write_tree; my @message = &write_message; my @file = $::FORM{'file'} ? &write_file : (0, 1); $SIG{'INT'} = $SIG{'HUP'} = $SIG{'QUIT'} = $SIG{'TERM'} = 'IGNORE'; if ($total[1] && $tree[1] && $message[1] && $file[1]) { $total[0]->complete(); $tree[0]->complete(); $message[0]->complete(); $file[0] && $file[0]->complete(); } else { $total[0]->incomplete(); $tree[0]->incomplete(); $message[0]->incomplete(); $file[0] && $file[0]->incomplete(); &::error(\'記事の書き込みに失敗しました。'); } $o_identify && $o_identify->complete; # $CNF::rank{'frequency'}{'mode'} && &write_frequency; ##── キーワード記録 #$CNF::post{'keyword'}{'mode'} && &keyword; #── メール送信 if ($CNF::mail{'mode'} != 2) { my %FRM2 = %::FORM; #参照で破壊されるので…… $FRM2{'operator'} = -1; if ( $CNF::mail{'master'}{'mode'} ) { require './app/lib/mailer.pl'; &MAILER::master_mail(\%FRM2); } %FRM2 = %::FORM; if ( $CNF::mail{'inform'}{'mode'} && $FRM2{'follow'} ) { require './app/lib/mailer.pl'; &MAILER::response_mail(\%FRM2); } ##凍結 #if ( $CNF::mail{'owner'}{'mode'} ) { # require './app/lib/mailer.pl'; # &MAILER::owner_mail #} } #── 記事数がオーバーしたら古いツリーを過去ログ化 or 削除 my $ret = 0; if ($total[1] > $CNF::post{'total'}) { require './app/cmd/delete.pl'; $ret = &DELETE::last_tree(3); if ( $ret == 0 ) { &::error(\'超過記事の処理に失敗しました。'); } } #── 添付ファイルの容量をオーバーしたら少し多めに古い添付ファイル削除 if ($file[0] && ($file[1] > $CNF::upload{'size'}{'total'})) { require './app/cmd/delete.pl'; &DELETE::last_file(($file[1] - $CNF::upload{'size'}{'total'}) * 2); } #── ロック解除 &::unlock('msg'); #── クッキー my @value = qw(email key mail_mode name inform_mail owner_mail web sage); $CNF::view{'genre'}{'cookie'}{'mode'} && push(@value, 'genre'); $CNF::view{'body_color'}{'cookie'}{'mode'} && push(@value, 'body_color'); my %value; map($value{$_} = $::FORM{$_}, (@value, grep(/^opt_/, keys %::FORM))); #── ジャンプ my $plfm = ""; &BASE::location("$CNF::place{'this'}{'url'}?cmd=one;no=$::FORM{'no'};" . "id=$::FORM{'id'}", {name => "$CNF::cookie{'name'}", value => \%value, expire => $CNF::cookie{'expire'}}); } #┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #┃ パラメーターをセット #┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sub parameter { require './app/lib/file/msg.pl'; require './app/lib/htm.pl'; my @error; #── 記事番号を設定 my $o_message = new FILE::MESSAGE($CNF::place{'data'}{'path'}); if (my $r_MSG = $o_message->read(0, 1)) { $o_message->close; $::FORM{'no'} = ${$r_MSG}{'no'} + 1; } elsif ($o_message->init()) { push(@error, '記事番号の取得に失敗しました。'); } else { $::FORM{'no'} = 1;} #── ツリー番号を設定 if ($::FORM{'follow'}) { $o_message = new FILE::MESSAGE($CNF::place{'data'}{'path'}); (my $r_MSG = $o_message->one($::FORM{'follow'})) or push(@error, '返信元の記事を見つけられませんでした。'); $::FORM{'tree'} = ${$r_MSG}{'tree'}; $o_message->close; } else { $::FORM{'tree'} = $::FORM{'no'};} #── ホスト情報を設定 $::FORM{'host'} = &CGI::get_host(0); $::FORM{'ext_host'} = &CGI::get_host(1); $::FORM{'addr'} = $ENV{'REMOTE_ADDR'}; #── 日付を設定 $::FORM{'date'} = &COMMON::date($CNF::dformat{'post'}); #── IDを設定 $::FORM{'user_id'} = $::COOKIE{'user_id'}; #── 識別番号(そのままでは長いので削る) $::FORM{'ident'} = substr(&COMMON::sha1(\"$::FORM{'name'}\t$::FORM{'key'}"), 0, 10); #── クライアント情報を設定 $::FORM{'agent'} = $ENV{'HTTP_USER_AGENT'} || 'unknown'; &COMMON::jsubstr(&HTML::escape(\$::FORM{'agent'}), 120); #── 時間を設定 $::FORM{'time'} = $::FLAG{'time'}; #── 携帯かどうか設定 $::FLAG{'mobile'}{'mode'} && ($::FORM{'mobile'} = 1); # #── 添付ファイルの情報を設定 # delete $::FORM{'file'}; # if ($::FLAG{'file'}) { # (!$CNF::upload{'mode'} || !$::FLAG{'master'} # && $CNF::upload{'mode'} != 2) # && &::error(\'ファイルのアップロードは禁止されています。'); # # $::FORM{'file'} = $::FLAG{'file'}; # foreach (@{$::FORM{'file'}}) { # (${$_}{'name'} =~ /\.(?:bmp|gif|jpe?g|png)$/i) or next; # my $r_screen # = &COMMON::get_image_size("$CNF::place{'file'}{'path'}/" . ${$_}{'name'}); # if (!$r_screen) { # push(@error, '画像のサイズの取得に失敗しました。'); last; # } # ${$_}{'screen'} = join('*', @{$r_screen}); # } # } return(@error ? \@error : 0); } #┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #┃ いろいろチェック #┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sub check { my @error; #── ブービートラップ if ( $::FORM{'comment'} && length($::FORM{'comment'}) > 0 ) { return(['不正な投稿と判定されました。']); } #── アクセス権チェック if ($CNF::permission{'pst'}{'mode'}) { require './app/lib/prm.pl'; &PERMISSION::check('pst'); } #── 投稿元をチェック $CNF::post{'referer_check'}{'mode'} && !$::FLAG{'mobile'}{'mode'} && !$::FLAG{'incm'} && ($ENV{'HTTP_REFERER'} !~ /^\Q$CNF::place{'this'}{'url'}\E/) && push(@error, '投稿元が不正です。'); #── プロキシ経由かチェック ($CNF::post{'no_proxy'}{'mode'} && !&CGI::check_proxy(&CGI::get_host(1))) && push(@error, 'プロキシサーバーを経由しての書き込みは' . '禁止されています。'); #── ここまででエラーがある場合は出力 @error && return(\@error); #── 投稿時間チェック(管理者以外) if ( $::FLAG{'master'} != 1 ) { @error = @{ &check_timekey( $::FORM{'timekey'}, $CNF::antispam{'timekey'}{'idseed'}, $CNF::antispam{'timekey'}{'secmax'}, $CNF::antispam{'timekey'}{'secmin'}) }; @error && return(\@error); #前陣速攻 } #── 名前をチェック my $name = $::FORM{'name'}; my $master = $CNF::master{'name'}; (!$::FLAG{'master'} && (&ETC::name_matching($name,$master,$CNF::master{'mode'}))) && return(['管理人と同じ名前は使えません。']); #── 新規スレッド立てチェック if (!$::FORM{'follow'}) { (!$::FLAG{'master'} && $CNF::permission{'pst'}{'master'}{'modenew'}) && return(['管理人以外は新規スレッドを投稿できません']); } #── ファイル添付チェック if ( $CNF::upload{'mode'}==0 || ( !$::FLAG{'master'} && $CNF::upload{'mode'} != 2) ) { if ( $::FLAG{'file'} || $::FORM{'file'} ) { return (\'ファイルのアップロードは禁止されています。'); } } if ( $::FLAG{'file'} || $::FORM{'file'} ) { foreach (@{$::FLAG{'file'}}) { ${$_}{'name'} =~ /(.*)\.(.*)$/; grep( /$2/i, @{$CNF::upload{'enable'}{'ext'}} ) or return( ['このタイプのファイルはアップロードが禁止されています。(' . $2 . ')'] ) ; } } #── ここまででエラーがある場合は出力 @error && return(\@error); #── 投稿データチェック @error = @{&check_parameter}; $::FLAG{'check'} = 1; #── 二重投稿チェック my $o_identify; if (!$::FLAG{'master'} && !$::FORM{'preview'} && ($::FORM{'cmd'} ne 'mdt')) { my $result; ($o_identify, $result) = &identify; ($::FLAG{'debug'} == 2) && ($result = 2); if ($result == 0) { push(@error, '同一内容の再投稿は禁止されています。'); } elsif ($result == 1) { push(@error, "管理人($CNF::master{'name'})以外は" . "$CNF::post{'interval'}秒以内の再投稿は出来ません。"); } } return((@error ? \@error : 0), $o_identify); } #┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #┃ 投稿データチェック #┃ もろもろの事情により(?)SJISであることをそれほど意識せずに #┃ 処理しています #┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sub check_parameter { require './app/lib/htm.pl'; my @error; my %item = qw( name 名前 email メールアドレス subject 題名 body 本文 key パスワード web ホームページアドレス ); my $os; if ($CNF::post{'no_dependence'}{'mode'}) { if ($ENV{'HTTP_USER_AGENT'} =~ /Win/) { $os = 0;} elsif ($ENV{'HTTP_USER_AGENT'} =~ /Mac(?:intosh|_PowerPC)/) { $os = 1; } } # スパム対策 if ( $::FLAG{'master'} != 1 ) { # 画像認証番号 if ( $CNF::antispam{'imagekey'}{'use'} == 1 ) { @error = @{ &check_imagekey( $::FORM{'imagekey'}, $::FORM{'num_crypted'}, $CNF::antispam{'timekey'}{'idseed'} ) }; @error && return(\@error); } # 投稿用フリーキーワード if ( ( $::FLAG{'mobile'}{'mode'} != 1 && $CNF::antispam{'postword'}{'use'} == 1 ) || $CNF::antispam{'postword'}{'use'} == 2 ) { if ( $::FORM{'postword'} ne $CNF::antispam{'postword'}{'key'} ) { push(@error, "投稿キーワードが合致しません。"); } } } #── ここまででエラーがある場合は出力 @error && return(\@error); #スパム投稿対策フィルター require './app/lib/filter.pl'; my $err_msg = &FILTER::anti_spampost ( $CNF::antispam{'filter'}{'level'},$::FORM{'name'},$::FORM{'subject'},$::FORM{'body'}, $::FORM{'email'},$::FORM{'web'},$ENV{'REMOTE_ADDR'} ); if ( length($err_msg) > 0 ) { push(@error, $err_msg); if ( $::FLAG{'debug'} == 1 ) { #トレース $::FLAG{'debug_out'} .= $err_msg . "\n"; } return(\@error); } my $item; #先行チェック foreach $item (keys %item) { #── 禁止語句をチェック foreach (@{$CNF::post{'disable'}{'word'}{'list'}}) { length($_) or next; if (index($::FORM{$item}, $_) != -1) { # 速度重視(手抜き) push(@error, "$item{$item}に禁止語句が含まれています。"); last; } } #── 長さをチェック if ($::FORM{$item} =~ /^(?: | |\n)*$/s) { $CNF::post{$item}{'indispensable'} && push(@error, "$item{$item}を記入してください。"); } (length($::FORM{$item}) > $CNF::post{$item}{'max'}) && push(@error, ("$item{$item}が長すぎます。$CNF::post{$item}{'max'}" . "文字以内にしてください。")); } #── 空白欄を補完 my %empty = ( 'name' => $CNF::post{'name'}{'complement'}, 'subject' => $CNF::post{'subject'}{'complement'}, 'body' => $CNF::post{'body'}{'complement'}, ); foreach (keys %item) { length($::FORM{$_}) or ($::FORM{$_} = $empty{$_}); } #── ここまででエラーがある場合は出力 @error && return(\@error); &STRING::undef_table; &EMOJI::undef_table; my $param; foreach $param (grep(/^opt_/, keys %::FORM)) { if (!grep($param eq $_, @{$CNF::post{'option'}{'param'}{'list'}})) { push(@error, "オプションパラメーター($param)は" . "登録されていません。"); next; } $::FORM{$_} =~ s/\n//g; (length($::FORM{$_}) > 100) && push(@error, 'オプションパラメーターが長すぎます。'); &HTML::escape(\$::FORM{$_}); } #── メールアドレスをチェック length($::FORM{'email'}) && ($::FORM{'email'} !~ /^[\w\.\-]+\@[\w\.\-]+\.[a-zA-Z]{2,6}$/) && push(@error, 'メールアドレスが不正です。'); #── ホームページアドレスをチェック length($::FORM{'web'}) && ($::FORM{'web'} !~ /^s?https?:\/\/[!-~]+\.[!-~]+$/ || ($CNF::post{'url'}{'check'}{'mode'} && !&HTML::check_url($::FORM{'web'}))) && push(@error, 'ホームページアドレスが不正です。'); #── パスワードをチェック ($::FORM{'key'} =~ /[<>&"]/) && &::error(\('パスワードに「<, >, &, "」は' . '使えません。')); #── ジャンルアイコン if (($::FLAG{'mobile'}{'mode'} != 1) && ($::FLAG{'pda'} != 1)) { exists $CNF::view{'genre'}{'list'}{$::FORM{'genre'}} or delete $::FORM{'genre'}; $CNF::view{'genre'}{'mode'} && $CNF::view{'genre'}{'require'}{'mode'} && !length($::FORM{'genre'}) && push(@error, "「$CNF::view{'genre'}{'menu'}」を選択してください。"); } #── 本文色選択(携帯/PDAの場合はチェックしない) if (($::FLAG{'mobile'}{'mode'} != 1) && ($::FLAG{'pda'} != 1)) { $CNF::view{'body_color'}{'mode'} && $CNF::view{'body_color'}{'require'}{'mode'} && !length($::FORM{'body_color'}) && push(@error, "「本文色」を選択してください。"); } #── 不正なパラメータを削除 ($CNF::mail{'inform'}{'mode'} && $::FORM{'email'}) or delete $::FORM{'inform_mail'}; ($CNF::mail{'owner'}{'mode'} && $::FORM{'email'}) or delete $::FORM{'owner_mail'}; $::FORM{'email'} or delete $::FORM{'mail_mode'}; #── ここまででエラーがある場合は出力 @error && return(\@error); #一応保険で置換 $::FORM{'email'} =~ s// /g; $::FORM{'web'} =~ s// /g; #投稿内容チェック foreach $item (keys %item) { #── 機種依存文字をチェック (defined $os) && &STRING::no_dependence(\$::FORM{$item}, $os); #── 内容を修正 if ($item eq 'body') { ($::FORM{$item} =~ /[!-~]{150}/) && push(@error, "半角文字列は適度に改行してください。"); $::FORM{$item} =~ s/^(?:(?: | )*\n)+//g; $::FORM{$item} =~ s/(?:(?: | )*\n)+$//; $::FORM{$item} =~ s/(?:(?: | )*\n){4,}/$1\n\n\n/g; #!Moyuku! ここで絵文字の対応をやる必要はない。 ##── 一連の処理前に携帯からの絵文字を#????#コードに変換 ##── メールのオートリンク対策でsjis←→eusの変換が生じたため #if ( $::FLAG{'mobile'}{'mode'} ) { # $CNF::post{'emoji'}{'mode'} # ? &EMOJI::to_code(\$::FORM{$item}) # : &EMOJI::to_string(\$::FORM{$item}); #} if ($::FLAG{'master'} && $CNF::tag{'mode'} || !$::FLAG{'master'} && $CNF::tag{'mode'} == 2) { &HTML::check(\$::FORM{$item}, $CNF::tag{'enable'}, $CNF::tag{'java'}{'mode'}, $CNF::tag{'style'}{'mode'}, $CNF::post{'url'}{'target'}, $CNF::post{'url'}{'check'}{'mode'}); } else { ##これではログに書き込んでしまう。 #&HTML::auto_link(&HTML::escape(\$::FORM{$item}), $CNF::post{'url'}{'target'}, $CNF::post{'url'}{'check'}{'mode'}); &HTML::escape(\$::FORM{$item}); } #ログには書き込まない #if ($sharp) { # &ETC::option_link(\$::FORM{$item}, $::FORM{'no'}); # $CNF::post{'emoji'}{'mode'} # ? &EMOJI::image(\$::FORM{$item}, # $CNF::place{'this'}{'path'} # . "?cmd=mji;id=$::FORM{'id'};name=") # : &EMOJI::string(\$::FORM{$item}); #} } else { #本文以外 ( $::FLAG{'mobile'}{'mode'} ) && &EMOJI::to_string(\$::FORM{$item}); $::FORM{$item} =~ s/\n//g; $::FORM{$item} =~ s/^(?: | )+//; $::FORM{$item} =~ s/(?: | )+$/$1/; &HTML::escape(\$::FORM{$item}); } } return(\@error); } #┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #┃ 暗号化タイムキー作成 #┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sub make_timekey { my $idSeed = shift; require './app/extlib/RC4.pm'; my $rc4 = Crypt::RC4->new( $idSeed ); my $timekey = $rc4->RC4( time() ); $timekey =~ s/(.)/unpack('H2', $1)/eg; return $timekey; } #┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #┃ 投稿タイムキーチェック #┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sub check_timekey { my $postTimekey = shift; my $idSeed = shift; my $secMax = shift; my $secMin = shift; my @error; if ( length($postTimekey) <= 0 ) { push(@error, "不正な投稿と判定されました。"); return(\@error); } require './app/extlib/RC4.pm'; my $rc4 = Crypt::RC4->new( $idSeed ); $postTimekey =~ s/([0-9A-Fa-f]{2})/pack('H2', $1)/eg; $start_time = $rc4->RC4( $postTimekey ); if ( (time() - $start_time) <= 2 ) { eval{ sleep(10) }; #ペナルティ push(@error, "不正な投稿です。"); } elsif ( (time() - $start_time) < $secMin ) { push(@error, "投稿にかかった時間から、自動投稿スパムと判定されました。"); } elsif ( (time() - $start_time) > $secMax ) { push(@error, "投稿までの制限時間を超過してしまいました。別途の再投稿をお願いします。"); } #push(@error, "test " . $postTimekey . ' -> ' . $start_time . ' now='. time() ); return(\@error); } #┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #┃ エラー #┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sub error { my $r_error = shift; my $o_identify = shift; do "$::FLAG{'template'}/psn.skin.pl"; require './app/lib/htm.pl'; #── 書き換え中止 $o_identify && $o_identify->incomplete; #一時ファイル削除 if ($::FLAG{'file'}) { foreach (@{$::FLAG{'file'}}) { unlink("$::SYS{'path_tmp'}/${$_}{'name'}"); } undef $::FLAG{'file'}; } #── ロック解除 &::unlock('msg'); #── 携帯の場合 $::FLAG{'mobile'}{'mode'} && &::error(\join("
\n", @{$r_error})); #── パラメーターをセット $::FORM{'cmd'} = 'psn'; #if ($::FLAG{'check'}) { # $CNF::post{'emoji'}{'mode'} && &EMOJI::cancel(\$::FORM{'body'}); # &ETC::option_unlink(&HTML::auto_unlink(\$::FORM{'body'})); #} map(&HTML::escape(\$::FORM{$_}), keys %::FORM); foreach (qw(email key mail_mode name inform_mail owner_mail web genre sage body_color postword)) { $::COOKIE{$_} = $::FORM{$_}; } delete $::FLAG{'check'}; #── 返信の場合 if ($::FORM{'follow'}) { require './app/lib/file/msg.pl'; require './app/cmd/message.pl'; my $o_message = new FILE::MESSAGE($CNF::place{'data'}{'path'}); (my $r_MSG = $o_message->one($::FORM{'follow'})) or &::error(\join("
\n ", (@{$r_error}, '返信元の記事を読み込めませんでした。'))); local *MSG = $r_MSG; #── 参照文 &MESSAGE::quot_color(\$MSG{'body'}); $MSG{'body'} =~ s/^/  /gm; $r_reference = &DESIGN::reference(\$MSG{'body'}); } #── 各種入力欄の設定 my $upload_input; $CNF::upload{'mode'} && map($upload_input .= ${&DESIGN::upload_input}, (0 .. ($CNF::upload{'enable'}{'number'} - 1))); $CNF::mail{'inform'}{'mode'} && (my $r_inform_mail_input = &DESIGN::inform_mail_input); $CNF::mail{'owner'}{'mode'} && (my $r_owner_mail_input = &DESIGN::owner_mail_input); $CNF::view{'genre'}{'mode'} && (my $r_genre_input = &DESIGN::genre_input); $CNF::view{'tree'}{'sort'}{'mode'} && $CNF::post{'sage'}{'mode'} && (my $r_sage_input = &DESIGN::sage_input); $CNF::view{'body_color'}{'mode'} && (my $r_body_color_input = &DESIGN::body_color_input); ##スパム対策系 #タイムキー my $r_timekey = $::FORM{'timekey'}; #画像認証 my $r_numcrypted = ''; if( $CNF::antispam{'imagekey'}{'use'}==1 && $::FORM{'cmd'} ne "mdt" ){ $r_numcrypted = &make_imagekey_number( $CNF::antispam{'timekey'}{'idseed'} ); } #画面表示 &BASE::head('pst'); map(&::error(\$_), @{$r_error}); print ${&DESIGN::line}; &DESIGN::post($r_genre_input, \$::FORM{'subject'}, \$::FORM{'body'}, \$upload_input, $r_sage_input, $r_inform_mail_input, $r_owner_mail_input, $r_reference, $r_body_color_input, $r_timekey, $r_numcrypted ); &BASE::foot('pst'); exit; } #┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #┃ プレビュー #┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sub preview { require './app/cmd/message.pl'; require './app/lib/htm.pl'; do "$::FLAG{'template'}/psn.skin.pl"; do "$::FLAG{'template'}/msg.skin.pl"; #── パラメーターをセット $::FORM{'cmd'} = 'psn'; foreach (qw(email key mail_mode name inform_mail owner_mail web genre sage body_color postword imagekey)) { $::COOKIE{$_} = $::FORM{$_}; } my $body = $::FORM{'body'}; $::FORM{'file'} && map($_{'size'} = &COMMON::size($_{'size'}), @{$::FORM{'file'}}); #── プレビュー表示 &BASE::head('pst'); $::FORM{'cmd'}="one"; &MESSAGE::all(\%::FORM); #── パラメーターを修正 $::FORM{'body'} = $body; $CNF::post{'emoji'}{'mode'} && &EMOJI::cancel(\$::FORM{'body'}); &ETC::option_unlink(&HTML::auto_unlink(\$::FORM{'body'})); map(&HTML::escape(\$::FORM{$_}), keys %::FORM); #── 返信の場合 if ($::FORM{'follow'}) { require './app/lib/file/msg.pl'; my $o_message = new FILE::MESSAGE($CNF::place{'data'}{'path'}); (my $r_MSG = $o_message->one($::FORM{'follow'})) or &::error(\'返信元の記事を読み込めませんでした。'); local *MSG = $r_MSG; #── 参照文 &MESSAGE::quot_color(\$MSG{'body'}); $MSG{'body'} =~ s/^/  /gm; $r_reference = &DESIGN::reference(\$MSG{'body'}); } #── 各種入力欄の設定 my $upload_input; $CNF::upload{'mode'} && map($upload_input .= ${&DESIGN::upload_input}, (0 .. ($CNF::upload{'enable'}{'number'} - 1))); $CNF::mail{'inform'}{'mode'} && (my $r_inform_mail_input = &DESIGN::inform_mail_input); $CNF::mail{'owner'}{'mode'} && (my $r_owner_mail_input = &DESIGN::owner_mail_input); $CNF::view{'genre'}{'mode'} && (my $r_genre_input = &DESIGN::genre_input); $CNF::view{'tree'}{'sort'}{'mode'} && $CNF::post{'sage'}{'mode'} && (my $r_sage_input = &DESIGN::sage_input); $CNF::view{'body_color'}{'mode'} && (my $r_body_color_input = &DESIGN::body_color_input); ##スパム対策系 my $r_timekey = $::FORM{'timekey'}; $r_numcrypted = $::FORM{'num_crypted'}; #── 入力欄表示 &DESIGN::post($r_genre_input, \$::FORM{'subject'}, \$::FORM{'body'}, \$upload_input, $r_sage_input, $r_inform_mail_input, $r_owner_mail_input, $r_reference, $r_body_color_input, $r_timekey, $r_numcrypted ); &BASE::foot('pst'); } #┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #┃ 絵文字パッド #┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sub emoji_pad { do "$::SYS{'path_skn'}/platforms/pc/emj.skin.pl"; require './app/lib/htm.pl'; &BASE::simple_header; &DESIGN::view; } #┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #┃ オートローダー #┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sub AUTOLOAD { my $name = ($AUTOLOAD =~ /^POST::(.+)$/)[0]; push(@{$::FLAG{'eval'}}, $AUTOLOAD); if (!defined $SUB{$name}) { &::error(\"定義されていない関数($AUTOLOAD)が呼ばれました。"); exit; } eval $SUB{$name}; length($@) && &::error(\"EVAL ERROR: $@ ($AUTOLOAD)"); delete $SUB{$name}; goto &{'POST::' . $name}; } %SUB = ( identify => <<'__SUB__', #┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #┃ 二重投稿防止 #┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sub identify { require './app/lib/file/psi.pl'; my $digest = &COMMON::sha1(\"$::FORM{'subject'}\t$::FORM{'body'}"); my $o_identify = new FILE::POST_IDENTIFY($CNF::place{'data'}{'path'}); return($o_identify, $o_identify->update({digest => $digest, host => $::FORM{'host'}, time => $::FLAG{'time'}}, $CNF::post{'identify'}{'total'}, $CNF::post{'interval'})); } __SUB__ write_total => <<'__SUB__', #┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #┃ ツリー&記事数記録 #┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sub write_total { require './app/lib/file/ttl.pl'; my $o_total = new FILE::TOTAL($CNF::place{'data'}{'path'}); return($o_total, $o_total->add($::FORM{'tree'} == $::FORM{'no'})); } __SUB__ write_tree => <<'__SUB__', #┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #┃ ツリー記録 #┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sub write_tree { require './app/lib/file/tre.pl'; my($item, %value); my @param = qw(date follow genre name no subject time); foreach $item (keys %::FORM) { ($item =~ /^opt_\w+$/ || grep(($_ eq $item), @param)) && ($value{$item} = $::FORM{$item}); } $value{'file'} = $::FORM{'file'} ? @{$::FORM{'file'}} : 0; my $o_tree = new FILE::TREE($CNF::place{'data'}{'path'}); #sage add if ($::FORM{'sage'}) { return($o_tree, $o_tree->write(\%value, $::FORM{'tree'},0)); } else { return($o_tree, $o_tree->write(\%value, $::FORM{'tree'}, $CNF::view{'tree'}{'sort'}{'mode'})); } # return($o_tree, $o_tree->write(\%value, $::FORM{'tree'}, # $CNF::view{'tree'}{'sort'}{'mode'})); } __SUB__ write_message => <<'__SUB__', #┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #┃ 記事記録 #┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sub write_message { my @param = qw( agent body date email follow genre host host_ext ident inform_mail owner_mail mail_mode mobile name no sage subject time tree typewriter user_id web body_color ); my($item, %value); foreach $item (keys %::FORM) { ($item =~ /^opt_\w+$/ || grep(($_ eq $item), @param)) && ($value{$item} = $::FORM{$item}); } if ($::FORM{'file'}) { my(@file, $file); foreach $file (@{$::FORM{'file'}}) { my %file; foreach (keys %{$file}) { $file{$_} = ${$file}{$_};} $file{'size'} = &COMMON::size($file{'size'}); push(@file, \%file); } $value{'file'} = \@file; } $value{'key'} = length($::FORM{'key'}) ? &COMMON::make_pass($::FORM{'key'}) : ''; $::FORM{'key_val'} = $value{'key'}; my $o_message = new FILE::MESSAGE($CNF::place{'data'}{'path'}); return($o_message, $o_message->write(\%value)); } __SUB__ write_file => <<'__SUB__', #┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #┃ 添付ファイル情報記録 #┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sub write_file { require './app/lib/file/fle.pl'; my $o_file = new FILE::FILE($CNF::place{'data'}{'path'}); return($o_file, $o_file->write({no => $::FORM{'no'}, file => $::FORM{'file'}})); } __SUB__ write_frequency => <<'__SUB__', #┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #┃ 添付ファイル情報記録 #┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sub write_frequency { require './app/lib/file/frq.pl'; my $o_frequency = new FILE::FREQUENCY($CNF::place{'data'}{'path'}); $o_frequency->add($::FORM{'name'}, length($::FORM{'subject'} . $::FORM{'body'})); } __SUB__ # keyword => <<'__SUB__', ##┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ##┃ キーワード記録 ##┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # sub keyword { # require './app/lib/file/kyw.pl'; # my $str = "$::FORM{'subject'}\t$::FORM{'body'}"; # my $o_keyword = new FILE::KEYWORD($CNF::place{'data'}{'path'}); # $o_keyword->write($::FORM{'no'}, &STRING::keyword(\$str)); # $o_keyword->complete(); # } #__SUB__ # attach => <<'__SUB__', ##┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ##┃ 添付ファイル追加 ##┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # sub attach { # do "$::FLAG{'template'}/psn.skin.pl"; require './app/lib/htm.pl'; # do "$::FLAG{'template'}/msg.skin.pl"; # # #── 添付ファイル削除 # foreach (@{$::FORM{'file'}}) { # unlink("$CNF::place{'file'}{'path'}/${$_}{'name'}"); # } # # #── ロック解除 # &::unlock('msg'); # # #── パラメーターをセット # $::FORM{'cmd'} = 'psn'; # foreach (qw(email key mail_mode name inform_mail owner_mail web genre sage body_color)) { # $::COOKIE{$_} = $::FORM{$_}; # } # my $body = $::FORM{'body'}; # $::FORM{'file'} # && map($_{'size'} = &COMMON::size($_{'size'}), @{$::FORM{'file'}}); # # ##── プレビュー表示 # #&BASE::head('pst'); &MESSAGE::all(\%::FORM); # # #── パラメーターを修正 # $::FORM{'body'} = $body; # $CNF::post{'emoji'}{'mode'} && &EMOJI::cancel(\$::FORM{'body'}); # &ETC::option_unlink(&HTML::auto_unlink(\$::FORM{'body'})); # map(&HTML::escape(\$::FORM{$_}), keys %::FORM); # # #── 返信の場合 # if ($::FORM{'follow'}) { # require './app/lib/file/msg.pl'; # require './app/cmd/msg.pl'; # my $o_message = new FILE::MESSAGE($CNF::place{'data'}{'path'}); # (my $r_MSG = $o_message->one($::FORM{'follow'})) # or &::error(\'返信元の記事を読み込めませんでした。'); # local *MSG = $r_MSG; # # #── 参照文 # &MESSAGE::quot_color(\$MSG{'body'}); $MSG{'body'} =~ s/^/  /gm; # $r_reference = &DESIGN::reference(\$MSG{'body'}); # } # # #── 各種入力欄の設定 # my $upload_input; # $CNF::upload{'mode'} # && map($upload_input .= ${&DESIGN::upload_input}, # (0 .. ($CNF::upload{'enable'}{'number'} - 1))); # $CNF::mail{'inform'}{'mode'} # && (my $r_inform_mail_input = &DESIGN::inform_mail_input); # $CNF::mail{'owner'}{'mode'} # && (my $r_owner_mail_input = &DESIGN::owner_mail_input); # $CNF::view{'genre'}{'mode'} # && (my $r_genre_input = &DESIGN::genre_input); # $CNF::view{'tree'}{'sort'}{'mode'} # && $CNF::post{'sage'}{'mode'} # && (my $r_sage_input = &DESIGN::sage_input); # $CNF::view{'body_color'}{'mode'} # && (my $r_body_color_input = &DESIGN::body_color_input); # # #スパム対策系 # if($::FORM{'cmd'} ne "mdt"){&tohoho;} # my $r_timekey; # if($::FORM{'cmd'} ne "mdt"){ # $r_timekey = &make_timekey($CNF::antispam{'timekey'}{'idseed'}); # } # # #── 入力欄表示 # &DESIGN::post($r_genre_input, \$::FORM{'subject'}, \$::FORM{'body'}, # \$upload_input, $r_sage_input, $r_inform_mail_input, # $r_owner_mail_input, $r_reference, # $r_body_color_input, $r_timekey, $r_postkey_input, # $upfile_list, $upfile_size, # $upfile_com, $upsize_com, $sub_com, $name_com, $email_com, $key_com, # $body_com, $web_com, $gen_com); # # # &BASE::foot('pst'); # } #__SUB__ ); 1;