Forum und email

Expect 関数

導入

この拡張モジュールは、PTY を経由したプロセス同士の対話機能を提供します。 ファイルシステム関数expect:// ラッパ を利用すれば、シンプルでより直感的なインターフェースが利用できるでしょう。

要件

このモジュールは » expect ライブラリの 関数を使用します。libexpect バージョン >= 5.43.0 が必要です。

インストール手順

この » PECL 拡張 モジュールは PHP にバンドルされていません。 この PECL 拡張モジュールをインストールする方法は、 マニュアルの PECL 拡張モジュールのインストール という章にあります。 新規リリース・ダウンロード・ソースファイル・管理者情報・CHANGELOG といった関連する情報については、次の場所にあります。 » https://pecl.php.net/package/expect.

PHP 4 の場合、この PECL 拡張モジュール のソースは、PHP のソースの ext/ ディレクトリ、または 上の PECL リンクで入手可能です。 これらの関数を使用するには、--with-expect[=DIR] オプションを使用して expect サポートつきで PHP をコンパイルする必要があります。

Windows ユーザは、これらの関数を使用するためには php.ini の中で php_expect.dll を有効にします。 PHP 4 の場合、この DLL は PHP の Windows ダウンロードバイナリの extensions/ ディレクトリ にあります。 この PECL 拡張モジュール用の DLL は、» PHP のダウンロード ページあるいは » https://pecl4win.php.net/ からダウンロードできます。

実行時設定

php.ini の設定により動作が変化します。

expect 拡張モジュールを設定するために、 設定ファイル php.ini に 設定項目が用意されています。

Expect 設定オプション
名前 デフォルト 変更可能 変更履歴
expect.timeout "10" PHP_INI_ALL  
expect.loguser "1" PHP_INI_ALL  
expect.logfile "" PHP_INI_ALL  
PHP_INI_* 定数の詳細および定義については php.ini ディレクティブ を参照してください。

以下に設定ディレクティブに関する 簡単な説明を示します。

expect.timeout integer

データを待ち受ける際のタイムアウト時間です。 expect_expectl() 関数で使用されます。

"-1" を指定すると、タイムアウトを発生させないようにします。

注意: "0" を指定すると、expect_expectl() 関数は 結果を直ちに返します。

expect.loguser boolean

expect が、子プロセスの出力を標準出力に送るかどうかを指定します。 典型的な対話型プログラムは入力した内容を表示するので、これを使用すれば 対話の両方の側を表示することができます。

expect.logfile string

子プロセスの出力内容が書き込まれるファイルの名前。もしファイルが 存在しない場合は新しく作成されます。

注意: この設置が空欄でなかった場合、 expect.loguser の設定内容に かかわらず出力が書き込まれます。

リソース型

expect_popen() は、オープンした PTY ストリームを返します。これを expect_expectl() で使用します。

定義済み定数

以下の定数が定義されています。 この関数の拡張モジュールが PHP 組み込みでコンパイルされているか、 実行時に動的にロードされている場合のみ使用可能です。

EXP_GLOB (integer)
パターンが、glob 形式の文字列パターンであることを示します。
EXP_EXACT (integer)
パターンが、単なる文字列であることを示します。
EXP_REGEXP (integer)
パターンが、正規表現形式の文字列パターンであることを示します。
EXP_EOF (integer)
EOF に到達した際に expect_expectl() が返す値です。
EXP_TIMEOUT (integer)
expect.timeout で指定した秒数を こえた際に expect_expectl() が返す値です。
EXP_FULLBUFFER (integer)
一致するパターンがなかった際に expect_expectl() が返す値です。

この例ではリモートホストに SSH 経由で接続し、接続先の稼働時間を表示します。

Example#1 Expect の使用例

<?php
ini_set 
("expect.loguser""Off");

$stream fopen ("expect://ssh root@remotehost uptime""r");

$cases = array (
  array (
=> "password:"=> PASSWORD)
);

switch (
expect_expectl ($stream$cases)) {
 case 
PASSWORD:
  
fwrite ($stream"password\n");
  break;
 
 default:
  die (
"リモートホストへの接続時にエラーが発生しました!\n");
}

while (
$line fgets ($stream)) {
  print 
$line;
}
fclose ($stream);
?>

次の例は、リモートホストに接続して インストールされている OS が 32 ビットか 64 ビットかを確認し、 それぞれのパッケージのアップデートを実行します。

Example#2 もうひとつの Expect の使用例

<?php
ini_set 
("expect.timeout", -1);
ini_set ("expect.loguser""Off");

$stream expect_popen ("ssh root@remotehost");

while (
true) {
    switch (
expect_expectl ($stream, array (
            array (
"password:"PASSWORD), // SSH がパスワードを問い合わせます
            
array ("yes/no)?"YESNO), // SSH がホストエントリを保存するかどうかを問い合わせます
            
array ("~$ "SHELLEXP_EXACT), // シェルにたどり着きました!
    
))) {
        case 
PASSWORD:
            
fwrite ($stream"secret\n");
            break;

        case 
YESNO:
            
fwrite ($stream"yes\n");
            break;

        case 
SHELL:
            
fwrite ($stream"uname -a\n");
            while (
true) {
                    switch (
expect_expectl ($stream, array (
                            array (
"~$ "SHELLEXP_EXACT), // シェルにたどり着きました!
                            
array ("^Linux.*$"UNAMEEXP_REGEXP), // uname -a の出力
                    
), $match)) {
                        case 
UNAME:
                            
$uname .= $match[0];
                            break;
                            
                        case 
SHELL:
                            
// アップデートの実行
                            
if (strstr ($uname"x86_64")) {
                                    
fwrite ($stream"rpm -Uhv https://mirrorsite/somepath/some_64bit.rpm\n");
                            } else {
                                    
fwrite ($stream"rpm -Uhv https://mirrorsite/somepath/some_32bit.rpm\n");
                            }
                            
fwrite ($stream"exit\n");
                            break 
2;
                        
                        case 
EXP_TIMEOUT:
                        case 
EXP_EOF:
                            break 
2;

                        default:
                            die (
"エラーが発生しました!\n");
                    }   
            }
            break 
2;

        case 
EXP_TIMEOUT:
        case 
EXP_EOF:
            break 
2;

        default:
            die (
"エラーが発生しました!\n");
    }
}

fclose ($stream);
?>

目次

  • expect_expectl — プロセスの出力がパターンに一致する・指定した時間が経過する・ あるいは EOF に達するのいずれかにあてはまるまで待ち続ける
  • expect_popen — Bourne シェル経由でコマンドを実行し、プロセスへの PTY ストリームをオープンする