壊れたメガネ

ホッチキスの達人の意識の高いブログ。

PHP のお勉強

お勉強といって、何かすごいことしたわけじゃないです。そういうのに憧れているのは確かですが。

PHP の CLI(Command Line Interface コマンドラインインターフェース)に --script-server っていうオプションを付け加えました。言われるまでもなくゴミです。このオプションは、「PHPのスクリプトエンジンをネットワークを通して提供する」というものです。こういえば聞こえはいいですがゴミはゴミです。

仕組みは単純で、よくネットワークプログラミングで 'Hello, World' 的に扱われるエコーサーバーが基本になっています。エコーサーバーとはクライアントからの接続を待ち、接続を受けクライアントから送信されてきた文字列をそのままクライアントにかえすプログラムのことです。
スクリプトサーバーは送られてきた文字列を PHP のスクリプトエンジンに渡して実行します。その結果の出力をクライアントに返します。サーバー部分のプログラムは「ふつうの Linux プログラミング」という参考書のコードを大体写経したものです。

PHP の出力をクライアントに返すために少しだけ工夫しました。
送信されてきたスクリプトに print() や var_dump() などがあった場合、この工夫を行う以前の動作では、スクリプトサーバーを起動した端末の標準出力にその出力が出てきます。
print() や var_dump() などは内部的に sapi モジュールにより提供された出力用の関数を用いているので、この関数をごにょればいいわけです。
この関数では出力に write(2) を用いており、その引数には端末の標準出力のファイルディスクリプタが渡されていました。というわけなのでこのファイルディスクリプタを、接続を受け付けたソケットのファイルディスクリプタと交換してあげれば出力先をすり替えることができます。実際には phpss_fileno というグローバル変数()を用意し、これに出力先のファイルディスクリプタを代入します。この変数にはデフォルトで標準出力が格納されています。
github: ore-php / sapi / cli / php_cli.c sapi_cli_single_write

extern int phpss_fileno = STDOUT_FILENO;

PHP_CLI_API size_t sapi_cli_single_write(const char *str, uint str_length TSRMLS_DC)
{
#ifdef PHP_WRITE_STDOUT
        long ret;
#else
        size_t ret;
#endif

        if (cli_shell_callbacks.cli_shell_write) {
                size_t shell_wrote;
                shell_wrote = cli_shell_callbacks.cli_shell_write(str, str_length TSRMLS_CC);
                if (shell_wrote > -1) {
                        return shell_wrote;
                }
        }

#ifdef PHP_WRITE_STDOUT
        do {
                ret = write(phpss_fileno, str, str_length);
        } while (ret <= 0 && errno == EAGAIN && sapi_cli_select(STDOUT_FILENO TSRMLS_CC));

        if (ret <= 0) {
                return 0;
        }

        return ret;
#else
        ret = fwrite(str, 1, MIN(str_length, 16384), stdout);
        return ret;
#endif
}


いろいろごちゃごちゃやった割にどうしようもないものが出来ました。
# 「どうしようもないものが出来ました」って言葉が妙だな。「なにも出来ませんでした」ってことだろ?
# スクリーンキャスト初めてやってみたけど、改めてキモいな。