PHP @exec静默失败

时间:2009-04-03 16:40:51

标签: php iis exec

这让我发疯了。我正在尝试在我的PHP Web应用程序的Windows框中执行命令行语句。它运行在Windows XP,IIS5.1上。 Web应用程序运行正常,但我不能让@exec()使用特定的contactenated变量。我的命令结构如下:

$cmd = ($config->svn." cat ".$this->repConfig->svnParams().quote($path).' -r '.$rev.' > '.quote($filename));

当命令生成以下字符串时,此命令不能如上所述:

svn --non-interactive --config-dir /tmp cat "file:///c:/temp/test/acccount/dbo_sproctest.sql" -r 1 > "C:\Inetpub\sites\websvn\temp\wsv5B45.tmp"

如果我将其复制/粘贴到我自己的命令行,它可以正常工作。

如果我硬编码相同的路径而不是将其与变量一起添加,它就可以了!我已尝试使用和不带引号的文件名。我在整个命令周围尝试过和没有引号。我试过其他目录。我已经尝试将输出参数传递给exec(),它返回空(Array())。我已经尝试将命令错误流的输出重定向到文件,并且永远不会创建错误输出文件。

我唯一可以理解的是exec()默默地失败了。我到底是做错了什么?如果我硬编码文件路径,使用相同的目录结构和文件名,它工作正常。如果我不这样做,那就没有。

也许文件路径中的斜杠()没有被正确转义,但是当我用单引号手动执行时,它们不被视为转义序列?

更新:

我从执行官那里拿走了@,但仍然没有看到任何错误。

我给了SVN的完整路径,但仍然没有运气。应该注意的是,只要我手动指定cat的文件目的地,该命令就可以使用非完整路径SVN。

更新2:RE:Kieth

我通过尝试两种方式调用exec:

exec($cmd);

exec($cmd, $out);

我的php.ini已经安装了safe_mode =。

我添加了error_reporting(E_ALL);并没有看到任何新的

如果我回复(或print_r)我的exec电话,我实际上并没有看到任何

如果我在包含输出var时回显(或print_r)我的exec调用,我得到一个空的arr

更新3

我尝试了escapeshellcmd和escapeshellarg都无济于事(好主意)。

我应该添加该文件是通过调用

创建的
tempnam("temp", "wbsn");

如果我手动指定字符串而不是让它由tempname生成,它的工作原理就好了,这似乎表明问题的根源,但我无法弄清楚如何。我对手动字符串与生成的字符串进行了比较,然后作为匹配返回。

9 个答案:

答案 0 :(得分:23)

@exec将始终无声地失败,因为@是PHP的错误抑制运算符。

答案 1 :(得分:5)

不确定这是否会对你有所帮助,因为你在Windows上,我在Linux上,但是我遇到了来自PHP exec()的同样的静默错误问题。我发现我试图发出的命令(nconvert)将其错误消息发送到标准错误流,而不是标准输出。所以我添加了

  

2>&1

在命令行的末尾,将我的错误重定向回标准流。然后我可以看到nconvert正在给我一个允许拒绝错误。

答案 2 :(得分:2)

可能是您的PHP脚本与您的用户帐户的PATH不同。尝试删除@并查看它是否尝试抛出错误。

此外,您可能希望尝试将完整的文件系统路径放到SVN可执行文件中。

答案 3 :(得分:1)

好吧,如果删除@无效,请尝试在您正在运行的代码段的开头包含此内容:

error_reporting(E_ALL);

这将打开完整的错误报告,以防您在php.ini文件中将其关闭或停用。

我不认为您可以告诉我们您是如何调用exec()的?您是否还可以检查以确保您不会在安全模式下意外运行脚本?你是否回应exec()正在返回的内容,如果是,它又回来了什么?

答案 4 :(得分:1)

我不是添加其他回复的忠实粉丝,但如果我只是编辑之前的回复,您可能看不到它。

PHP为shell脚本提供了一些特殊的转义命令:escapeshellcmdescapeshellarg

你应该可以在整个$ cmd周围使用escapeshellcmd,但我不确定。

答案 5 :(得分:1)

您是否尝试使用echo exec(“dir”)或简单的东西来查看exec()是否正常工作?

答案 6 :(得分:1)

我不知道发生了什么,但我至少有一个解决方法。

这有效:

$tmp = tempnam("./", "wbsn");
$filename = dirname($tmp).'\\temp\\'.basename($tmp);

然而,这不是,但我希望它生成相同的路径(diff文件名,因为它是一个新的tempnam())。

$tmp = tempnam("temp", "wbsn");

此外,这不起作用,我也希望产生相同的东西:

$tmp = tempnam("temp", "wbsn");
$filename = dirname($tmp).'\\'.basename($tmp);

所有这三个解决方案出现以生成相同的文件路径,但只有第一个在我的exec中使用时实际工作。我有没有线索为什么它没有。

所有这3个中的视觉检查(回声)似乎生成相同的路径(当然,文件名不同)。这三个中每个的dirname()的字符串比较显示为匹配。我不知道这笔交易是什么,但第一个是解决方法。

答案 7 :(得分:1)

调试shell exec问题时,一个非常有用的技巧是在命令的开头放置一个“echo”。确保您可以在某处查看标准输出。

这将让您检查命令是否有任何明显的问题。也许它有一个意外扩展的通配符,或者shell引用可能不完全正确。 echo会让你看到这个,你可以将echoed命令剪切并粘贴到另一个shell中,看看它是否正常工作。

答案 8 :(得分:0)

我的建议是从WIN,IIS切换到linux,但作为替代方案,你可以试试这个:

function exec_alt($cmd) {
    exec($cmd, $output);
    if (!$output) {
        /**
         * FIXME: for some reason exec() returns empty output array @mine,'s machine.
         *        Somehow proc_open() approach (below) works, but doesn't work at
         *        test machines - same empty output with both pipes and temporary
         *        files (not we bypass shell wrapper). So use it as a fallback.
         */
        $output = array();
        $handle = proc_open($cmd, array(1 => array('pipe', 'w')), $pipes, null, null, array('bypass_shell' => true));
        if (is_resource($handle)) {
            $output = explode("\n", stream_get_contents($pipes[1]));
            fclose($pipes[1]);
            proc_close($handle);
        }
    }
    return $output; }