PHP 执行命令后脚本挂起

PHP script hangs after exec command

我是 PHP 和 phpseclib implementation of SSH 的新手。

我有以下代码:

$ssh = new Net_SSH2($_SESSION['targetAddress']);
if (!$ssh->login(SSH_USER, SSH_PASSWORD)) {
    exit('Login Failed');
} 

$ssh->setTimeout(400);
$a = 0;

while(isset($file[$a])) {
    $ssh->exec('cd '.$_SESSION['path'].'; find -L '.$file[$a].' > /tmp/ligacoes; for i in `cat /tmp/ligacoes`; do cp $i /var/tmp/; done');
    $a++;
}

我在这里试图完成的是将用户在远程服务器上选择的文件复制到同一服务器上的新目录中。执行脚本时,它成功找到第一个文件并将其复制到新目录,但之后脚本就停止了。即使用户只选择一项,脚本也会挂起并且不会继续。它甚至不增加 $a

对可能发生的事情有什么想法吗?

更新:

Real Time NET_SSH2 Log

我也 运行 直接在服务器中使用该命令,它运行良好。我想这个问题仅限于 $ssh->exec();

更新 2:

我将 $ssh->exec('cd '.$_SESSION['path'].'; find -L '.$file[$a].' > /tmp/ligacoes; for i in 'cat /tmp/ligacoes'; do cp $i /var/tmp/; done'); 更改为 $ssh->exec('cd '.$_SESSION['path'].'; cp '.$file[$a].' /var/tmp;');,这解决了部分问题。现在我可以将一个选定的文件复制到一个新目录并且脚本不会挂起。选择两个或多个文件时,问题一直在发生。

可能有帮助的事情:

  1. $ssh->execstdoutstderr 相呼应。检查那些。
  2. 试试 echo $ssh->exec('echo hello');
  3. 首先手动连接以确保 "The authenticity of host...Are you sure you want to continue connecting?" 已被接受。
  4. 确定 **手动检查您的每个命令以确保它们在通过您的脚本进行管道传输之前有效。
  5. 一个示例 的命令放入 bash 文件中,并尝试仅执行 bash 文件。如果可行,您可以通过 exec() 将变量发送到 bash 文件进行处理。类似于:

mybash.sh

cd /example/path/; 
find -L example_file > /tmp/ligacoes;
for i in `cat /tmp/ligacoes`;
do cp $i /var/tmp/;
done

并在您的 php

$ssh->exec('mybash.sh');

如果可行,那么您可以扩展它以发送变量

cd ; 
find -L  > /tmp/ligacoes;
for i in `cat /tmp/ligacoes`;
do cp $i /var/tmp/;
done

这样调用它,其中 $_SESSION['path'] 将是 </code>:</p> <pre><code>$ssh->exec('mybash.sh '.$_SESSION['path'].' '.$file[$a]);

超时的工作原理如下 w.r.t。执行()。

所以 exec() 方法的第一行是这样的:

$this->curTimeout = $this->timeout;

稍后有一个 while (true) 循环,其中包含这一行:

$temp = $this->_get_channel_packet(self::CHANNEL_EXEC);

_get_channel_packet 也有一个 while (true) 循环。它循环直到它超时或直到它在适当的通道上接收到数据。这是超时代码:

        if ($this->curTimeout) {
            if ($this->curTimeout < 0) {
                $this->is_timeout = true;
                return true;
            }
            $read = array($this->fsock);
            $write = $except = null;
            $start = microtime(true);
            $sec = floor($this->curTimeout);
            $usec = 1000000 * ($this->curTimeout - $sec);
            // on windows this returns a "Warning: Invalid CRT parameters detected" error
            if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
                $this->is_timeout = true;
                return true;
            }
            $elapsed = microtime(true) - $start;
            $this->curTimeout-= $elapsed;
        }

stream_select 阻塞,直到数据可供读取。根据 SSH 服务器的行为,它很可能会阻塞 400 秒。谁知道呢...也许在您的系统上 stream_select 会在达到 400 秒之前崩溃。

也就是说,该函数启用了错误抑制,如 stream_select 调用上方的注释中所述。您可以删除可能提供一些见解的错误抑制。

此外,请记住,超时只是跟踪数据可用所需的时间。例如,解密所花费的时间不计入超时。

例如...

$ssh->write("cat /dev/urandom\n");

$ssh->setTimeout(10);
$start = microtime(true);
echo $ssh->exec('ping google.com');
$elapsed = microtime(true) - $start;

echo "took $elapsed seconds\n";

我这样做了,$ssh->exec() 花了 20 秒(尽管超时)。如果我注释掉 $ssh->write() 需要 10 秒。 cat /dev/urandom\n 正在淹没客户端。您可以通过实时日志记录更清楚地看到这一点 (define('NET_SSH2_LOGGING', 3);)。问题是瓶颈不是花在阻塞上的时间,而是花在接收数据/解密数据上的时间。