#┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#┃■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{'email'} =~ s/>/ /g;
$::FORM{'web'} =~ 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;