Observers
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 relevantContent-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'))
&& 0 == 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();
?>