HTTP_Request_Listener – HTTP_Request 操作にリスナーをアタッチする

HTTP_Request_Listener は抽象クラスです。 これを継承すると、発生したイベントを受け取ってそれに対する応答を返すことができます。 HTTP_Request には、コンソールベースのプログレスバーのサンプルが含まれています。 これを実装するには、HTTP_Request_DownloadListener クラスを使用します。これは、 Console_ProgressBar パッケージを使用してダウンロードの進捗メーターを表示します。

リスナーを使用するには、確認したい特定の HTTP_Request あるいは HTTP_Response オブジェクトに対してリスナーをアタッチする必要があります。 アタッチするコードは、サンプルの一番最後にあります。 ごらんいただいてわかるとおり、HTTP_Request からその配下のすべての HTTP_Response オブジェクトに対してイベントリスナーが伝播します。 そして最初の HTTP_Request オブジェクトに対してのみアタッチが必要となります。

HTTP_Request_Listener を使用したダウンロード進捗バー


<?php
/**
 * HTTP_Request でのリスナーの使用例です。これは、ファイルの
 * ダウンロードと保存を行うと同時に、処理の進捗状況をバーで表示します
 * 
 * 注意すべき点は以下のとおりです
 * 1) ブラウザでなく、コンソールから実行しないといけません
 * 2) 出力バッファリングを OFF にしないと正常に動作しません
 */

require_once 'HTTP/Request.php';
require_once 
'HTTP/Request/Listener.php';
require_once 
'Console/ProgressBar.php';

PEAR::setErrorHandling(PEAR_ERROR_DIE);

set_time_limit(0);

class 
HTTP_Request_DownloadListener extends HTTP_Request_Listener
{
   
/**
    * 対象となるファイルのハンドル
    * @var int
    */
    
var $_fp;

   
/**
    * インジケータの表示に使用する Console_ProgressBar のインスタンス
    * @var object
    */
    
var $_bar;

   
/**
    * 対象となるファイルの名前
    * @var string
    */
    
var $_target;

   
/**
    * 受信したファイルのバイト数
    * @var int
    */
    
var $_size 0;

    function 
HTTP_Request_DownloadListener()
    {
        
$this->HTTP_Request_Listener();
    }

   
/**
    * 対象となるファイルをオープンする
    * @param string ファイル名
    * @throws PEAR_Error
    */
    
function setTarget($target)
    {
        
$this->_target $target;
        
$this->_fp = @fopen($target'wb');
        if (!
$this->_fp) {
            
PEAR::raiseError("'{$target}' をオープンできません");
        }
    }

    function 
update(&$subject$event$data null)
    {
        switch (
$event) {
            case 
'sentRequest'
                
$this->_target basename($subject->_url->path);
                break;

            case 
'gotHeaders':
                if (isset(
$data['content-disposition']) &&
                    
preg_match('/filename="([^"]+)"/'$data['content-disposition'], $matches)) {

                    
$this->setTarget(basename($matches[1]));
                } else {
                    
$this->setTarget($this->_target);
                }
                
$this->_bar =& new Console_ProgressBar(
                    
'* ' $this->_target ' %fraction% KB [%bar%] %percent%''=>''-'
                    
79, (isset($data['content-length'])? round($data['content-length'] / 1024): 100)
                );
                
$this->_size 0;
                break;

            case 
'tick':
                
$this->_size += strlen($data);
                
$this->_bar->update(round($this->_size 1024));
                
fwrite($this->_fp$data);
                break;

            case 
'gotBody':
                
fclose($this->_fp);
                break;

            default:
                
PEAR::raiseError("イベント '{$event}' が処理できません");
        } 
// switch
    
}
}

// 別のパッケージを使用してもかまいませんが、できるだけ大き目のものを
// 選ばないと進捗バーが見えません
$url 'http://pear.php.net/get/HTML_QuickForm-stable';

$req =& new HTTP_Request($url);

$download =& new HTTP_Request_DownloadListener();
$req->attach($download);
$req->sendRequest(false);
?>

HTTP_Request クラスはこれらのイベントを送信します。

  • connect - サーバと接続した際にこのイベントを送信します。

  • sentRequest - リクエストを送信した後でこのイベントを送信します。

  • disconnect - サーバとの接続を切断した後でこのイベントを送信します。

HTTP_Response クラスはこれらのイベントを送信します。

  • gotHeaders - レスポンスヘッダを受信したあとでこのイベントを送信します (ヘッダが連想配列として $data に渡されます)。

  • tick - レスポンス本文の一部を受信した際にこのイベントを送信します (受信した内容が文字列として $data に渡されます)。

  • gzTick - gzip 圧縮されたレスポンス本文の一部を受信した際にこのイベントを送信します (受信した内容が文字列として $data に渡されます)。

  • gotBody - レスポンス全体を受信し終えた後でこのイベントを送信します (gzip 圧縮されている場合、それをデコードした内容が文字列として $data に渡されます)。