Hi, all
这几天在搬一个老项目,于是又折腾一把蛋疼的PHP。
原来PHP调用shell脚本完成工作,觉得太分离了,那一堆shell脚本以后肯定没人
能想起来那奇怪的写法是怎么回事,于是决定把功能移植进PHP里。
大致的需求是调用/bin/bash,需要拿到返回值,标准输入与标准输出,有时需要
login模式。
原来在Python里干过类似的事情,用subprocess还是挺惬意的。
谁知PHP...
自带的几个都不怎么行,proc_open勉强可以用,不过不支持login,还得自己绕。
于是用pcntl自己刻了一个[1],求吐槽。
[1]:
https://gist.github.com/aleiphoenix/6d53a37474cc40b56c90
顺带把源代码稍上,不过感觉还是怪怪的,PHP里POSIX没有匿名管道,并发还得
自己刻
function subprocess($cmd, $login = FALSE, $cwd = './',
$shell = '/bin/bash', $pipespec = NULL) {
$pid = getmypid();
$inpipe = '/tmp/_php_inpipe' . $pid;
$outpipe = '/tmp/_php_outpipe' . $pid;
$errpipe = '/tmp/_php_errpipe' . $pid;
if ($pipespec) {
$inpipe = $pipespec['stdin'];
$outpipe = $pipespec['stdout'];
$errpipe = $pipespec['stderr'];
}
posix_mkfifo($inpipe, 0600);
posix_mkfifo($outpipe, 0600);
posix_mkfifo($errpipe, 0600);
$pid = pcntl_fork();
if ($pid) {
// parent
$ret = 0;
$out = fopen($outpipe, 'r');
$err = fopen($errpipe, 'r');
while (TRUE) {
$_ = pcntl_waitpid($pid, $status, WNOHANG);
if ($_ === 0) {
usleep(1000);
}
elseif (pcntl_wifexited($status)) {
$ret = pcntl_wexitstatus($status);
break;
}
else {
throw new RuntimeException();
};
}
$_stdout = '';
$_stderr = '';
while (!feof($out)) {
$_stdout .= fgets($out);
}
while (!feof($err)) {
$_stderr .= fgets($err);
}
fclose($out);
fclose($err);
unlink($inpipe);
unlink($outpipe);
unlink($errpipe);
$rv = array(
'ret' => $ret,
'stdout' => $_stdout,
'stderr' => $_stderr,
);
return $rv;
}
else {
if ($cwd) {
chdir($cwd);
}
$params = array('-c', "$cmd >${outpipe} 2>${errpipe}");
if ($login) {
array_unshift($params, '-l');
}
pcntl_exec($shell, $params);
}
}