Using linux 'dialog' command from PHP

大兔子大兔子 提交于 2021-01-28 01:38:00

问题


I'm trying to write a helper script for doing various admin tasks on a server which can only be done from the command line and trying to use the 'dialog' command to display message boxes, inputs, password prompts etc, however, the needs of this task call for me to process the data in PHP.

I'm having problems getting the dialog command to work in this way and can't figure out what i'm doing wrong.

There's an example here

Unfortunately it doesn't work.

When you run PHP and exec/backtick/system to an external application, the IO doesn't appear to work how you'd expect.

The nearest I can get is using the passthru() command:

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

This is the only way that PHP will let dialog use the STDOUT properly, anything else results in no display but you can press return to select an option.

I've tried backticks, exec() and system() but nothing seems to work.

What I wondered was how to read STDERR properly from within PHP to get the return value into a variable called $result.

I'm sure some other sysadmins have had to do this before.

My reasons for not using bash for this are that one command I have to execute as a result of a selection produces XML output only and I can't parse that effectively in bash.


回答1:


I think you can't run ncurses application through PHP like this - maybe you should take a look at this: http://php.net/manual/de/book.ncurses.php




回答2:


Just in case someone else is searching for this:

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;
}

It requires dialog (apt-get install dialog) and proc_xxx (PHP 4.3.0, PHP 5)

It works, at least for me. :)




回答3:


You can use proc_open() but not as show above... All dialog boxes do not work in same way. I provides a concrete sample below:

#!/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:


You can use proc_open() to run a command and interact on all pipes, STDIN, STDOUT and 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]);

See the manual for more examples.




回答5:


PHP-GTK looks like a solution for this problem http://gtk.php.net/



来源:https://stackoverflow.com/questions/4711904/using-linux-dialog-command-from-php

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!