web-dev-qa-db-ja.com

PHP)を使用したインタラクティブシェル

不思議なことに、PHPだけを使用して、インタラクティブなシェルを作成することは可能ですか。データベースやPythonなどで使用しているようなものを意味します。

もしそうなら、どのように?

はい、可能です。対話型であるためには、プログラムはstdinからのユーザー入力を待機して読み込むことができなければなりません。 PHPでは、ファイル記述子を _'php://stdin'_ に開くことにより、stdinから読み取ることができます。 別の質問への回答 から取得、これはインタラクティブユーザープロンプトの例ですPHP(もちろんコマンドラインから実行する場合):

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

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

もちろん、1文字ではなく全行の入力を取得するには、 fgets() ではなく fgetc() が必要です。 。プログラム/シェルの動作によっては、プログラム全体が1つの大きな連続ループとして構造化される場合があります。うまくいけば、それはあなたに始める方法のアイデアを与えるでしょう。 本当にファンシー(CLI疑似GUI)を取得したい場合は、 ncursesを使用 にすることができます。

39
Wiseguy

この質問が尋ねられ、答えられたので、より良い解決策がPHPに追加されました。最近のすべてのPHPバージョンでは、次のようにユーザー入力を簡単に取得できます。

$input = fgets(STDIN);
26
dotancohen

私があなたの質問を理解する方法では、PHPインタープリターをコマンドラインで実行して、入力したPHPコードを評価するようにします。I Pythonの機能を常に使用して、コードスニペットをテストします。この場合、探している答えは(コマンドラインから)実行することだと思います。

php -a

PHPがパスにあると仮定すると、これにより、私の場合と同様に、PHPインタープリターに移動します:

$ php -a
Interactive Shell

php > 

そこから、任意のPHP式の評価を開始し、結果を確認できます。

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

これを拡張したものです。 CLIとWebサーバーの両方でスクリプトを実行する場合に備えて、isCLI()チェックを追加しました。そうしないと、サーバーが私の関数を使用してループする可能性があります。このソリューションは、ユーザーにプロンプ​​トを表示し、入力を確認し、必要に応じてユーザーに固定入力を再プロンプトします。 I rtrim()入力。ユーザーがreturnを使用してエントリを送信すると、エントリに追加される可能性があるためです。検証は必要ありません。その場合は関数を渡さないでください。

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);
2
skibulk

PHPのみを使用してシェルを作成するのか、それともインタラクティブシェルでPHPコマンドを処理するのか)」という質問からは完全には明らかではありません。後者を想定します。その場合、1つの例は phpsh です。これは、Facebookで作成されたようですが、Pythonで記述されています。

1
Greg

質問者が2番目のオプションを望んでいないことは知っていますが、私と同じように2番目のオプションが必要な場合は、phpshに加えて、PHPにも 自分のシェル

ただ走れ php -a

1
TinyGrasshopper

PHPには組み込みのunix onlyfunction readline()があるので、これを正確に実行します。次のメモを残します。

readlineの結果を使用して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!";
_

出力例:

llsの結果

h"こんにちは"

q exit

_ctrl+c_終了します。

_ctrl+d_入力が空の場合、次のシーケンスに進みます。 "ありがとう"。 _$user_が定義されており、空です。エラーはありません。

_ctrl+d_入力あり:アクションなし。まだ入力を待っています。

_ctrl+m_続行して、_$user_の現在の入力を取得します。

_ctrl+j_続行して、_$user_の現在の入力を取得します。これは、_ctrl+m_と同じ動作です。

Return次のシーケンスに進みます"ありがとう"。 _$user_は空のままで、エラーは発生しません。

_ctrl+z_は、ループをキャンセルして一番上のループに移動するために使用できます。変数がこのスコープで定義されていない場合、_$user_は設定解除されます。

入力に応じて、_!empty_を使用して空の値を定義するか、より多くの外科的テストを行うことができます(readlineの応答は多くの文字になる可能性があります)。

_$user_は、まだ尋ねられていない場合は_!isset_でテストできます

ユーザー入力をオブジェクトに格納するための組み込みのreadline_add_history()もあり、値は名前で直接取得できます(コードをわかりやすくするために便利です)。

_readline_add_history($user);
print_r(readline_list_history());
print_r(readline_user());
_

本当に複雑なものを構築するのに非常に便利です!

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

1
NVRM

チェックアウト:

https://github.com/shaneharter/sheldon

始めるのはとても簡単です。これには、多くの基本的なコンソールI/O作業を実行するSymfony2およびZendFrameworkライブラリが含まれており、コマンドオブジェクト(正規表現ルートを使用)およびコンテキスト(不変の状態を保持)を中心に構築された高レベルの抽象化を提供します。

私が気に入っていることの1つは、アプリケーションを「すぐに使用できる」状態で、対話型シェルとして実行することも、コマンドラインから実行してコマンドを指定し、引数を渡すことができる標準スクリプトとして実行することもできます。終了すると、アプリケーションは終了します。

0
Shane H