--- /dev/null
+
+A Beginners Tutorial
+--------------------
+$Revision$
+
+
+- GET Queries
+
+ The HttpRequest class can be used to execute any HTTP request method.
+ The following example shows a simple GET request where a few query
+ parameters are supplied. Additionally potential cookies will be
+ read from and written to a file.
+
+<?php
+$r = new HttpRequest('http://www.google.com');
+
+// store Googles cookies in a dedicated file
+$r->setOptions(
+ array( 'cookiestore' => '../cookies/google.txt',
+ )
+);
+
+$r->setQueryData(
+ array( 'q' => '+"pecl_http" -msg -cvs -list',
+ 'hl' => 'de'
+ )
+);
+
+// HttpRequest::send() returns an HttpMessage object
+// of type HttpMessage::RESPONSE or throws an exception
+try {
+ print $r->send()->getBody();
+} catch (HttpException $e) {
+ print $e;
+}
+?>
+
+- Multipart Posts
+
+ The following example shows an multipart POST request, with two form
+ fields and an image that's supposed to be uploaded to the server.
+ It's a bad habit as well as common practice to issue a redirect after
+ an received POST request, so we'll allow a redirect by enabling the
+ redirect option.
+
+<?php
+$r = new HttpRequest('http://dev.iworks.at/.print_request.php', HTTP_POST);
+
+// if redirects is set to true, a single redirect is allowed;
+// one can set any reasonable count of allowed redirects
+$r->setOptions(
+ array( 'cookies' => array('MyCookie' => 'has a value'),
+ 'redirect' => true,
+ )
+);
+
+// common form data
+$r->setPostFields(
+ array( 'name' => 'Mike',
+ 'mail' => 'mike@php.net',
+ )
+);
+// add the file to post (form name, file name, file type)
+$r->addPostFile('image', 'profile.jpg', 'image/jpeg');
+
+try {
+ print $r->send()->getBody();
+} catch (HttpException $e) {
+ print $e;
+}
+?>
+
+- Parallel Requests
+
+ It's possible to execute several HttpRequests in parallel with the
+ HttpRequestPool class. HttpRequests to send, do not need to perform
+ the same request method, but can only be attached to one HttpRequestPool
+ at the same time.
+
+<?php
+try {
+ $p = new HttpRequestPool;
+ // if you want to set _any_ options of the HttpRequest object,
+ // you need to do so *prior attaching* to the request pool!
+ $p->attach(new HttpRequest('http://pear.php.net', HTTP_HEAD));
+ $p->attach(new HttpRequest('http://pecl.php.net', HTTP_HEAD));
+} catch (HttpException $e) {
+ print $e;
+ exit;
+}
+
+try {
+ $p->send();
+ // HttpRequestPool implements an iterator over attached HttpRequest objects
+ foreach ($p as $r) {
+ print "Checking ", $r->getUrl(), " reported ", $r->getResponseCode(), "\n";
+ }
+} catch (HttpException $e) {
+ print $e;
+}
+?>
+
+- Parallel Requests?
+
+ You can use a more advanced approach by using the protected interface of
+ the HttpRequestPool class. This allows you to perform some other tasks
+ while the requests are executed.
+
+<?php
+class Pool extends HttpRequestPool
+{
+ public function __construct()
+ {
+ parent::__construct(
+ new HttpRequest('http://pear.php.net', HTTP_HEAD),
+ new HttpRequest('http://pecl.php.net', HTTP_HEAD)
+ );
+
+ // HttpRequestPool methods socketPerform() and socketSelect() are
+ // protected; one could use this approach to do something else
+ // while the requests are being executed
+ print "Executing requests";
+ for ($i = 0; $this->socketPerform(); $i++) {
+ $i % 3 or print ".";
+ if (!$this->socketSelect()) {
+ throw new HttpException("Socket error!");
+ }
+ }
+ print "\nDone!\n";
+ }
+}
+
+try {
+ foreach (new Pool as $r) {
+ print "Checking ", $r->getUrl(), " reported ", $r->getResponseCode(), "\n";
+ }
+} catch (HttpException $ex) {
+ print $e;
+}
+?>
+
+- Cached Responses
+
+ One of the main key features of HttpResponse is HTTP caching. HttpResponse
+ will calculate an ETag based on the http.etag_mode INI setting as well as
+ it will determine the last modification time of the sent entity. It uses
+ those two indicators to decide if the cache entry on the client side is
+ still valid and will emit an "304 Not Modified" response if applicable.
+
+<?php
+HttpResponse::setCacheControl('public');
+HttpResponse::setCache(true);
+HttpResponse::capture();
+
+print "This will be cached until content changes!\n";
+print "Note that this approach will only save the clients download time.\n";
+?>
+
+- Bandwidth Throttling
+
+ HttpResponse supports a basic throttling mechanism, which is enabled by
+ setting a throttle delay and a buffer size. PHP will sleep the specified
+ amount of seconds after each sent chunk of specified bytes.
+
+<?php
+// send 5000 bytes every 0.2 seconds, i.e. max ~25kByte/s
+HttpResponse::setThrottleDelay(0.2);
+HttpResponse::setBufferSize(5000);
+HttpResponse::setCache(true);
+HttpResponse::setContentType('application/x-zip');
+HttpResponse::setFile('../archive.zip');
+HttpResponse::send();
+?>
+
+Exemplar Use Cases
+------------------
+
+- KISS XMLRPC Client
+
+<?php
+class XmlRpcClient
+{
+ public $namespace;
+ protected $request;
+
+ public function __construct($url, $namespace = '')
+ {
+ $this->namespace = $namespace;
+ $this->request = new HttpRequest($url, HTTP_POST);
+ $this->request->setContentType('text/xml');
+ }
+
+ public function setOptions($options = array())
+ {
+ return $this->request->setOptions($options);
+ }
+
+ public function addOptions($options)
+ {
+ return $this->request->addOptions($options);
+ }
+
+ public function __call($method, $params)
+ {
+ if ($this->namespace) {
+ $method = $this->namespace .'.'. $method;
+ }
+ $this->request->setPostData(xmlrpc_encode_request($method, $params));
+ $response = $this->request->send();
+ if ($response->getResponseCode() != 200) {
+ throw new Exception($response->getBody(), $response->getResponseCode());
+ }
+ return xmlrpc_decode($response->getBody(), 'utf-8');
+ }
+
+ public function getHistory()
+ {
+ return $this->request->getHistory();
+ }
+}
+
+?>
+
+- Simple Feed Aggregator
+
+<?php
+class FeedAggregator
+{
+ public $directory;
+ protected $feeds = array();
+
+ public function __construct($directory = 'feeds')
+ {
+ $this->setDirectory($directory);
+ }
+
+ public function setDirectory($directory)
+ {
+ $this->directory = $directory;
+ foreach (glob($this->directory .'/*.xml') as $feed) {
+ $this->feeds[basename($feed, '.xml')] = filemtime($feed);
+ }
+ }
+
+ public function url2name($url)
+ {
+ return preg_replace('/[^\w\.-]+/', '_', $url);
+ }
+
+ public function hasFeed($url)
+ {
+ return isset($this->feeds[$this->url2name($url)]);
+ }
+
+ public function addFeed($url)
+ {
+ $r = $this->setupRequest($url);
+ $r->send();
+ $this->handleResponse($r);
+ }
+
+ public function addFeeds($urls)
+ {
+ $pool = new HttpRequestPool;
+ foreach ($urls as $url) {
+ $pool->attach($this->setupRequest($url));
+ }
+ $pool->send();
+
+ foreach ($pool as $request) {
+ $this->handleResponse($request);
+ }
+ }
+
+ public function getFeed($url)
+ {
+ $this->addFeed($url);
+ return $this->loadFeed($this->url2name($url));
+ }
+
+ public function getFeeds($urls)
+ {
+ $feeds = array();
+ $this->addFeeds($urls);
+ foreach ($urls as $url) {
+ $feeds[] = $this->loadFeed($this->url2name($url));
+ }
+ return $feeds;
+ }
+
+ protected function saveFeed($file, $contents)
+ {
+ if (file_put_contents($this->directory .'/'. $file .'.xml', $contents)) {
+ $this->feeds[$file] = time();
+ } else {
+ throw new Exception("Could not save feed contents to $file.xml");
+ }
+ }
+
+ protected function loadFeed($file)
+ {
+ if (isset($this->feeds[$file]) {
+ if ($data = file_get_contents($this->directory .'/'. $file .'.xml')) {
+ return $data;
+ } else {
+ throw new Exception("Could not load feed contents from $file.xml");
+ }
+ } else {
+ throw new Exception("Unknown feed/file $file.xml");
+ }
+ }
+
+ protected function setupRequest($url)
+ {
+ $r = new HttpRequest($url);
+ $r->setOptions(array('redirect' => true));
+
+ $file = $this->url2name($url);
+
+ if (isset($this->feeds[$file])) {
+ $r->addOptions(array('lastmodified' => $this->feeds[$file]));
+ }
+
+ return $r;
+ }
+
+ protected function handleResponse(HttpRequest $r)
+ {
+ if ($r->getResponseCode() != 304) {
+ if ($r->getResponseCode() != 200) {
+ throw new Exception("Unexpected response code ". $r->getResponseCode());
+ }
+ if (!strlen($body = $r->getResponseBody())) {
+ throw new Exception("Received empty feed from ". $r->getUrl());
+ }
+ $this->saveFeed($file, $body);
+ }
+ }
+}
+?>
+
+