96ee9de72cd4652ccb7b9c1f3e856a77beaa6ae4
[m6w6/ext-http] / docs / examples / tutorial.txt
1
2 A Beginners Tutorial
3 --------------------
4 $Revision$
5
6
7 - GET Queries
8
9 The HttpRequest class can be used to execute any HTTP request method.
10 The following example shows a simple GET request where a few query
11 parameters are supplied. Additionally potential cookies will be
12 read from and written to a file.
13
14 <?php
15 $r = new HttpRequest('http://www.google.com/search');
16
17 // store Googles cookies in a dedicated file
18 touch('google.txt');
19 $r->setOptions(
20 array( 'cookiestore' => 'google.txt',
21 )
22 );
23
24 $r->setQueryData(
25 array( 'q' => '+"pecl_http" -msg -cvs -list',
26 'hl' => 'de'
27 )
28 );
29
30 // HttpRequest::send() returns an HttpMessage object
31 // of type HttpMessage::RESPONSE or throws an exception
32 try {
33 print $r->send()->getBody();
34 } catch (HttpException $e) {
35 print $e;
36 }
37 ?>
38
39 - Multipart Posts
40
41 The following example shows an multipart POST request, with two form
42 fields and an image that's supposed to be uploaded to the server.
43 It's a bad habit as well as common practice to issue a redirect after
44 an received POST request, so we'll allow a redirect by enabling the
45 redirect option.
46
47 <?php
48 $r = new HttpRequest('http://dev.iworks.at/.print_request.php', HTTP_METH_POST);
49
50 // if redirects is set to true, a single redirect is allowed;
51 // one can set any reasonable count of allowed redirects
52 $r->setOptions(
53 array( 'cookies' => array('MyCookie' => 'has a value'),
54 'redirect' => true,
55 )
56 );
57
58 // common form data
59 $r->setPostFields(
60 array( 'name' => 'Mike',
61 'mail' => 'mike@php.net',
62 )
63 );
64 // add the file to post (form name, file name, file type)
65 $r->addPostFile('image', 'profile.jpg', 'image/jpeg');
66
67 try {
68 print $r->send()->getBody();
69 } catch (HttpException $e) {
70 print $e;
71 }
72 ?>
73
74 - Parallel Requests
75
76 It's possible to execute several HttpRequests in parallel with the
77 HttpRequestPool class. HttpRequests to send, do not need to perform
78 the same request method, but can only be attached to one HttpRequestPool
79 at the same time.
80
81 <?php
82 try {
83 $p = new HttpRequestPool;
84 // if you want to set _any_ options of the HttpRequest object,
85 // you need to do so *prior attaching* to the request pool!
86 $p->attach(new HttpRequest('http://pear.php.net', HTTP_METH_HEAD));
87 $p->attach(new HttpRequest('http://pecl.php.net', HTTP_METH_HEAD));
88 } catch (HttpException $e) {
89 print $e;
90 exit;
91 }
92
93 try {
94 $p->send();
95 // HttpRequestPool implements an iterator over attached HttpRequest objects
96 foreach ($p as $r) {
97 echo "Checking ", $r->getUrl(), " reported ", $r->getResponseCode(), "\n";
98 }
99 } catch (HttpException $e) {
100 print $e;
101 }
102 ?>
103
104 - Parallel Requests?
105
106 You can use a more advanced approach by using the protected interface of
107 the HttpRequestPool class. This allows you to perform some other tasks
108 while the requests are executed.
109
110 <?php
111 class Pool extends HttpRequestPool
112 {
113 public function __construct()
114 {
115 parent::__construct(
116 new HttpRequest('http://pear.php.net', HTTP_METH_HEAD),
117 new HttpRequest('http://pecl.php.net', HTTP_METH_HEAD)
118 );
119
120 // HttpRequestPool methods socketPerform() and socketSelect() are
121 // protected; one could use this approach to do something else
122 // while the requests are being executed
123 print "Executing requests";
124 for ($i = 0; $this->socketPerform(); $i++) {
125 $i % 10 or print ".";
126 if (!$this->socketSelect()) {
127 throw new HttpException("Socket error!");
128 }
129 }
130 print "\nDone!\n";
131 }
132 }
133
134 try {
135 foreach (new Pool as $r) {
136 echo "Checking ", $r->getUrl(), " reported ", $r->getResponseCode(), "\n";
137 }
138 } catch (HttpException $ex) {
139 print $e;
140 }
141 ?>
142
143 - Cached Responses
144
145 One of the main key features of HttpResponse is HTTP caching. HttpResponse
146 will calculate an ETag based on the http.etag_mode INI setting as well as
147 it will determine the last modification time of the sent entity. It uses
148 those two indicators to decide if the cache entry on the client side is
149 still valid and will emit an "304 Not Modified" response if applicable.
150
151 <?php
152 HttpResponse::setCacheControl('public');
153 HttpResponse::setCache(true);
154 HttpResponse::capture();
155
156 print "This will be cached until content changes!\n";
157 print "Note that this approach will only save the clients download time.\n";
158 ?>
159
160 - Bandwidth Throttling
161
162 HttpResponse supports a basic throttling mechanism, which is enabled by
163 setting a throttle delay and a buffer size. PHP will sleep the specified
164 amount of seconds after each sent chunk of specified bytes.
165
166 <?php
167 // send 5000 bytes every 0.2 seconds, i.e. max ~25kByte/s
168 HttpResponse::setThrottleDelay(0.2);
169 HttpResponse::setBufferSize(5000);
170 HttpResponse::setCache(true);
171 HttpResponse::setContentType('application/x-zip');
172 HttpResponse::setFile('../archive.zip');
173 HttpResponse::send();
174 ?>
175
176 Exemplar Use Cases
177 ------------------
178
179 - KISS XMLRPC Client
180
181 <?php
182 class XmlRpcClient
183 {
184 public $namespace;
185 protected $request;
186
187 public function __construct($url, $namespace = '')
188 {
189 $this->namespace = $namespace;
190 $this->request = new HttpRequest($url, HTTP_METH_POST);
191 $this->request->setContentType('text/xml');
192 }
193
194 public function setOptions($options = array())
195 {
196 return $this->request->setOptions($options);
197 }
198
199 public function addOptions($options)
200 {
201 return $this->request->addOptions($options);
202 }
203
204 public function __call($method, $params)
205 {
206 if ($this->namespace) {
207 $method = $this->namespace .'.'. $method;
208 }
209 $this->request->setRawPostData(xmlrpc_encode_request($method, $params));
210 $response = $this->request->send();
211 if ($response->getResponseCode() != 200) {
212 throw new Exception($response->getBody(), $response->getResponseCode());
213 }
214 return xmlrpc_decode($response->getBody(), 'utf-8');
215 }
216
217 public function getHistory()
218 {
219 return $this->request->getHistory();
220 }
221 }
222
223 ?>
224
225 - Simple Feed Aggregator
226
227 <?php
228 class FeedAggregator
229 {
230 public $directory;
231 protected $feeds = array();
232
233 public function __construct($directory = 'feeds')
234 {
235 $this->setDirectory($directory);
236 }
237
238 public function setDirectory($directory)
239 {
240 $this->directory = $directory;
241 foreach (glob($this->directory .'/*.xml') as $feed) {
242 $this->feeds[basename($feed, '.xml')] = filemtime($feed);
243 }
244 }
245
246 public function url2name($url)
247 {
248 return preg_replace('/[^\w\.-]+/', '_', $url);
249 }
250
251 public function hasFeed($url)
252 {
253 return isset($this->feeds[$this->url2name($url)]);
254 }
255
256 public function addFeed($url)
257 {
258 $r = $this->setupRequest($url);
259 $r->send();
260 $this->handleResponse($r);
261 }
262
263 public function addFeeds($urls)
264 {
265 $pool = new HttpRequestPool;
266 foreach ($urls as $url) {
267 $pool->attach($r = $this->setupRequest($url));
268 }
269 $pool->send();
270
271 foreach ($pool as $request) {
272 $this->handleResponse($request);
273 }
274 }
275
276 public function getFeed($url)
277 {
278 $this->addFeed($url);
279 return $this->loadFeed($this->url2name($url));
280 }
281
282 public function getFeeds($urls)
283 {
284 $feeds = array();
285 $this->addFeeds($urls);
286 foreach ($urls as $url) {
287 $feeds[] = $this->loadFeed($this->url2name($url));
288 }
289 return $feeds;
290 }
291
292 protected function saveFeed($file, $contents)
293 {
294 if (file_put_contents($this->directory .'/'. $file .'.xml', $contents)) {
295 $this->feeds[$file] = time();
296 } else {
297 throw new Exception("Could not save feed contents to $file.xml");
298 }
299 }
300
301 protected function loadFeed($file)
302 {
303 if (isset($this->feeds[$file])) {
304 if ($data = file_get_contents($this->directory .'/'. $file .'.xml')) {
305 return $data;
306 } else {
307 throw new Exception("Could not load feed contents from $file.xml");
308 }
309 } else {
310 throw new Exception("Unknown feed/file $file.xml");
311 }
312 }
313
314 protected function setupRequest($url)
315 {
316 $r = new HttpRequest($url);
317 $r->setOptions(array('redirect' => true));
318
319 $file = $this->url2name($url);
320
321 if (isset($this->feeds[$file])) {
322 $r->setOptions(array('lastmodified' => $this->feeds[$file]));
323 }
324
325 return $r;
326 }
327
328 protected function handleResponse(HttpRequest $r)
329 {
330 if ($r->getResponseCode() != 304) {
331 if ($r->getResponseCode() != 200) {
332 throw new Exception("Unexpected response code ". $r->getResponseCode());
333 }
334 if (!strlen($body = $r->getResponseBody())) {
335 throw new Exception("Received empty feed from ". $r->getUrl());
336 }
337 $this->saveFeed($this->url2name($r->getUrl()), $body);
338 }
339 }
340 }
341 ?>
342
343