Observers

Observers – Monitoring the request's progress

Overview

Observers are classes that can be attached to an instance of HTTP_Request2 and notified of request's progress. Possible uses:

  • Drawing a progress bar for large file uploads and / or downloads;
  • Saving large response body to disk instead of storing it in memory;
  • Cancelling the request by throwing an exception in Observer.

HTTP_Request2 implements SplSubject interface, so Observers should implement SplObserver. When Observer is notified of an event, it should use HTTP_Request2::getLastEvent() to access event details. That method returns an associative array with 'name' and 'data' keys. Possible event names are

'connect'
On connection to remote server, 'data' is the destination (string).
'disconnect'
On disconnection from server.
'sentHeaders'
On sending the request headers, 'data' is the headers sent (string).
'sentBodyPart'
On sending a part of the request body, 'data' is the length of that part (integer).
'sentBody' (since release 2.0.0beta1)
On sending the complete request body, 'data' is the length of request body (integer).
'receivedHeaders'
On receiving the response headers, 'data' is HTTP_Request2_Response object containing these headers.
'receivedBodyPart'
On receiving a part of the response body, 'data' is the received part (string).
'receivedEncodedBodyPart'
As 'receivedBodyPart', but 'data' is still encoded by relevant Content-Encoding.
'receivedBody'
On receiving the complete response body, data is HTTP_Request2_Response object, probably containing this body.

As the events are actually sent by request Adapters, you can receive fewer or different events if you switch to another Adapter. Curl Adapter does not notify of 'connect', 'disconnect' and 'receivedEncodedBodyPart' events (it always uses 'receivedBodyPart' as cURL extension takes care of decoding). Mock Adapter does not send any notifications at all.

Usage Example

The following example shows how an Observer can be used to save response body to disk without storing it in memory. Note that only events relevant to that task are handled in its update() method, the others can be safely ignored.

The package contains another Observer implementation: HTTP_Request2_Observer_Log class that allows logging request progress to a file or an instance of Log.

Saving response body to disk

<?php
class HTTP_Request2_Observer_Download implements SplObserver
{
    protected 
$dir;

    protected 
$fp;

    public function 
__construct($dir)
    {
        if (!
is_dir($dir)) {
            throw new 
Exception("'{$dir}' is not a directory");
        }
        
$this->dir $dir;
    }

    public function 
update(SplSubject $subject)
    {
        
$event $subject->getLastEvent();

        switch (
$event['name']) {
        case 
'receivedHeaders':
            if ((
$disposition $event['data']->getHeader('content-disposition'))
                && 
== strpos($disposition'attachment')
                && 
preg_match('/filename="([^"]+)"/'$disposition$m)
            ) {
                
$filename basename($m[1]);
            } else {
                
$filename basename($subject->getUrl()->getPath());
            }
            
$target $this->dir DIRECTORY_SEPARATOR $filename;
            if (!(
$this->fp = @fopen($target'wb'))) {
                throw new 
Exception("Cannot open target file '{$target}'");
            }
            break;

        case 
'receivedBodyPart':
        case 
'receivedEncodedBodyPart':
            
fwrite($this->fp$event['data']);
            break;

        case 
'receivedBody':
            
fclose($this->fp);
        }
    }
}

$request = new HTTP_Request2(
    
'http://pear.php.net/distributions/manual/pear_manual_en.tar.bz2',
    
HTTP_Request2::METHOD_GET, array('store_body' => false)
);
$request->attach(new HTTP_Request2_Observer_Download('.'));

// This won't output anything since body isn't stored in the response
echo $request->send()->getBody();
?>