風柳メモ

ソフトウェア・プログラミング関連の覚書が中心。

ダウンロードしつつ逐次処理できるcURL wrapperを試作

PHPしか使えないような*1レンタルサーバ上で、HTTP GET/POST/HEAD 等の応答をダウンロードしつつ、逐次処理(典型的にはプログレスバー表示)できたら、それなりに使い道があるかも? と思って、試作してみた。

AsyncCurl: ダウンロードしつつ逐次処理を行うための cURL(PHP) wrapper

※ 説明はこちら
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はなるべく避けたかったので。

*1:え、Perlなら大抵のところで使える?そんなものもあったかなぁ……(トオイメ)

*2:CGI版/usr/local/bin/phpを5.4.XXとか5.5.XXにしてあっても、CLI版は古いまま