PHP script hangs after exec command

时间:2016-12-09 12:43:58

标签: php bash ssh phpseclib

I'm new to PHP and the phpseclib implementation of SSH.

I have the following code :

$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++;
}

What I am trying to accomplish here is to copy files chosen by user on a remote server to a new directory on the same server. When executing the script, it successfully find and copy the first file to the new directory, but after that the script just stops. Even if the user choose just one item the script hangs and does not continue. It doesn't even increment $a

Any thoughts on what may be happening ?

UPDATE:

Real Time NET_SSH2 Log

I also ran the command directly in the server and it works perfectly. I guess the issue is limited to $ssh->exec();

UPDATE 2:

I changed my $ssh->exec('cd '.$_SESSION['path'].'; find -L '.$file[$a].' > /tmp/ligacoes; for i in 'cat /tmp/ligacoes'; do cp $i /var/tmp/; done'); to $ssh->exec('cd '.$_SESSION['path'].'; cp '.$file[$a].' /var/tmp;'); and that solved part of the problem. Now I am able to copy one selected file to a new directory and the script does not hang. The issue keeps happening when two or more files are selected.

2 个答案:

答案 0 :(得分:3)

可能会有所帮助的事情:

  1. $ssh->exec回复stdoutstderr。检查那些。
  2. 只试用echo $ssh->exec('echo hello');
  3. 首先手动连接以确保“主机的真实性......您确定要继续连接吗?”已被接受。
  4. 确定以手动检查每个命令,以确保它们在通过脚本进行管道之前能够正常工作。
  5. 将命令的示例放在bash文件中,并尝试仅执行bash文件。如果可行,您可以通过exec()将变量发送到bash文件进行处理。类似的东西:
  6. <强> 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 $1; 
    find -L $2 > /tmp/ligacoes;
    for i in `cat /tmp/ligacoes`;
    do cp $i /var/tmp/;
    done
    

    $_SESSION['path'] $1 $ssh->exec('mybash.sh '.$_SESSION['path'].' '.$file[$a]); 称为

    Decorator pattern

答案 1 :(得分:0)

这是超时工作的原因w.r.t. EXEC()。

因此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会在到达400s之前崩溃。

也就是说,对该功能启用了错误抑制,如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);)更清楚地看到这一点。问题在于瓶颈不是阻塞所花费的时间,而是接收数据/解密所花费的时间。