Я пишу обертку для mysqldump
и хочу показать результат красиво в приложении CLI PHP.
Я пытаюсь бежать mysqldump -v
с помощью popen
так что я могу получить подробный вывод и отобразить индикаторы прогресса для пользователя. Однако вывод не возвращается (по умолчанию он регистрируется на экране через stdErr
).
Я пытался добавить 2>&1
к команде, чтобы нажать подробный вывод из stdErr
в stdOut
, но fread
до сих пор не получает никакого вывода, хотя выходной Nolonger идет на экран через stdErr
,
$cmd = "mysqldump -uroot -proot -v dbname 2>&1 | mysql -uroot -proot dbname2";
$handle = popen($cmd, "r");
$buffer = "";
while ($handle && !feof($handle)){
$output = fread($handle, 100);
$buffer .= $output;
echo sprintf("Buffer: %s\n", $buffer);
}
pclose($handle);
Должен ли я использовать что-то другое вместо popen
? Или я просто неправильно перенаправляю вывод?
Вы, кажется, на самом деле передаете данные mysqldump в mysql, и в этом случае может быть плохой идеей включать сообщения об ошибках в канал.
Конечно, в этом сценарии вы не можете захватить вывод mysqldump.
Вы должны использовать tee
команда:
mysqldump -uroot -proot -v dbname | tee /tmp/output | mysql -uroot -proot dbname2
Таким образом, вы можете получить как в трубе для MySQL и /tmp/output
,
Таким образом, вы можете тогда fopen
/tmp/output
для результатов.
Обратите внимание, что у вас могут не быть возможных ошибок в выходных данных, так как mysql не будет рад видеть их позже.
Я понял это, не используя файл в качестве буфера потока.
/**
* PROCESS
*
* Process the command
*
* @param int $buffer The size of the buffer
* @param int $pipe The pipe to subscribe to (0=stdIn, 1=stdOut, 2=stdErr)
*
* @return bool Success or not
*/
public function process($buffer=10, $pipe=1) {
$handle = proc_open(
$this->command,
[
["pipe","r"],
["pipe","w"],
["pipe","w"]
],
$pipes
);
if (!is_resource($handle)) {
return false;
}
$output = "";
$buffer = "";
$hasLineCallbacks = count($this->onNewLine);
while ($buffer = fread($pipes[$pipe], 10)) {
$output .= $buffer;
if (preg_match("/[\r\n]/", $output)) {
$segments = preg_split("/[\r\n]+/", $output);
while (count($segments) > 1) {
$line = array_shift($segments);
if (!$hasLineCallbacks) { continue; }
foreach ($this->onNewLine as $callback) {
if (!$callback["pattern"] || preg_match($callback["pattern"], $line)) {
call_user_func($callback["callback"], $line);
}
}
}
$output = array_shift($segments);
}
}
proc_close($handle);
return true;
}
Я в основном делаю Background
класс для запуска команды терминала и передачи вывода в функции обратного вызова. Это, очевидно, еще предстоит пройти долгий путь.
Спасибо за вашу помощь, @Victor