3

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.

11
  • It is effective to just look at the output of $ssh->getLastError() (which returns a string) and $ssh->getErrors() (which returns an array). Post that output, if any, in your question. Commented Dec 9, 2016 at 12:53
  • This can be done using using PHP with less resource footprint. See: stackoverflow.com/questions/19139434/… Commented Dec 9, 2016 at 12:55
  • @WEBjuju There is no error output. Using $ssh->getLog(); the only log I got is connection successful. Commented Dec 9, 2016 at 13:09
  • @kitson88 the OP is trying to move files on a remote system Commented Dec 9, 2016 at 13:12
  • 1
    I'd say do what Murilo suggested and get the SSH2 logs. To enable logging you'll need to do define('NET_SSH2_LOGGING', 2); at the top of the file. Then do $ssh->getLog(). Copy / paste the output into a pastebin.com link and then add that link to your question. Commented Dec 9, 2016 at 16:30

2 Answers 2

3

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]);
Sign up to request clarification or add additional context in comments.

12 Comments

I created a bash file like you sugested. I am able to execute it but I get the same results: my PHP script stops. I get no output in echo $ssh->exec('grava1.sh');, even the first file being copied successfully.
Try just echo $ssh->exec('echo hello');
also be sure you have accepted the man-in-the-middle warning you get when you first connect via ssh (see my new #3 above)
OK, I get 'hello' when executing echo $ssh->exec('echo hello');. I connected manually and everything seems to be ready too.
@MuriloKomirchuk well it sounds like you are getting closer. take it one step at a time. next i might add that echo hello into the shell script. try fiddling with the permissions until it works (i suggest chmod 700 for starters).
|
0

Here's how timeout works w.r.t. 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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.