Perl IPC::Open3在Apache下运行失败

Perl IPC::Open3在Apache下运行失败,perl,apache,ipc,mod-perl2,Perl,Apache,Ipc,Mod Perl2,我有一个模块,它使用IPC::Open3(或IPC::Open2,两者都存在此问题)调用外部二进制文件(本例中为bogofilter),并通过子输入文件句柄向其提供一些输入,然后从子输出句柄读取结果。在大多数环境中运行时,代码工作正常。但是,该模块的主要用途是在Apache2.2.6下运行的web服务中。在这种环境下,我得到了一个错误: 无法打开标准输出:参数无效 这仅在代码在Apache下运行时发生。在此之前,代码构造了一个极其复杂的命令,其中包含一个用于输入的here文档,并使用back t

我有一个模块,它使用IPC::Open3(或IPC::Open2,两者都存在此问题)调用外部二进制文件(本例中为bogofilter),并通过子输入文件句柄向其提供一些输入,然后从子输出句柄读取结果。在大多数环境中运行时,代码工作正常。但是,该模块的主要用途是在Apache2.2.6下运行的web服务中。在这种环境下,我得到了一个错误:

无法打开标准输出:参数无效


这仅在代码在Apache下运行时发生。在此之前,代码构造了一个极其复杂的命令,其中包含一个用于输入的here文档,并使用back ticks运行它。这是可行的,但非常缓慢,而且容易以独特而复杂的方式崩溃。我不想回到旧版本,但我无法破解它。

这可能是因为mod_perl 2关闭了STDOUT吗?我刚刚发现了这一点并发布了相关信息:

http://marc.info/?l=apache-modperl&m=126296015910250&w=2
我认为这是一个令人讨厌的错误,但到目前为止似乎没有人关心它。如果您的问题与此相关,并且希望引起注意,请在mod_perl列表上发布后续信息


Jon

Bogofilter为垃圾邮件/非垃圾邮件返回不同的退出代码

您可以通过将stdout重定向到/dev/null来“修复”这个问题

system("bogofilter < $input > /dev/null") >> 8;
system(“bogofilter<$input>/dev/null”)>>8;
将为垃圾邮件返回0,为非垃圾邮件返回1,为未知返回2(>>8是因为perl帮助更正了退出代码,这修复了损坏)

注意:缺少环境也可能会阻止bogofilter查找其单词列表,因此也要显式地传入:

system("bogofilter -d /path/to/.bogofilter/ < $input > /dev/null") >> 8;
system(“bogofilter-d/path/to/.bogofilter/<$input>/dev/null”)>>8;
(其中/path/to/.bogofilter包含wordlist.db)


您无法检索bogofilter以这种方式给出的实际评级,但它确实给您带来了一些好处。

如果您的代码只在Linux/Unix系统上运行,则很容易编写一个不会失败的open3替换,因为标准输出不是真正的文件句柄:

sub my_open3 {
    # untested!
    pipe my($inr), my($inw) or die;
    pipe my($outr), my($outw) or die;
    pipe my($errr), my($errw) or die;
    my $pid = fork;
    unless ($pid) {
        defined $pid or die;
        POSIX::dup2($inr, 0);
        POSIX::dup2($outw, 1);
        POSIX::dup2($errw, 2);
        exec @_;
        POSIX::_exit(1);
    }
    return ($inw, $outr, $errr);
}

my ($in, $out, $err) = my_open3('ls /etc/');

注意:我不是perl向导

正如@JonathanSwartz所建议的,我认为问题在于apache2 modu perl关闭了STDIN和STDOUT。这与IPC::Open3的工作无关,但它有一个bug

总之(这是我不太清楚的部分),open3尝试将子进程STDIN/OUT/ERR与您的进程相匹配,或者在请求时复制它。由于open('>&=X')的一些未记录的方式可以工作,因此它通常可以正常工作,但STDIN/OUT/ERR关闭的情况除外

这会深入到细节中

一种解决方案是修复IPC::Open3,如这两个链接中所述。另一个对我有效的方法是在mod_perl代码中临时打开STDIN/OUT,然后关闭它:

my ($save_stdin,$save_stdout);
open $save_stdin, '>&STDIN';
open $save_stdout, '>&STDOUT';
open STDIN, '>&=0';
open STDOUT, '>&=1';

#make your normal IPC::Open3::open3 call here

close(STDIN);
close(STDOUT);
open STDIN, '>&', $save_stdin;
open STDOUT, '>&', $save_stdout;

另外,我注意到网上有很多关于IPC::Run3遇到同样问题的投诉,因此如果有人遇到同样的问题,我怀疑同样的解决方案会起作用。

如果需要专门使用Open3,我不认为这是直接的问题。