user15063
user15063

Reputation:

How to set timeout for a ssh command executed with php?

I use php to execute scp commands via ssh via a wrapper function. The moves are between local and remote servers.

I roughly know how long the script should execute for, and I would like to kill the scp process if its taking too long (due to a destination server getting bogged down, or other network issues). When this happens currently, the scp processes get locked up completely until the destination server is restarted or the scp processes are killed manually from command line.

Can I pass some kind of timeout into shell_exec() that will quit the work its doing and proceed with the script execution?

Upvotes: 3

Views: 6001

Answers (5)

neubert
neubert

Reputation: 16802

You can do this with phpseclib by doing the following:

<?php
include('Net/SSH2.php');

$ssh = new Net_SSH2('www.domain.tld');
if (!$ssh->login('username', 'password')) {
    exit('Login Failed');
}

$ssh->setTimeout(5);
echo $ssh->read();
//$ssh->write('whatever');
?>

Upvotes: 2

sleetdrop
sleetdrop

Reputation: 465

or you can use select to waiting for the command to return. here is a example of code copied from php manual you can refer to proc_open() and stream_select()

<?php
$descriptorspec = array(
   0 => array("pipe", "r"),  
   1 => array("pipe", "w"),
   2 => array("file", "/tmp/error-output.txt", "a")
);

$pipes = array();
$process = proc_open('sleep 5 && echo hello', $descriptorspec, $pipes);
$timer = 0;
if (is_resource($process)) {
    while(true) {
        $write = null;
        $except = null;
        $read = array($pipes[1]);
        $ret = stream_select($read, $write, $except, 1);
        if ($ret === false) {
            echo "error";
            break;
        } else if ($ret == 0) {
            echo "waiting for " . ++$timer . "sec" . PHP_EOL;       
        } else {
            echo stream_get_contents($pipes[1]);
            break;
        }
    }
    fclose($pipes[1]);
    $return_value = proc_close($process);
    echo "command returned $return_value\n";
}

?>

Upvotes: 0

romaninsh
romaninsh

Reputation: 10664

You can use PHP sockets with timeout:

$process = proc_open($command,$descriptorspec,$pipes);
stream_set_timeout($pipes[1], 30);
$line=stream_get_contents($pipes[1]);    // read data
while($line)stream_get_contents($pipes[1]);
fclose($pipes[1]);

Upvotes: 0

nickb
nickb

Reputation: 59709

Wrap your command with the UNIX timeout utility.

system('timeout n ../my/aa');
                ^

Where n is some integer value in seconds.

If the command times out, then exit with status 124. Otherwise, exit with the status of COMMAND. If no signal is specified, send the TERM signal upon timeout. The TERM signal kills any process that does not block or catch that signal. For other processes, it may be necessary to use the KILL (9) signal, since this signal cannot be caught.

Upvotes: 6

Harald Brinkhof
Harald Brinkhof

Reputation: 4455

you could write a shell script that you invoke with shell_exec that autokills after a certain time, which you then invoke instead of scp directly, a script like this would take arguments or have them hardcoded. Here is an example of a script that takes 2 arguments, 2 second one the number of seconds it waits before killing the process. (sleep also accepts minutes, ours or days, just append m, h or d)

 #!/bin/sh
 scp $1 &
 pid=$!
 sleep $2
 kill $pid

edit: or use nickb's solution, that's even nicer. :)

Upvotes: 0

Related Questions