繁体   English   中英

PHP @exec静默失败

[英]PHP @exec is failing silently

这真让我抓狂。 我正在尝试在我的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()默默地失败了。 我到底是做错了什么? 如果我硬编码文件路径,使用相同的目录结构和文件名,它工作正常。 如果我不这样做,那就没有。

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

更新:

我接过了执行官的@ off,但仍然没有看到任何错误。

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

更新2:RE:Kieth

我通过尝试两个来调用exec:

exec($cmd);

要么

exec($cmd, $out);

我的php.ini已经有safe_mode = 0。

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

如果我回复(或打印)我的执行电话,我实际上并没有做任何事情

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

更新3

我试过escapeshellcmd和escapeshellarg都没有用(虽然好主意)。

我应该补充说,该文件是通过调用创建的

tempnam("temp", "wbsn");

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

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

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

2>&1

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

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

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

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

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

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

error_reporting(E_ALL);

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

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

我不是添加另一个回复的忠实粉丝,但如果我只是编辑我之前的回复,你可能看不到它。

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

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

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

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

这有效:

$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()的字符串比较显示为匹配。 我不知道这笔交易是什么,但第一个是解决方法。

我的建议是从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; }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM