【问题标题】:Why does my system call to another CGI script work on the command line but not when run as a CGI program?为什么我对另一个 CGI 脚本的系统调用可以在命令行上运行,但在作为 CGI 程序运行时却不行?
【发布时间】:2012-12-12 13:26:52
【问题描述】:

我有一个 scriptA.cgi,它调用 scriptB.cgi。

scriptB.cgi 需要一个参数。

我都试过了 在我尝试过的 scriptA.cgi 中:

`perl -l scriptB.cgi foo="toast is good" `;

还有

@args = ("perl", "-l", "scriptB.cgi", "foo=\"toast is good\"");
system(@args);

当我从命令行调用 scriptA.cgi 时,它按预期工作。 但是,当我通过浏览器调用 scriptA.cgi 时 scriptB.cgi 被执行,但它无法读取传入的参数并将 foo 打印为空。

有没有更丑陋的方式来调用另一个 cgi 并传入参数?

scriptB 不必是 cgi,如果使用直接的 .pl 和 args 更容易做到这一点,我也很乐意这样做......但 arg 必须是带空格的引号字符串。

欢迎所有想法。

【问题讨论】:

  • 为什么将它们放在不同的程序中?
  • 因为它们是独立的程序......它们做不同的事情。具体来说,scriptB 发送 SMS 消息。它将电话号码和消息作为参数。它被许多其他脚本使用,并且在所有其他程序中实际包含该代码将非常难看。
  • 您实际上并没有显示不起作用的代码。
  • 我实际上已经展示了不起作用的代码!我展示了两个例子。你还想看什么?我的问题的重点是,当我从命令行运行初始脚本(调用第二个脚本)时,代码确实有效。它与其余代码的作用有什么不同?两个脚本都可以正常工作,唯一不起作用的是将参数从 scriptA 传递到 scriptB,我详细说明了我在这方面所做的工作。
  • 你没有展示你是如何尝试在 scriptB 中获取参数的。

标签: perl cgi


【解决方案1】:

如果许多脚本之间有共同的功能,把它放在一个模块中

模块可能看起来很吓人,但它们确实非常简单。

文件SMSTools.pm

package SMSTools;
use strict;
use warnings;
use Exporter qw(import);

# Name subs (and variables, but don't do that) to export to calling code:
our @EXPORT_OK = qw( send_sms_message );

our @EXPORT = @EXPORT_OK;  
# Generally you should export nothing by default.
# However, for simple cases where there is only one key function
# provided by a module, I believe it is reasonable to export it by default.


sub send_sms_message {
    my $phone_number = shift;
    my $message      = shift;

    # Do stuff.

    return; # Return true on successful send.
}

# Various supporting subroutines as needed.

1;  # Any true value.

现在,在foo.cgi 中使用您的模块:

use strict;
use warnings;
use CGI;

use SMSTools;

my $q = CGI->new;

my $number = $q->param_fetch( 'number');
my $message = $q->param_fetch( 'msg');

print 
    $q->header,
    $q->start_html,
    (    send_sms_message($number, $message) 
         ? $q->h1("Sent SMS Message") 
         : $q->h1("Message Failed")
    ),
    q->end_html; 

请参阅perlmodthe docs for Exporter 了解更多信息。

【讨论】:

  • 这是一个很好的答案,我赞成,但我仍然想弄清楚我最初的问题的答案。不过,非常感谢。
【解决方案2】:

我怀疑 CGI 环境妨碍了您。你在用 CGI.pm 吗?

当您从命令行运行 CGI 脚本时,您可能还没有设置任何 CGI 环境变量,例如 QUERY_STRING。 CGI 脚本启动,注意到它缺少那些环境变量,并认为它一定是从命令行运行的。如果它认为它是从命令行运行的,它会在其他地方(例如@ARGV)查找数据。这是我的第一个猜测。

CGI 程序案例中可能会发生各种事情。很可能,scriptB.cgi 使用与 scriptA.cgi 相同的环境设置,但它没有所需的参数或数据。由于 CGI 环境已经建立,并且有一个 QUERY_STRING 变量,它永远不会想到去查看 @ARGV

但是,您有很多选择,具体取决于您想要做什么(这超出了您的情况):

  • 如果您只需要 scriptB.cgi 来支持其他脚本(即浏览器不应该直接调用它),请将其设为库或模块。您应该始终尝试这样做。使每个脚本至少是一个模数。

  • 如果 scriptB.cgi 是一个独立的 CGI 脚本并且应该保持这种状态,请在 scriptA.cgi 中发出子请求,以便通过服务器设置所有正常的 CGI 内容。

  • 如果您不想进行子请求,请本地化 %ENV,哪些子进程将共享,并自己伪造 CGI 环境。这有点工作,但并不难。

【讨论】:

  • 布赖恩!听到你的声音真是太好了。大约 12 年前,你和我一起为 Smith Renaud 工作。我希望你在生活中的表现和你的 SO 积分一样好!我非常喜欢你的回答,我相信它可以解决我的问题。如果你有一个公共电子邮件地址,你可以在这里发帖,我会把我的发给你。新年快乐,-吉恩
  • 哦,嘿,吉恩,我只是在和某人谈论你。我们在谈论俄罗斯的笑话如何永远不会翻译成英语,以及你如何总是不得不说“俄罗斯很有趣”:)
【解决方案3】:

还有一个选择是使用hidden field 在CGI 脚本之间传递参数。顾名思义,这些字段对用户是不可见的,但可以像任何其他字段一样用于传递参数。

【讨论】:

    【解决方案4】:

    请参阅此处的“解码表单输出”:

    http://www.cgi101.com/class/ch4/text.html

    (她的 post.cgi 脚本对我诊断这个问题非常宝贵。)

    对于那些使用 CGI.pm 的人来说,还有一点需要注意——它使用multipart/form-data 作为其默认编码类型,“适用于……用于传输二进制数据的形式”。有趣的是,将编码类型更改为另一种选项后,一切都按预期进行:

    enctype=>"application/x-www-form-urlencoded"
    

    (使用 Windows XP、Perl 5.10、CGI.pm 3.43 和 Apache 2 测试)

    【讨论】:

      【解决方案5】:

      这是我编写的一些代码的 sn-p,它有一个调用 Perl 脚本的 *.cgi 脚本:

      $note = "toast is good";
      $cmd = "addAccTrans.pl $priAcc $date $priGrp \"$note\" $amt";<br />
      open($f, "perl $cmd|");<br />
      while(<$f>) { print "$_\n" };<br />
      close($f);<br />
      

      CGI 脚本捕获 Perl 脚本的输出并再次打印出来。

      【讨论】:

      • 哎哟。如果 $priAcc 有类似 foo; 的东西怎么办? rm -rf /*?或者更现实地说,这样的变量可以用来上传引导脚本以供将来 pwnage 使用。
      • 这就是你首先清理 $cmd 的原因。
      • @unk,这就是为什么你不通过 shell 传递用户输入的原因——不管是否经过清理。
      【解决方案6】:

      答:

      #!/usr/bin/perl
      print "Content-type: text/html\n\n";
      {
          local $foo = "toas is bad";
          do 'b.cgi';
      }
      

      乙:

      #!/usr/bin/perl
      print "$foo";
      

      【讨论】:

      • 为什么下线?这完成了你的要求?
      • 我不是降级的人...如果有人花时间尝试帮助我,我永远不会降级,即使他们的信息没有用(不是说你的't)。你能解释一下你的代码中发生了什么吗?我不明白为什么 $foo 会在这里被用作 cgi 调用的参数
      • 如果使用do FILE 似乎是一个不错的解决方案,那么您确实应该使用模块。
      • 你不知道这样做会给调用程序带来什么破坏。它可以改变各种状态、破坏数据等等。至少对于一个模块,在调用其中一个子例程之前,您通常不会真正运行代码。
      猜你喜欢
      • 2023-03-05
      • 1970-01-01
      • 1970-01-01
      • 2016-10-31
      • 2017-01-01
      • 1970-01-01
      • 2016-10-04
      • 2021-10-06
      • 2016-07-30
      相关资源
      最近更新 更多