[一覧に戻る]
デバッグ用 イベント自由自在アイテム

   (04/03/26)表示を微調整(内容の意味、ソースコードは同じ)
   (04/07/04)[重要]任意のスクリプトを実行可能なセキュリティホールを修正
   (05/01/03)USERPASS系認証時に過去のクッキーで認証しようとする問題を修正
             エラーメッセージを変更


イベント編集してると発動しないとデバッグできなくて面倒なものですが、
発動を自由自在に制御できるアイテムができました。

が・・・
結構デンジャーなことしてます(笑)
おかげで動的な使用表示が実現しましたが。

   04/07/04挿入

・・・とか書いてたら本当にデンジャーで笑い事にならないセキュリティホールを発見してしまいました。
このセキュリティホールはかなり危険です。
もしこのスクリプトをデバッグ用ではなく実運営版で使用している場合は直ちに更新してください。
(デバッグ用のみの使用であるとしても更新を推奨します)

●詳細
   イベント起動部に特定の文字列を入力すると無効なイベントを起動してしまいます。
   以降イベントによる影響を受けるスクリプトを起動するごとに無効なイベントを呼び出します。
   しかし呼び出された無効なイベントの内容は正常なイベントではないため、
   異常動作により暴走、強制終了、データ破壊などの問題を発生させます。
   また、条件によっては外部からの攻撃の足掛かりにされる危険性もあります。
   
   上記「特定の文字列」は第三者が発見することは比較的容易なため、直ちに更新することを推奨します。
   
   ただし、攻撃者がこのスクリプトを起動するアイテムを入手することが条件になります。
   これはSOLD自体の防御機構によってこのスクリプトが起動される前に終了されるためです。

   04/07/04挿入ここまで
   05/01/03挿入


   オークションの方で11月末に修正した問題がこちらの方にも存在するということが判明したので修正しました。
   こちらでも「USERPASS系で認証している場合に過去のクッキー情報で認証しようとする」問題で、
   ログアウトする、タイムアウトする、前回のログイン店舗として操作しようとする等の現象が発生する可能性があります。
   
   ついでにエラーメッセージも変更しました。
   
   05/01/03挿入ここまで

要望があれば詳細な解説作りますが・・・
作ったら何行になるかな・・・(笑)

互換性はver03-04-11以上必須です。
ver02-07-28系でも改造すれば一応使えますが・・・

今あるイベント一覧と発動状態を取得して表示することができます
表示にはstartmsgか、codeが使われます。
ただし、自動発動なしの場合はstartmsgが取得できないので常にcode表示になります。

イベント終了を使うと無条件に強制終了されますのでご注意ください。

アイテム定義です。アイテムパラメータは適当に変えてもかまいません。

でも120行もあるアイテム定義って・・・(笑)
まだ続きます

@@ITEM
   no      82
   type   道具
   code   eventitem2
   name   イベント制御キット
   info   テスト専用スーパーキット
   price   0
   cost   0
   limit   500/2000
   scale   回
   plus    1m
   @@USE
      time   1s
      action   ニセモノ。押すな
      name   イベント起動
      info   イベントを起動します
      arg nocount
      okmsg   起動完了
         need      1   イベント制御キット
      funci _local_
         require (main::GetPath($main::ITEM_DIR,"event"));
         my $mes="<form action=\"$main::MYNAME\" $main::METHOD><SELECT NAME=eventcode>";
         my %event=%EVENT;
         opendir(DIR,$main::ITEM_DIR."/event");
         my @eventfile=grep(/.$main::FILE_EXT$/,readdir(DIR));
         closedir(DIR);
         foreach(@eventfile){
            $_=substr($_,0,length($_)-length($main::FILE_EXT));
            next if(defined $event{$_});
            $event{$_}={};
            $event{$_}->{code}=$_;
            $event{$_}->{startmsg}="[手動発動専用]$_";
         }
         foreach(sort(keys(%event))){
            $mes.="<option value=\"$event{$_}->{code}\">";
            $mes.="[残り".int(($main::DTevent{$_}-$main::NOW_TIME)/60)."分]" if(exists $main::DTevent{$_});
            $mes.=$event{$_}->{startmsg} eq "" ? $_:$event{$_}->{startmsg};
         }
         $mes.="</select><INPUT TYPE=HIDDEN NAME=bk VALUE=\"$main::Q{bk}\">";
         $mes.=$main::USERPASSFORM;
         $mes.="<INPUT TYPE=HIDDEN NAME=item VALUE=\"$main::itemno\"><INPUT TYPE=HIDDEN NAME=no VALUE=\"$main::no\">";
         $mes.="<input type=hidden name=cnt1 value=\"1\"><INPUT TYPE=text NAME=eventtime size=5>分間<INPUT TYPE=SUBMIT VALUE='イベント実行'></form>";
         return $mes;
      _local_
      func   _local_
         return '無効なボタンです' if(!defined $main::Q{eventcode});
         my $eventcode=$main::Q{eventcode};
         my $count2=int(!defined $main::Q{eventtime} ? 0:$main::Q{eventtime});
         if($eventcode=~m/[\.\/]/){
            return "イベントコードに使用できない文字が使用されています";
         }
         return '既に実行済みです' if(exists $main::DTevent{$eventcode});
         return '実行時間が長すぎます' if($count2>525600);
         require (main::GetPath($main::ITEM_DIR,"event"));
         my $noauto=0;
         return '指定されたイベントは存在しません' if((!exists $EVENT{$eventcode})&&(($noauto=1) && !-e main::GetPath($main::ITEM_DIR,"event",$eventcode)));
         my $E={};
         $E=$EVENT{$eventcode} if(!$noauto);
         $E->{basetime}=1 if($noauto);
         return '実行時間が入力されていません' if($count2<1 && $E->{basetime}+$E->{plustime});
         my $msg;
         my $ret=1;
         my   $mes="未知の作用により「";
            $mes.=$E->{startmsg} eq "" ? $eventcode:$E->{startmsg};
            $mes.="」が発生しました";
         if($E->{startfunc}){
            @event::DT=@main::DT;
            @event::ITEM=@main::ITEM;
            main::RequireFile('inc-event.cgi');
            my $extfile=main::GetPath($main::ITEM_DIR,"event-s",$eventcode);
            require $extfile if -e $extfile;
            my $func="event::".$E->{startfunc};
            ($ret,$msg)=&$func(split(/[:,]/,$E->{startfuncparam}));
            WriteLog(2,0,$msg) if $msg;
            undef &$func;
            delete $INC{$extfile};
         }
         if($ret)
         {
            WriteLog(2,0,$E->{startmsg}) if $E->{startmsg};
            $main::DTevent{$eventcode}=$main::NOW_TIME+$count2*60 if ($E->{basetime}+$E->{plustime});
         }
         return $mes;
      _local_
   @@USE
      time   1s
      action   ニセモノ。押すな
      name   イベント終了
      info   イベントを強制終了します
      arg nocount
      okmsg   終了完了
         need      1   イベント制御キット
      funci _local_
         require (main::GetPath($main::ITEM_DIR,"event"));
         my $mes="<form action=\"$main::MYNAME\" $main::METHOD><SELECT NAME=eventcode>";
         foreach(keys(%main::DTevent)){
            $mes.="<option value=\"$_\">";
            $mes.="[残り".int(($main::DTevent{$_}-$main::NOW_TIME)/60)."分]";
            $mes.=$EVENT{$_}->{startmsg} eq "" ? $_:$EVENT{$_}->{startmsg};
         }
         $mes.="</select><INPUT TYPE=HIDDEN NAME=bk VALUE=\"$main::Q{bk}\">";
         $mes.=$main::USERPASSFORM;
         $mes.="<INPUT TYPE=HIDDEN NAME=item VALUE=\"$main::itemno\"><INPUT TYPE=HIDDEN NAME=no VALUE=\"$main::no\">";
         $mes.="<input type=hidden name=cnt1 value=\"1\"><INPUT TYPE=SUBMIT VALUE='イベント終了'></form>";
         return $mes;
      _local_
      func   _local_
         return '無効なボタンです' if(!defined $main::Q{eventcode});
         my $eventcode=$main::Q{eventcode};
         return '指定されたイベントは起動されていません' if(!exists $main::DTevent{$eventcode});
         require (main::GetPath($main::ITEM_DIR,"event"));
         my $E={};
         $E=$EVENT{$eventcode} if(exists $EVENT{$eventcode});
         delete $main::DTevent{$eventcode};
         WriteLog(2,0,$E->{endmsg}) if $E->{endmsg};
         my   $mes="未知の作用により「";
            $mes.=$E->{startmsg} eq "" ? $eventcode:$E->{startmsg};
            $mes.="」が終了しました";
         return $mes;
      _local_



表示テキストは適当に変えても構いません・・・アルファベットの中に表示テキストだけが浮いている・・・(笑)

これを書くだけなんですが、02-07-28以前ではfunciがエラーになるので、
さらにいろいろ改造しなきゃいけません。

デバッグ中にしばしば「戻る」のリンクが壊れたのが気になるんですが・・・
デバッグアイテムだからいいかな?
ということで無視してます。

02-07-28系で使う時はfunciの定義を他のところに書くことでなんとかなります。
(1)inc/html-item-usemode.cgiの95行目あたり({$nonuse=1; $disp.="<B>熟練度が足りません</B><BR>";}の次)に、

require(GetPath("item-use-i/".$ITEM[$itemno]->{code})),$disp.=&{"item::_local_i$no"}() if(-e GetPath("item-use-i/".$ITEM[$itemno]->{code}));

を追記します。
(2)data/item-use-iディレクトリを作成します
(3)アイテムのcodeと同じ名前でデータファイルと同じ拡張子のファイルを、作成したディレクトリに入れます(デフォルトでは eventitem2.cgi)
(4)3で作成したファイルの中身を以下の通りにします
まだ続きます

package item;

sub _local_i0{
   require (main::GetPath($main::ITEM_DIR,"event"));
   my $mes="<form action=\"$main::MYNAME\" $main::METHOD><SELECT NAME=eventcode>";
   my %event=%EVENT;
   opendir(DIR,$main::ITEM_DIR."/event");
   my @eventfile=grep(/.$main::FILE_EXT$/,readdir(DIR));
   closedir(DIR);
   foreach(@eventfile){
      $_=substr($_,0,length($_)-length($main::FILE_EXT));
      next if(defined $event{$_});
      $event{$_}={};
      $event{$_}->{code}=$_;
      $event{$_}->{startmsg}="[手動発動専用]$_";
   }
   foreach(sort(keys(%event))){
      $mes.="<option value=\"$event{$_}->{code}\">";
      $mes.="[残り".int(($main::DTevent{$_}-$main::NOW_TIME)/60)."分]" if(exists $main::DTevent{$_});
      $mes.=$event{$_}->{startmsg} eq "" ? $_:$event{$_}->{startmsg};
   }
   $mes.="</select><INPUT TYPE=HIDDEN NAME=bk VALUE=\"$main::Q{bk}\">";
   $mes.=$main::USERPASSFORM;
   $mes.="<INPUT TYPE=HIDDEN NAME=item VALUE=\"$main::itemno\"><INPUT TYPE=HIDDEN NAME=no VALUE=\"$main::no\">";
   $mes.="<input type=hidden name=cnt1 value=\"1\"><INPUT TYPE=text NAME=eventtime size=5>分間<INPUT TYPE=SUBMIT VALUE='イベント実行'></form>";
   return $mes;
}
sub _local_i1{
   require (main::GetPath($main::ITEM_DIR,"event"));
   my $mes="<form action=\"$main::MYNAME\" $main::METHOD><SELECT NAME=eventcode>";
   foreach(keys(%main::DTevent)){
      $mes.="<option value=\"$_\">";
      $mes.="[残り".int(($main::DTevent{$_}-$main::NOW_TIME)/60)."分]";
      $mes.=$EVENT{$_}->{startmsg} eq "" ? $_:$EVENT{$_}->{startmsg};
   }
   $mes.="</select><INPUT TYPE=HIDDEN NAME=bk VALUE=\"$main::Q{bk}\">";
   $mes.=$main::USERPASSFORM;
   $mes.="<INPUT TYPE=HIDDEN NAME=item VALUE=\"$main::itemno\"><INPUT TYPE=HIDDEN NAME=no VALUE=\"$main::no\">";
   $mes.="<input type=hidden name=cnt1 value=\"1\"><INPUT TYPE=SUBMIT VALUE='イベント終了'></form>";
   return $mes;
   _local_
}
1;



subの後の名前は _local_i"USEの番号(上から0起算で)"になります。
最初のUSEが0から始まることにご注意ください。(名前が間違っていると全体がエラーになります)

本当はdata/itemの中に入れたかったのですが、入れるとmakeitemした時に消されてしまうのでdataに入れることにしました。

ちなみに、他にも同じ命名規則を用いることにより、03-04-11以降のfunciとほぼ同じものを実行できます。
[注意]03-04-11以降のバージョンにはこの操作を行わないでください。
  行うと本来のfunci関数と競合するため、場合によっては予期せぬエラーが発生する可能性があります。
  (何事もなく動くかもしれませんが推奨はしません)


(5)funci部分を削除します
アイテム定義のfunci _local_から終わりの_local_までを削除します。

funci部分を削除した02-07-28用アイテム定義(81行・・・まだ長い)

@@ITEM
   no      82
   type   道具
   code   eventitem2
   name   イベント制御キット
   info   テスト専用スーパーキット
   price   0
   cost   0
   limit   500/2000
   scale   回
   plus    1m
   @@USE
      time   1s
      action   ニセモノ。押すな
      name   イベント起動
      info   イベントを起動します
      arg nocount
      okmsg   起動完了
         need      1   イベント制御キット
      func   _local_
         return '無効なボタンです' if(!defined $main::Q{eventcode});
         my $eventcode=$main::Q{eventcode};
         my $count2=int(!defined $main::Q{eventtime} ? 0:$main::Q{eventtime});
         if($eventcode=~m/[\.\/]/){
            return "イベントコードに使用できない文字が使用されています";
         }
         return '既に実行済みです' if(exists $main::DTevent{$eventcode});
         return '実行時間が長すぎます' if($count2>525600);
         require (main::GetPath($main::ITEM_DIR,"event"));
         my $noauto=0;
         return '指定されたイベントは存在しません' if((!exists $EVENT{$eventcode})&&(($noauto=1) && !-e main::GetPath($main::ITEM_DIR,"event",$eventcode)));
         my $E={};
         $E=$EVENT{$eventcode} if(!$noauto);
         $E->{basetime}=1 if($noauto);
         return '実行時間が入力されていません' if($count2<1 && $E->{basetime}+$E->{plustime});
         my $msg;
         my $ret=1;
         my   $mes="未知の作用により「";
            $mes.=$E->{startmsg} eq "" ? $eventcode:$E->{startmsg};
            $mes.="」が発生しました";
         if($E->{startfunc}){
            @event::DT=@main::DT;
            @event::ITEM=@main::ITEM;
            main::RequireFile('inc-event.cgi');
            my $extfile=main::GetPath($main::ITEM_DIR,"event-s",$eventcode);
            require $extfile if -e $extfile;
            my $func="event::".$E->{startfunc};
            ($ret,$msg)=&$func(split(/[:,]/,$E->{startfuncparam}));
            WriteLog(2,0,$msg) if $msg;
            undef &$func;
            delete $INC{$extfile};
         }
         if($ret)
         {
            WriteLog(2,0,$E->{startmsg}) if $E->{startmsg};
            $main::DTevent{$eventcode}=$main::NOW_TIME+$count2*60 if ($E->{basetime}+$E->{plustime});
         }
         return $mes;
      _local_
   @@USE
      time   1s
      action   ニセモノ。押すな
      name   イベント終了
      info   イベントを強制終了します
      arg nocount
      okmsg   終了完了
         need      1   イベント制御キット
      func   _local_
         return '無効なボタンです' if(!defined $main::Q{eventcode});
         my $eventcode=$main::Q{eventcode};
         return '指定されたイベントは起動されていません' if(!exists $main::DTevent{$eventcode});
         require (main::GetPath($main::ITEM_DIR,"event"));
         my $E={};
         $E=$EVENT{$eventcode} if(exists $EVENT{$eventcode});
         delete $main::DTevent{$eventcode};
         WriteLog(2,0,$E->{endmsg}) if $E->{endmsg};
         my   $mes="未知の作用により「";
            $mes.=$E->{startmsg} eq "" ? $eventcode:$E->{startmsg};
            $mes.="」が終了しました";
         return $mes;
      _local_


最終更新 2005/01/03