読者です 読者をやめる 読者になる 読者になる

めもりーあろけーと

技術的な話とか日常的な話とか。

PHPで対話シェルを自動化する話。

自動テストなどで、証明書作成をしたいと思って対話する機会があったので。 対話シェルを進めるにはシェルのexpectなどを使うのが一般らしいですが、どうも動かない…。 シェルとかよくわからないし、なんならいっそPHPで書けばいいじゃん!って思いました。 対話シェルはコマンドの標準入力に直接書き込めばいいので、PHPproc_openを使うことで実現できます。

下記はOpenSSLの例ですが、他の用途にも使えます。

<?php
system('openssl genrsa 2048 > server.key');
$desc = [["pipe", "r"], ["pipe", "w"], ["pipe", "w"]];
$handle = proc_open('openssl req -new -key server.key > server.csr', $desc, $pipe);
if (is_resource($handle)) {
    for($i=0;$i<9;$i++){
        fwrite($pipe[0], "\n");
    }
    echo stream_get_contents($pipe[1]);
    fclose($pipe[0]);
    fclose($pipe[1]);
    fclose($pipe[2]);
}
system('openssl x509 -days 3650 -req -signkey server.key < server.csr > server.crt');

PHP自体にはopenssl拡張(http://php.net/manual/ja/ref.openssl.php)があるので、それを使うのもアリです。 gistにも公開していますので、ぜひご活用ください。 gist.github.com

他には例えばyum(-yオプションを付けない場合)であれば、

<?php
$desc = [["pipe", "r"], ["pipe", "w"], ["pipe", "w"]];
$handle = proc_open('yum install hogehoge', $desc, $pipe);
if (is_resource($handle)) {
    fwrite($pipe[0], "y\n");
    echo stream_get_contents($pipe[1]);
    fclose($pipe[0]);
    fclose($pipe[1]);
    fclose($pipe[2]);
}

上記のような感じで可能です。非常に簡単です。

もうすこし応用として、y/nではなく、yes/noでインストールできるようにしてみましょう。

<?php
$desc = [["pipe", "r"], ["pipe", "w"], ["pipe", "w"]];
$handle = proc_open('yum install hogehoge', $desc, $pipe);
if (is_resource($handle)) {
    $read = trim(fread(STDIN, 1024));
    $command ='n';
    if ($read === 'yes') {
        $command = 'y';
    }
    fwrite($pipe[0], $command . "\n");
    echo stream_get_contents($pipe[1]);
    fclose($pipe[0]);
    fclose($pipe[1]);
    fclose($pipe[2]);
}

などなど。