PHPしか使えないような*1レンタルサーバ上で、HTTP GET/POST/HEAD 等の応答をダウンロードしつつ、逐次処理(典型的にはプログレスバー表示)できたら、それなりに使い道があるかも? と思って、試作してみた。
※ 説明はこちら
Asyncだの非同期だのといいつつ、どこが? って感じだけれど……他の名前も特に思いつかなかったのでそのまま。
仕組み
単に、proc_open()で子プロセスを起動し、親→子にPIPE経由で指示を送り、子プロセスで cURL によりコンテンツをダウンロード&子→親にPIPE経由で結果を送信、という処理を行っているだけ。
ユーザーは、子→親用のPIPEのファイルポインタリソースを取得し(init()の第3引数、もしくはget_contents_pointer())、fread() 等を使って一定サイズずつ読み込むようにすれば、逐次処理を実行できる。
落ち
と、せっかく作ってみたものの……お名前.comのレンタルサーバ上では使えなかった(哀)。どこがいけないのかなぁ?
さくらインターネットとかXREA.COM、ファーストサーバなんかのレンタルサーバ上ではとりあえず動いたのだが……。
追記(2014/12/13)
お名前.comのレンタルサーバでも動作するようになった。
ポイントは、
- PHPのCLI版の位置(/usr/local/bin/php.cliなので、async_curl_options.phpの$PHP_CLIを書き換える必要あり)
- CLI版バージョンがPHP 5.2.12 (cli) (built: Feb 23 2010 12:46:49)*2であるため、array_replace() が使えない。
- php://fd/* 形式のストリームもオープンできない模様。
2014/12/13時点での情報
追記(2014/12/15)
さくらインターネットのレンタルサーバにおいても、php://fd/* 形式のストリームをオープンできないことがある模様。
- CLI版の実行時には親/子共にphp://fd/*をオープン可能。
- CGI版(Webからのアクセス)の場合、子プロセスは php://fd/* がオープン可能だが、親プロセスでは不可。
結局、転送結果の取得用にはphp://fd/3 は使用せず、STDERRで代用するよう修正。
追記(2014/12/21)
子プロセスにおいてphp://fd/* 形式のストリームがオープン可能かどうかのチェック方法を見直し、可能な場合はchild→parentの制御用チャネルとしてphp://fd/3を使用するように修正。
制御用チャネルはTLV形式データ専用で、ノイズ(エラーメッセージ)が混じる可能性のあるSTDERRはなるべく避けたかったので。