Использование команды linux 'dialog' из PHP - PullRequest
2 голосов
/ 17 января 2011

Я пытаюсь написать вспомогательный скрипт для выполнения различных административных задач на сервере, которые можно выполнить только из командной строки, и пытаюсь использовать команду 'dialog' для отображения окон сообщений, входных данных, запросов пароля и т. Д., Однако , потребности этой задачи требуют от меня обработки данных в PHP.

У меня проблемы с тем, чтобы заставить команду диалога работать таким образом, и я не могу понять, что я делаю неправильно.

Вот пример здесь

К сожалению, это не работает.

Когда вы запускаете PHP и exec / backtick / system для внешнего приложения, ввод-вывод не работает так, как вы ожидаете.

Ближайшее, что я могу получить, это использовать команду passthru ():

<?php
  $CMD = "dialog --menu \"Please select\" 10 40 3 backup \"Backup Files\" restore \"Restore Files\"";
  passthru($CMD);
?>

Это единственный способ, которым PHP позволяет диалогу правильно использовать STDOUT, все остальное не приводит к отображению, но вы можете нажать return, чтобы выбрать опцию.

Я пробовал обратные ссылки, exec () и system (), но, похоже, ничего не работает.

Что меня удивило, так это как правильно читать STDERR из PHP, чтобы получить возвращаемое значение в переменную с именем $ result.

Я уверен, что некоторым другим системным администраторам приходилось делать это раньше.

Мои причины для того, чтобы не использовать bash для этого, состоят в том, что одна команда, которую я должен выполнить в результате выбора, производит только вывод XML, и я не могу эффективно проанализировать это в bash.

Ответы [ 5 ]

4 голосов
/ 06 июля 2012

Вы можете использовать proc_open (), но не так, как показано выше ... Все диалоговые окна не работают одинаково. Я привожу конкретный образец ниже:

#!/usr/bin/env php
<?php

$pipes = array();
$process = null;
$output = '';
$ret = -1;

/**
 * Start process
 *
 * @param string $cmd Command to execute
 * @param bool $wantinputfd Whether or not input fd (pipe) is required
 * @retun void
 */
function processStart($cmd, $wantinputfd = false)
{
    global $process, $pipes;

    $process = proc_open(
        $cmd,
        array(
            0 => ($wantinputfd) ? array('pipe', 'r') : STDIN, // pipe/fd from which child will read
            1 => STDOUT,
            2 => array('pipe', 'w'), // pipe to which child will write any errors
            3 => array('pipe', 'w') // pipe to which child will write any output
        ),
        $pipes
    );
}

/**
 * Stop process
 *
 * @return void
 */
function processStop()
{
    global $output, $pipes, $process, $ret;

    if (isset($pipes[0]) {
        fclose($pipes[0]);
        usleep(2000);
    }

    $output = '';
    while ($_ = fgets($pipes[3])) {
        $output .= $_;
    }

    $errors = '';
    while ($_ = fgets($pipes[2])) {
        fwrite(STDERR, $_);
        $errors++;
    }

    if ($errors) {
        fwrite(STDERR, "dialog output the above errors, giving up!\n");
        exit(1);
    }

    fclose($pipes[2]);
    fclose($pipes[3]);

    do {
        usleep(2000);
        $status = proc_get_status($process);
    } while ($status['running']);

    proc_close($process);
    $ret = $status['exitcode'];
}

// Test for yesno dialog box
processStart("dialog --backtitle 'dialog test' --title 'Little test' --output-fd 3 --yesno 'yesno dialog box' 0 70");
processStop();
echo "Exit code is $ret\n";

// Test for gauge dialog box
processStart("dialog --backtitle 'dialog test' --title 'Little test' --output-fd 3 --gauge  'Gauge dialog box' 0 70 0", true);
sleep(1);
fwrite($pipes[0], "XXX\n0\nFirst step\nXXX\n20\n");
sleep(1);
fwrite($pipes[0], "XXX\n20\nSecond step\nXXX\n50\n");
sleep(1);
fwrite($pipes[0], "XXX\n50\nThird step\nXXX\n80\n");
sleep(1);
fwrite($pipes[0], "XXX\n80\nFourth step\nXXX\n100\n");
sleep(1);
processStop();
echo "Exit code is $ret\n";

// Test for input dialog box
processStart("dialog --backtitle 'dialog test' --title 'Little test' --output-fd 3 --inputbox 'input dialog box' 0 70");
processStop();
echo "Output is $output\n";
echo "Exit code is $ret\n";

// Test for errors output
processStart("dialog --backtitle 'dialog test' --title 'Little test' --output-fd 3 --dummy 'my input box' 0 70");
processStop();

exit(0);
4 голосов
/ 05 января 2012

На всякий случай, если кто-то ищет это:

function dialog ($args) {
    $pipes = array (NULL, NULL, NULL);
    // Allow user to interact with dialog
    $in = fopen ('php://stdin', 'r');
    $out = fopen ('php://stdout', 'w');
    // But tell PHP to redirect stderr so we can read it
    $p = proc_open ('dialog '.$args, array (
        0 => $in,
        1 => $out,
        2 => array ('pipe', 'w')
    ), $pipes);
    // Wait for and read result
    $result = stream_get_contents ($pipes[2]);
    // Close all handles
    fclose ($pipes[2]);
    fclose ($out);
    fclose ($in);
    proc_close ($p);
    // Return result
    return $result;
}

Требуется диалог (диалог установки apt-get) и proc_xxx (PHP 4.3.0, PHP 5)

Это работает, по крайней мере, для меня. :)

2 голосов
/ 17 января 2011

Вы можете использовать proc_open () для запуска команды и взаимодействия на всех каналах, STDIN, STDOUT и STDERR:

$pipes = array(NULL, NULL, NULL);
$proc = proc_open(
    "dialog --gauge ..",
    array(
        0 => array('pipe', 'r'),
        1 => array('pipe', 'w'),
        2 => array('pipe', 'w'),
    ),
    $pipes
);
print fgets($pipes[2]);

См. Руководство для дополнительных примеров.

1 голос
/ 17 января 2011

PHP-GTK выглядит как решение этой проблемы http://gtk.php.net/

0 голосов
/ 17 января 2011

Я думаю, что вы не можете запустить приложение ncurses через PHP следующим образом - возможно, вам стоит взглянуть на это: http://php.net/manual/de/book.ncurses.php

...