Interactive shell using PHP

2019-01-07 22:44发布

问题:

Just wondering, is it possible to create an interactive shell, using PHP alone. I mean something like you have with databases, python, etc.

If it is, how?

回答1:

Yes, it's possible. In order to be interactive, the program must be able to wait for and read in user input from stdin. In PHP, you can read from stdin by opening a file descriptor to 'php://stdin'. Taken from an answer to different question, here's an example of an interactive user prompt in PHP (when run from the command line, of course):

echo "Continue? (Y/N) - ";

$stdin = fopen('php://stdin', 'r');
$response = fgetc($stdin);
if ($response != 'Y') {
   echo "Aborted.\n";
   exit;
}

Of course, to get a full line of input rather than a single character, you'd need fgets() instead of fgetc(). Depending what your program/shell will do, the whole program might be structured as one big continuous loop. Hopefully that gives you an idea how to get started. If you wanted to get really fancy (CLI pseudo-GUI), you could use ncurses.



回答2:

Since this question has been asked and answered, a better solution has been added to PHP. In all recent PHP versions you can easily get user input as so:

$input = fgets(STDIN);


回答3:

The way I understand your question you just want the PHP interpreter to run on the command line so you that it will evaluate any PHP code that you type. I use that feature of Python all the time to test code snippets. In which case I believe the answer you are looking for is to execute (from the command line):

php -a

Assuming PHP is in your path this will drop you in to the PHP interpreter, like it does on mine:

$ php -a
Interactive shell

php > 

From there you can start to evaluate arbitrary PHP expressions and see the results:

php > $a = 'abcdef';
php > echo strlen($a);
6


回答4:

Here's an expanded take on this. I've added an isCLI() check in case you're run your script both in CLI and on a web server. Otherwise the server could loop using my function. This solution will prompt the user, check the input, and re-prompt the user for fixed input if necessary. I rtrim() the input because if the user uses return to submit their entry, that may be appended to the entry. Validation is not necessary, just don't pass a function in that case.

function isCLI() {
    return (php_sapi_name() === 'cli' OR defined('STDIN'));
}

function userPrompt($message, $validator=null) {
    if (!isCLI()) return null;

    print($message);
    $handle = fopen ('php://stdin','r');
    $line = rtrim(fgets($handle), "\r\n");

    if (is_callable($validator) && !call_user_func($validator, $line)) {
        print("Invalid Entry.\r\n");
        return userPrompt($message, $validator);
    } else {
        print("Continuing...\r\n");
        return $line;
    }
}

// Example =====================

function validateSetLangCode($str) {
    return preg_match("/^[A-Z0-9]{3}-[A-Z]{2}$/", $str);
}

$code = userPrompt("Please enter the set / language codes. Use the format 'SET-EN', where SET is the three-letter set code and EN is the two-letter lang code. \r\n", 'validateSetLangCode') ?: 'SET-EN';
var_dump($code);


回答5:

It is not entirely clear from the question whether you want to CREATE the shell using PHP alone, or whether you want the interactive shell to process PHP commands. I'm going to assume the latter, and in that case one example is phpsh which was apparently created at Facebook, but is written in python.



回答6:

I know the questioner didn't want the second option, but for those that wanted the second option as I did, in addition to phpsh, PHP also has it's own shell:

Just run php -a.



回答7:

Check out:

https://github.com/shaneharter/sheldon

It's pretty easy to get started. It includes Symfony2 and Zend Framework libraries that do a lot of the basic console I/O work and gives you a higher-level abstraction built around Command objects (with regex routes) and Contexts (which hold immutable state).

One of the things I love is that "out of the box" your application can run as either an interactive shell, or as a standard script that you can run from the command line, specify a command, pass any arguments, and when the command is finished the application exits.



回答8:

Since PHP has a built-in unix only function readline() to do exactly that, here leaving the following notes.

We can use and hold the result of readline into a var.

#!/usr/bin/php
<?php
$user = readline("List dir [l] | Say hello [h] | exit [q]: ");

if ($user === "l"){ system("ls"); }

if ($user === "h"){ echo "Hello!"; }

if ($user === "q"){ exit; }

echo "\nThanks!";

Example output:

l ls result

h «hello»

q exit

ctrl+c exit.

ctrl+d with empty input, continue to the next sequence. «Thanks». $user is defined and empty, no error.

ctrl+d with some input: No action. Still waiting for input.

ctrl+m Continue and take the current input in $user.

ctrl+j Continue and take the current input in $user, same behavior as ctrl+m.

Return continue to the next sequence «Thanks». $user can stay empty, no error.

ctrl+z may be used to cancel a loop and move to the top one. $user will be unset if the var is not defined in this scope.

Depending input, we can define empty values using!empty or do more surgical testings (the readline response can be many chars).

$user can be tested with !isset if not yet asked.

There is also the built-in readline_add_history() to store the user input into an object, where values can be retrieved directly by their name (Nice for code clarity):

readline_add_history($user);
print_r(readline_list_history());
print_r(readline_user());

Very useful to build real complex stuffs!

http://php.net/manual/en/function.readline.php