I'm using the following command to open a temporary ssh tunnel for making a mysql connection:
exec('ssh -f -L 3400:127.0.0.1:3306 [email protected] sleep 1 > /dev/null');
$connection = @new \mysqli(127.0.0.1, $username, $password, $database, 3400);
This works splendidly. However, once in a while there may be another process using that port in which case it fails.
bind [127.0.0.1]:3400: Address already in use channel_setup_fwd_listener_tcpip: cannot listen to port: 3401 Could not request local forwarding.
What I'd like to do is capture the error output of exec() so that I can retry using a different port. If I add 2>&1 to my command the error output just goes nowhere since stdout is already being piped to /dev/null.
One solution I've come up with is to pipe output to a file instead of /dev/null:
exec('ssh -f -L 3400:127.0.0.1:3306 [email protected] sleep 1 >temp.log 2>&1');
$output = file_get_contents('temp.log');
This works, but it feels messy. I'd prefer not to use the filesystem just to get the error response. Is there a way to capture the error output of this command without piping it to a file?
UPDATE: For the sake of clarity:
(a) Capturing result code using the second argument of exec() does not work in this case. Don't ask me why - but it will always return 0 (success)
(b) stdout must be redirected somewhere or php will not treat it as a background process and script execution will stop until it completes. (https://www.php.net/manual/en/function.exec.php#refsect1-function.exec-notes)
If a program is started with this function, in order for it to continue running in the background, the output of the program must be redirected to a file or another output stream. Failing to do so will cause PHP to hang until the execution of the program ends.
execthe second argument should be the output (array). The third argument should be the result code. Another reason why you get0is, that you possibly currently capture the output fromsleep, not fromssh.tee. This may look likessh -f -L 3400:127.0.0.1:3306 [email protected] | tee temp.log. Also, instead of usingexec, you could simply pass your command into a variable with system()$command = system("ssh ..."), which return the LAST LINE only, on your case onlyCould not request local forwarding.. To just catch a switching state it can be enough. Lastly, if you intent to high load, and into a UNIX machine, use the system tools, you better have to run a separate script task and POSIX signals to fine control it, and it's just for ssh use a LIB