简体   繁体   中英

PHP script hangs after exec command

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.

Things that may help:

  1. $ssh->exec echos both stdout and stderr . Check those.
  2. Try just echo $ssh->exec('echo hello');
  3. Connect manually first to be sure the "The authenticity of host...Are you sure you want to continue connecting?" has been accepted.
  4. Be certain to **check each of your commands manually to be sure they work before piping them through your script.
  5. Put one example of your commands in a bash file and try to execute only the bash file. If that works, you may be able to send the variables via exec() to the bash file for processing. Something like:

mybash.sh

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

and in your php

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

If that works, then you can expand it to send variables

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

calling it like this where $_SESSION['path'] will be $1 :

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

Here's how timeout works wrt exec().

So the first line in the exec() method is this:

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

Later there's a while (true) loop that has in it this line:

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

_get_channel_packet has a while (true) loop as well. It loops until either it times out or until it receives data on the appropriate channel. Here's the timeout code:

        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 blocks until data is available to be read. Depending on the behavior of your SSH server it could very well block for 400s. And who knows... maybe on your system stream_select will crash before it gets to 400s.

That said, error suppression is enabled on that function, as noted in the comment above the stream_select call. You could remove the error suppression That might provide some insight.

Also, keep in mind that the timeout is only keeping track of how long it takes for data to be made available. The time it takes to decrypt, for example, does not count against the timeout.

For example...

$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";

I do that and $ssh->exec() takes 20s (despite the timeout). If I comment out the $ssh->write() it takes 10s. The cat /dev/urandom\\n is just flooding the client. You can see this more clearly with real time logging ( define('NET_SSH2_LOGGING', 3); ). The issue is that the bottleneck isn't the time spent blocking but the time spent receiving data / decrypting it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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