source: trunk/www.guidonia.net/wp/wp-content/plugins/ferdinand-wordbook/fbcurl.php@ 44

Last change on this file since 44 was 44, checked in by luciano, 14 years ago
File size: 12.9 KB
Line 
1<?php
2/**
3 * @author Dick Munroe (munroe@csworks.com)
4 * @copyright copyright @ 2004-2007, Dick Munroe, released under the GPL.
5 * @license http://www.csworks.com/publications/ModifiedNetBSD.html
6 * @version 1.2.0
7 * @package cURL
8 *
9 * The cURL class is a thin wrapper around the procedural interface
10 * to cURL provided by PHP. I use it mostly as a base class for
11 * web services whose low level interface is, literally, web pages.
12 *
13 * There are a few differences (value added, I guess) between the interface
14 * provided by this class and the procedural cURL interface. Most
15 * noticable are:
16 *
17 * 1. The curl::exec function (when returning data to the caller rather
18 * than simply outputing it) always parses the HTTP header and returns
19 * only the body portion of the reqeust. The header is available via
20 * the curl::getHeader method.
21 * 2. The status of the last curl::exec is always maintained. It is
22 * available via the curl::getStatus method. In addition to the information
23 * returned by curl_getinfo, that of curl_error and curl_errno is folded
24 * in as well.
25 *
26 * @example ./example.class.curl.php
27 */
28
29//
30// Edit History:
31//
32// Dick Munroe munroe@csworks.com 30-Nov-2004
33// Initial Version Created.
34//
35// Dick Munroe munroe@csworks.com 01-Dec-2004
36// Forgot to check for cURL actually being in this instance of PHP.
37//
38// Dick Munroe (munroe@csworks.com) 07-Apr-2006
39// Fix tab characters.
40// Add utility function to return post string.
41//
42// Richard W. Schlatter (richard@rth10260.info) 27-Apr-2006
43// Extend processing for headers when CURLOPT_FOLLOWLOCATION is also set.
44// Only the headers of the final page will be used to return parsed headers.
45// Add utility function to return array of all collected headers.
46//
47// Dick Munroe (munroe@csworks.com) 01-May-2006
48// asPostString doesn't need to be an object specific method.
49//
50// Dick Munroe (munroe@csworks.com) 02-May-2006
51// Not all versions of PHP allow returning of a reference to the result
52// of a function.
53//
54// Richard W. Schlatter (richard@rth10260.info) 03-May-2006
55// For consistency, return an empty array if there aren't any headers
56// to be parsed.
57//
58// Richard W. Schlatter (richard@rth10260.info) 05-Jun-2006
59// Don't parse headers in the event of an error when executing a cURL request.
60//
61// Dick Munroe (munroe@csworks.com) 17-Dec-2007 1.2.0
62// Add a function to parse post strings as this is frequently needed capability.
63
64class fbcurl
65{
66 /**
67 * The mapping to caseless header names.
68 *
69 * @access private
70 * @var array
71 */
72
73 var $m_caseless ;
74
75 /**
76 * The handle for the current curl session.
77 *
78 * @access private
79 * @var resource
80 */
81
82 var $m_handle ;
83
84 /**
85 * The parsed contents of the HTTP header if one happened in the
86 * message. All repeated elements appear as arrays.
87 *
88 * The headers are stored as an associative array, the key of which
89 * is the name of the header, e.g., Set-Cookie, and the values of which
90 * are the bodies of the header in the order in which they occurred.
91 *
92 * Some headers can be repeated in a single header, e.g., Set-Cookie and
93 * pragma, so each type of header has an array containing one or more
94 * headers of the same type.
95 *
96 * The names of the headers can, potentially, vary in spelling from
97 * server to server and client to client. No attempt to regulate this
98 * is made, i.e., the curl class does not force all headers to lower
99 * or upper class, but it DOES collect all headers of the same type
100 * under the spelling of the type of header used by the FIRST header
101 * of that type.
102 *
103 * For example, two headers:
104 *
105 * 1. Set-Cookie: ...
106 * 2. set-cookie: ...
107 *
108 * Would appear as $this->m_header['Set-Cookie'][0] and ...[1]
109 *
110 * @access private
111 * @var mixed
112 */
113
114 var $m_header ;
115
116 /**
117 * Current setting of the curl options.
118 *
119 * @access private
120 * @var mixed
121 */
122
123 var $m_options ;
124
125 /**
126 * Status information for the last executed http request. Includes the errno and error
127 * in addition to the information returned by curl_getinfo.
128 *
129 * The keys defined are those returned by curl_getinfo with two additional
130 * ones specified, 'error' which is the value of curl_error and 'errno' which
131 * is the value of curl_errno.
132 *
133 * @link http://www.php.net/curl_getinfo
134 * @link http://www.php.net/curl_errno
135 * @link http://www.php.net/curl_error
136 * @access private
137 * @var mixed
138 */
139
140 var $m_status ;
141
142 /**
143 * Collection of headers when curl follows redirections as per CURLOPTION_FOLLOWLOCATION.
144 * The collection includes the headers of the final page too.
145 *
146 * @access private
147 * @var array
148 */
149
150 var $m_followed ;
151
152 /**
153 * curl class constructor
154 *
155 * Initializes the curl class for it's default behavior:
156 * o no HTTP headers.
157 * o return the transfer as a string.
158 * o URL to access.
159 * By default, the curl class will simply read the URL provided
160 * in the constructor.
161 *
162 * @link http://www.php.net/curl_init
163 * @param string $theURL [optional] the URL to be accessed by this instance of the class.
164 */
165
166 function curl($theURL=null)
167 {
168 if (!function_exists('curl_init'))
169 {
170 trigger_error('PHP was not built with --with-curl, rebuild PHP to use the curl class.',
171 E_USER_ERROR) ;
172 }
173
174 $this->m_handle = curl_init() ;
175
176 $this->m_caseless = null ;
177 $this->m_header = null ;
178 $this->m_options = null ;
179 $this->m_status = null ;
180 $this->m_followed = null ;
181
182 if (!empty($theURL))
183 {
184 $this->setopt(CURLOPT_URL, $theURL) ;
185 }
186 $this->setopt(CURLOPT_HEADER, false) ;
187 $this->setopt(CURLOPT_RETURNTRANSFER, true) ;
188 }
189
190 /**
191 * Free the resources associated with the curl session.
192 *
193 * @link http://www.php.net/curl_close
194 */
195
196 function close()
197 {
198 curl_close($this->m_handle) ;
199 $this->m_handle = null ;
200 }
201
202 /**
203 * Execute the curl request and return the result.
204 *
205 * @link http://www.php.net/curl_exec
206 * @link http://www.php.net/curl_getinfo
207 * @link http://www.php.net/curl_errno
208 * @link http://www.php.net/curl_error
209 * @return string The contents of the page (or other interaction as defined by the
210 * settings of the various curl options).
211 */
212
213 function exec()
214 {
215 $theReturnValue = curl_exec($this->m_handle) ;
216
217 $this->m_status = curl_getinfo($this->m_handle) ;
218 $this->m_status['errno'] = curl_errno($this->m_handle) ;
219 $this->m_status['error'] = curl_error($this->m_handle) ;
220
221 //
222 // Collect headers espesically if CURLOPT_FOLLOWLOCATION set.
223 // Parse out the http header (from last one if any).
224 //
225
226 $this->m_header = null ;
227
228 //
229 // If there has been a curl error, just return a null string.
230 //
231
232 if ($this->m_status['errno'])
233 {
234 return '' ;
235 }
236
237 if ($this->getOption(CURLOPT_HEADER))
238 {
239
240 $this->m_followed = array() ;
241 $rv = $theReturnValue ;
242
243 while (count($this->m_followed) <= $this->m_status['redirect_count'])
244 {
245 $theArray = preg_split("/(\r\n){2,2}/", $rv, 2) ;
246
247 $this->m_followed[] = $theArray[0] ;
248
249 $rv = $theArray[1] ;
250 }
251
252 $this->parseHeader($theArray[0]) ;
253
254 return $theArray[1] ;
255 }
256 else
257 {
258 return $theReturnValue ;
259 }
260 }
261
262 /**
263 * Returns the parsed http header.
264 *
265 * @param string $theHeader [optional] the name of the header to be returned.
266 * The name of the header is case insensitive. If
267 * the header name is omitted the parsed header is
268 * returned. If the requested header doesn't exist
269 * false is returned.
270 * @returns mixed
271 */
272
273 function getHeader($theHeader=null)
274 {
275 //
276 // There can't be any headers to check if there weren't any headers
277 // returned (happens in the event of errors).
278 //
279
280 if (empty($this->m_header))
281 {
282 return false ;
283 }
284
285 if (empty($theHeader))
286 {
287 return $this->m_header ;
288 }
289 else
290 {
291 $theHeader = strtoupper($theHeader) ;
292 if (isset($this->m_caseless[$theHeader]))
293 {
294 return $this->m_header[$this->m_caseless[$theHeader]] ;
295 }
296 else
297 {
298 return false ;
299 }
300 }
301 }
302
303 /**
304 * Returns the current setting of the request option. If no
305 * option has been set, it return null.
306 *
307 * @param integer the requested CURLOPT.
308 * @returns mixed
309 */
310
311 function getOption($theOption)
312 {
313 if (isset($this->m_options[$theOption]))
314 {
315 return $this->m_options[$theOption] ;
316 }
317
318 return null ;
319 }
320
321 /**
322 * Did the last curl exec operation have an error?
323 *
324 * @return mixed The error message associated with the error if an error
325 * occurred, false otherwise.
326 */
327
328 function hasError()
329 {
330 if (isset($this->m_status['error']))
331 {
332 return (empty($this->m_status['error']) ? false : $this->m_status['error']) ;
333 }
334 else
335 {
336 return false ;
337 }
338 }
339
340 /**
341 * Parse an HTTP header.
342 *
343 * As a side effect it stores the parsed header in the
344 * m_header instance variable. The header is stored as
345 * an associative array and the case of the headers
346 * as provided by the server is preserved and all
347 * repeated headers (pragma, set-cookie, etc) are grouped
348 * with the first spelling for that header
349 * that is seen.
350 *
351 * All headers are stored as if they COULD be repeated, so
352 * the headers are really stored as an array of arrays.
353 *
354 * @param string $theHeader The HTTP data header.
355 */
356
357 function parseHeader($theHeader)
358 {
359 $this->m_caseless = array() ;
360
361 $theArray = preg_split("/(\r\n)+/", $theHeader) ;
362
363 //
364 // Ditch the HTTP status line.
365 //
366
367 if (preg_match('/^HTTP/', $theArray[0]))
368 {
369 $theArray = array_slice($theArray, 1) ;
370 }
371
372 foreach ($theArray as $theHeaderString)
373 {
374 $theHeaderStringArray = preg_split("/\s*:\s*/", $theHeaderString, 2) ;
375
376 $theCaselessTag = strtoupper($theHeaderStringArray[0]) ;
377
378 if (!isset($this->m_caseless[$theCaselessTag]))
379 {
380 $this->m_caseless[$theCaselessTag] = $theHeaderStringArray[0] ;
381 }
382
383 $this->m_header[$this->m_caseless[$theCaselessTag]][] = $theHeaderStringArray[1] ;
384 }
385 }
386
387 /**
388 * Return the status information of the last curl request.
389 *
390 * @param string $theField [optional] the particular portion
391 * of the status information desired.
392 * If omitted the array of status
393 * information is returned. If a non-existant
394 * status field is requested, false is returned.
395 * @returns mixed
396 */
397
398 function getStatus($theField=null)
399 {
400 if (empty($theField))
401 {
402 return $this->m_status ;
403 }
404 else
405 {
406 if (isset($this->m_status[$theField]))
407 {
408 return $this->m_status[$theField] ;
409 }
410 else
411 {
412 return false ;
413 }
414 }
415 }
416
417 /**
418 * Set a curl option.
419 *
420 * @link http://www.php.net/curl_setopt
421 * @param mixed $theOption One of the valid CURLOPT defines.
422 * @param mixed $theValue the value of the curl option.
423 */
424
425 function setopt($theOption, $theValue)
426 {
427 curl_setopt($this->m_handle, $theOption, $theValue) ;
428 $this->m_options[$theOption] = $theValue ;
429 }
430
431 /**
432 * @desc Post string as an array
433 * @param string by reference data to be written.
434 * @return array hash containing the post string as individual elements, urldecoded.
435 * @access public
436 */
437
438 function &fromPostString(&$thePostString)
439 {
440 $return = array() ;
441 $fields = explode('&', $thePostString) ;
442 foreach($fields as $aField)
443 {
444 $xxx = explode('=', $aField) ;
445 $return[$xxx[0]] = urldecode($xxx[1]) ;
446 }
447
448 return $return ;
449 }
450
451 /**
452 * Arrays are walked through using the key as a the name. Arrays
453 * of Arrays are emitted as repeated fields consistent with such things
454 * as checkboxes.
455 *
456 * @desc Return data as a post string.
457 * @param mixed by reference data to be written.
458 * @param string [optional] name of the datum.
459 * @access public
460 */
461
462 function &asPostString(&$theData, $theName = NULL)
463 {
464 $thePostString = '' ;
465 $thePrefix = $theName ;
466
467 if (is_array($theData))
468 {
469 foreach ($theData as $theKey => $theValue)
470 {
471 if ($thePrefix === NULL)
472 {
473 $thePostString .= '&' . fbcurl::asPostString($theValue, $theKey) ;
474 }
475 else
476 {
477 $thePostString .= '&' . fbcurl::asPostString($theValue, $thePrefix . '[' . $theKey . ']') ;
478 }
479 }
480 }
481 else
482 {
483 $thePostString .= '&' . urlencode((string)$thePrefix) . '=' . urlencode($theData) ;
484 }
485
486 $xxx =& substr($thePostString, 1) ;
487
488 return $xxx ;
489 }
490
491 /**
492 * Returns the followed headers lines, including the header of the retrieved page.
493 * Assumed preconditions: CURLOPT_HEADER and expected CURLOPT_FOLLOWLOCATION set.
494 * The content is returned as an array of headers of arrays of header lines.
495 *
496 * @param none.
497 * @returns mixed an empty array implies no headers.
498 * @access public
499 */
500
501 function getFollowedHeaders()
502 {
503 $theHeaders = array() ;
504 if ($this->m_followed)
505 {
506 foreach ( $this->m_followed as $aHeader )
507 {
508 $theHeaders[] = explode( "\r\n", $aHeader ) ;
509 } ;
510 return $theHeaders ;
511 }
512
513 return $theHeaders ;
514 }
515}
516?>
Note: See TracBrowser for help on using the repository browser.