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