1

私はPerl(POEに基づく)でボットに取り組んでおり、これまでのところうまくいっていますが、!jsまたは!perlコマンドを追加してそれぞれのコードを評価し、チャネルに出力する1行の出力を返す方法がわかりません。App :: EvalServerを見つけましたが、使い方がわかりません。

助けてくれてありがとう!

4

2 に答える 2

3

モジュールには、スタンドアロンアプリケーションとして実行するためのApp::EvalServerバイナリが付属しています。あなたはそれをあなたのプログラムに入れませんが、むしろそれ自身でそれを実行します。コードをjson文字列として渡すことができるポートを開きます。これも私には良い考えではないようです。

あなたが見たいと思うかもしれない別のモジュールがSafeと呼ばれています。これを使用する前に、完全なドキュメントとOpcodeのドキュメント(ドキュメントにリンクされている)を一読することをお勧めします。任意のコードを評価すると、重大な損害を与える可能性があります。決してそれを忘れないで。


アップデート:

printedコードの出力またはedコードsayからの出力をキャプチャする方法の例を次に示しevalます。open変数とともに使用して、 printed出力を常にその変数に送ることができます。後で元に戻すと、変数にキャプチャされた出力を操作できます。これは、メモリ内ファイルと呼ばれます。

use strict; use warnings;
use feature 'say'; 
use Safe;

# Put our STDOUT into a variable
my $printBuffer;
open(my $buffer, '>', \$printBuffer);
# Everything we say and print will go into $printBuffer until we change it back
my $stdout = select($buffer);

# Create a new Safe
my $compartment = new Safe;
$compartment->permit(qw(print)); # for testing

# This is where the external code comes in:
my $external_code = qq~print "Hello World!\n"~;

# Execute the code
my $ret = $compartment->reval($external_code, 1);

# Go back to STDOUT
select($stdout);

printf "The return value of the reval is: %d\n", $ret;
say "The reval's output is:";
say $printBuffer;

# Now you can do whatever you want with your output
$printBuffer =~ s/World/Earth/;
say "After I change it:";
say $printBuffer;

免責事項:このコードは自己責任で使用してください。


更新2:チャットでの長い議論の後、これが私たちが思いついたものです。revalこれは、たとえば無限ループが原因で時間がかかる場合に実行を停止するための一種のタイムアウトを実装します。

#!/usr/bin/perl
use warnings;
use strict;
use Safe;
use Benchmark qw(:hireswallclock);

my ($t0, $t1); # Benchmark
my $timedOut = 0;
my $userError = 0;
my $printBuffer;
open (my $buffer, '>', \$printBuffer);
my $stdout = select($buffer);
my $cpmt = new Safe;
$cpmt->permit_only(qw(:default :base_io sleep));
eval
{
        local $SIG{'ALRM'} = sub { $timedOut = 1; die "alarm\n"};
        $t0 = Benchmark->new;
        alarm 2;
        $cpmt->reval('print "bla\n"; die "In the user-code!";');
#         $cpmt->reval('print "bla\n"; sleep 50;');
        alarm 0;
        $t1 = Benchmark->new;
        if ($@)
        {
                $userError = "The user-code died! $@\n";
        }
};
select($stdout);


if ($timedOut)
{
        print "Timeout!\n";
        my $td = timediff($t1, $t0);
        print timestr($td), "\n";
        print $printBuffer;
}
else
{
        print "There was no timeout...\n";
        if ($userError)
        {
                print "There was an error with your code!\n";
                print $userError;
                print "But here's your output anyway:\n";
                print $printBuffer;
        }
        else
        {
          print $printBuffer;
        }
}
于 2012-06-24T21:37:00.653 に答える
2

perl eval()を見てください。変数/文字列を渡すことができ、perlコードであるかのように評価されます。同様にjavascriptには、同様に実行されるeval()関数もあります。

ただし、完全に閉じた環境で実行できる場合を除いて、perlまたはjavascriptで任意のコードを評価しないでください(それでも、それは悪い考えです)。多くの人が、これが起こらないようにするために多くの時間を費やしています。だから、それはあなたがそれをする方法です、しかしあなたはそれをしたくありません、本当に全く。

于 2012-06-24T21:05:27.363 に答える