[ Index ]
 

Code source de DokuWiki 2006-11-06

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/inc/ -> HTTPClient.php (source)

   1  <?php
   2  /**
   3   * HTTP Client
   4   *
   5   * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
   6   * @author     Andreas Goetz <cpuidle@gmx.de>
   7   */
   8  
   9  if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/');
  10  require_once(DOKU_CONF.'dokuwiki.php');
  11  
  12  define('HTTP_NL',"\r\n");
  13  
  14  
  15  /**
  16   * Adds DokuWiki specific configs to the HTTP client
  17   *
  18   * @author Andreas Goetz <cpuidle@gmx.de>
  19   */
  20  class DokuHTTPClient extends HTTPClient {
  21  
  22      /**
  23       * Constructor.
  24       *
  25       * @author Andreas Gohr <andi@splitbrain.org>
  26       */
  27      function DokuHTTPClient(){
  28          global $conf;
  29  
  30          // call parent constructor
  31          $this->HTTPClient();
  32  
  33          // set some values from the config
  34          $this->proxy_host = $conf['proxy']['host'];
  35          $this->proxy_port = $conf['proxy']['port'];
  36          $this->proxy_user = $conf['proxy']['user'];
  37          $this->proxy_pass = $conf['proxy']['pass'];
  38          $this->proxy_ssl  = $conf['proxy']['ssl'];
  39      }
  40  }
  41  
  42  /**
  43   * This class implements a basic HTTP client
  44   *
  45   * It supports POST and GET, Proxy usage, basic authentication,
  46   * handles cookies and referers. It is based upon the httpclient
  47   * function from the VideoDB project.
  48   *
  49   * @link   http://www.splitbrain.org/go/videodb
  50   * @author Andreas Goetz <cpuidle@gmx.de>
  51   * @author Andreas Gohr <andi@splitbrain.org>
  52   */
  53  class HTTPClient {
  54      //set these if you like
  55      var $agent;         // User agent
  56      var $http;          // HTTP version defaults to 1.0
  57      var $timeout;       // read timeout (seconds)
  58      var $cookies;
  59      var $referer;
  60      var $max_redirect;
  61      var $max_bodysize;  // abort if the response body is bigger than this
  62      var $header_regexp; // if set this RE must match against the headers, else abort
  63      var $headers;
  64      var $debug;
  65  
  66      // don't set these, read on error
  67      var $error;
  68      var $redirect_count;
  69  
  70      // read these after a successful request
  71      var $resp_status;
  72      var $resp_body;
  73      var $resp_headers;
  74  
  75      // set these to do basic authentication
  76      var $user;
  77      var $pass;
  78  
  79      // set these if you need to use a proxy
  80      var $proxy_host;
  81      var $proxy_port;
  82      var $proxy_user;
  83      var $proxy_pass;
  84      var $proxy_ssl; //boolean set to true if your proxy needs SSL
  85  
  86      /**
  87       * Constructor.
  88       *
  89       * @author Andreas Gohr <andi@splitbrain.org>
  90       */
  91      function HTTPClient(){
  92          $this->agent        = 'Mozilla/4.0 (compatible; DokuWiki HTTP Client; '.PHP_OS.')';
  93          $this->timeout      = 15;
  94          $this->cookies      = array();
  95          $this->referer      = '';
  96          $this->max_redirect = 3;
  97          $this->redirect_count = 0;
  98          $this->status       = 0;
  99          $this->headers      = array();
 100          $this->http         = '1.0';
 101          $this->debug        = false;
 102          $this->max_bodysize = 0;
 103          $this->header_regexp= '';
 104          if(extension_loaded('zlib')) $this->headers['Accept-encoding'] = 'gzip';
 105          $this->headers['Accept'] = 'text/xml,application/xml,application/xhtml+xml,'.
 106                                     'text/html,text/plain,image/png,image/jpeg,image/gif,*/*';
 107          $this->headers['Accept-Language'] = 'en-us';
 108      }
 109  
 110  
 111      /**
 112       * Simple function to do a GET request
 113       *
 114       * Returns the wanted page or false on an error;
 115       *
 116       * @param  string $url       The URL to fetch
 117       * @param  bool   $sloppy304 Return body on 304 not modified
 118       * @author Andreas Gohr <andi@splitbrain.org>
 119       */
 120      function get($url,$sloppy304=false){
 121          if(!$this->sendRequest($url)) return false;
 122          if($this->status == 304 && $sloppy304) return $this->resp_body;
 123          if($this->status != 200) return false;
 124          return $this->resp_body;
 125      }
 126  
 127      /**
 128       * Simple function to do a POST request
 129       *
 130       * Returns the resulting page or false on an error;
 131       *
 132       * @author Andreas Gohr <andi@splitbrain.org>
 133       */
 134      function post($url,$data){
 135          if(!$this->sendRequest($url,$data,'POST')) return false;
 136          if($this->status != 200) return false;
 137          return $this->resp_body;
 138      }
 139  
 140      /**
 141       * Do an HTTP request
 142       *
 143       * @author Andreas Goetz <cpuidle@gmx.de>
 144       * @author Andreas Gohr <andi@splitbrain.org>
 145       */
 146      function sendRequest($url,$data=array(),$method='GET'){
 147          $this->error = '';
 148          $this->status = 0;
 149  
 150          // parse URL into bits
 151          $uri = parse_url($url);
 152          $server = $uri['host'];
 153          $path   = $uri['path'];
 154          if(empty($path)) $path = '/';
 155          if(!empty($uri['query'])) $path .= '?'.$uri['query'];
 156          $port = $uri['port'];
 157          if($uri['user']) $this->user = $uri['user'];
 158          if($uri['pass']) $this->pass = $uri['pass'];
 159  
 160          // proxy setup
 161          if($this->proxy_host){
 162              $request_url = $url;
 163              $server      = $this->proxy_host;
 164              $port        = $this->proxy_port;
 165              if (empty($port)) $port = 8080;
 166          }else{
 167              $request_url = $path;
 168              $server      = $server;
 169              if (empty($port)) $port = ($uri['scheme'] == 'https') ? 443 : 80;
 170          }
 171  
 172          // add SSL stream prefix if needed - needs SSL support in PHP
 173          if($port == 443 || $this->proxy_ssl) $server = 'ssl://'.$server;
 174  
 175          // prepare headers
 176          $headers               = $this->headers;
 177          $headers['Host']       = $uri['host'];
 178          $headers['User-Agent'] = $this->agent;
 179          $headers['Referer']    = $this->referer;
 180          $headers['Connection'] = 'Close';
 181          if($method == 'POST'){
 182              $post = $this->_postEncode($data);
 183              $headers['Content-Type']   = 'application/x-www-form-urlencoded';
 184              $headers['Content-Length'] = strlen($post);
 185          }
 186          if($this->user) {
 187              $headers['Authorization'] = 'BASIC '.base64_encode($this->user.':'.$this->pass);
 188          }
 189          if($this->proxy_user) {
 190              $headers['Proxy-Authorization'] = 'BASIC '.base64_encode($this->proxy_user.':'.$this->proxy_pass);
 191          }
 192  
 193          // stop time
 194          $start = time();
 195  
 196          // open socket
 197          $socket = @fsockopen($server,$port,$errno, $errstr, $this->timeout);
 198          if (!$socket){
 199              $resp->status = '-100';
 200              $this->error = "Could not connect to $server:$port\n$errstr ($errno)";
 201              return false;
 202          }
 203          //set non blocking
 204          stream_set_blocking($socket,0);
 205  
 206          // build request
 207          $request  = "$method $request_url HTTP/".$this->http.HTTP_NL;
 208          $request .= $this->_buildHeaders($headers);
 209          $request .= $this->_getCookies();
 210          $request .= HTTP_NL;
 211          $request .= $post;
 212  
 213          $this->_debug('request',$request);
 214  
 215          // send request
 216          fputs($socket, $request);
 217          // read headers from socket
 218          $r_headers = '';
 219          do{
 220              if(time()-$start > $this->timeout){
 221                  $this->status = -100;
 222                  $this->error = 'Timeout while reading headers';
 223                  return false;
 224              }
 225              if(feof($socket)){
 226                  $this->error = 'Premature End of File (socket)';
 227                  return false;
 228              }
 229              $r_headers .= fread($socket,1); #FIXME read full lines here?
 230          }while(!preg_match('/\r\n\r\n$/',$r_headers));
 231  
 232          $this->_debug('response headers',$r_headers);
 233  
 234          // check if expected body size exceeds allowance
 235          if($this->max_bodysize && preg_match('/\r\nContent-Length:\s*(\d+)\r\n/i',$r_headers,$match)){
 236              if($match[1] > $this->max_bodysize){
 237                  $this->error = 'Reported content length exceeds allowed response size';
 238                  return false;
 239              }
 240          }
 241  
 242          // get Status
 243          if (!preg_match('/^HTTP\/(\d\.\d)\s*(\d+).*?\n/', $r_headers, $m)) {
 244              $this->error = 'Server returned bad answer';
 245              return false;
 246          }
 247          $this->status = $m[2];
 248  
 249          // handle headers and cookies
 250          $this->resp_headers = $this->_parseHeaders($r_headers);
 251          if(isset($this->resp_headers['set-cookie'])){
 252              foreach ((array) $this->resp_headers['set-cookie'] as $c){
 253                  list($key, $value, $foo) = split('=', $cookie);
 254                  $this->cookies[$key] = $value;
 255              }
 256          }
 257  
 258          $this->_debug('Object headers',$this->resp_headers);
 259  
 260          // check server status code to follow redirect
 261          if($this->status == 301 || $this->status == 302 ){
 262              if (empty($this->resp_headers['location'])){
 263                  $this->error = 'Redirect but no Location Header found';
 264                  return false;
 265              }elseif($this->redirect_count == $this->max_redirect){
 266                  $this->error = 'Maximum number of redirects exceeded';
 267                  return false;
 268              }else{
 269                  $this->redirect_count++;
 270                  $this->referer = $url;
 271                  if (!preg_match('/^http/i', $this->resp_headers['location'])){
 272                      $this->resp_headers['location'] = $uri['scheme'].'://'.$uri['host'].
 273                                                        $this->resp_headers['location'];
 274                  }
 275                  // perform redirected request, always via GET (required by RFC)
 276                  return $this->sendRequest($this->resp_headers['location'],array(),'GET');
 277              }
 278          }
 279  
 280          // check if headers are as expected
 281          if($this->header_regexp && !preg_match($this->header_regexp,$r_headers)){
 282              $this->error = 'The received headers did not match the given regexp';
 283              return false;
 284          }
 285  
 286          //read body (with chunked encoding if needed)
 287          $r_body    = '';
 288          if(preg_match('/transfer\-(en)?coding:\s*chunked\r\n/i',$r_header)){
 289              do {
 290                  unset($chunk_size);
 291                  do {
 292                      if(feof($socket)){
 293                          $this->error = 'Premature End of File (socket)';
 294                          return false;
 295                      }
 296                      if(time()-$start > $this->timeout){
 297                          $this->status = -100;
 298                          $this->error = 'Timeout while reading chunk';
 299                          return false;
 300                      }
 301                      $byte = fread($socket,1);
 302                      $chunk_size .= $byte;
 303                  } while (preg_match('/[a-zA-Z0-9]/',$byte)); // read chunksize including \r
 304  
 305                  $byte = fread($socket,1);     // readtrailing \n
 306                  $chunk_size = hexdec($chunk_size);
 307                  $this_chunk = fread($socket,$chunk_size);
 308                  $r_body    .= $this_chunk;
 309                  if ($chunk_size) $byte = fread($socket,2); // read trailing \r\n
 310  
 311                  if($this->max_bodysize && strlen($r_body) > $this->max_bodysize){
 312                      $this->error = 'Allowed response size exceeded';
 313                      return false;
 314                  }
 315              } while ($chunk_size);
 316          }else{
 317              // read entire socket
 318              while (!feof($socket)) {
 319                  if(time()-$start > $this->timeout){
 320                      $this->status = -100;
 321                      $this->error = 'Timeout while reading response';
 322                      return false;
 323                  }
 324                  $r_body .= fread($socket,4096);
 325                  if($this->max_bodysize && strlen($r_body) > $this->max_bodysize){
 326                      $this->error = 'Allowed response size exceeded';
 327                      return false;
 328                  }
 329              }
 330          }
 331  
 332          // close socket
 333          $status = socket_get_status($socket);
 334          fclose($socket);
 335  
 336          // decode gzip if needed
 337          if($this->resp_headers['content-encoding'] == 'gzip'){
 338              $this->resp_body = gzinflate(substr($r_body, 10));
 339          }else{
 340              $this->resp_body = $r_body;
 341          }
 342  
 343          $this->_debug('response body',$this->resp_body);
 344          $this->redirect_count = 0;
 345          return true;
 346      }
 347  
 348      /**
 349       * print debug info
 350       *
 351       * @author Andreas Gohr <andi@splitbrain.org>
 352       */
 353      function _debug($info,$var){
 354          if(!$this->debug) return;
 355          print '<b>'.$info.'</b><br />';
 356          ob_start();
 357          print_r($var);
 358          $content = htmlspecialchars(ob_get_contents());
 359          ob_end_clean();
 360          print '<pre>'.$content.'</pre>';
 361      }
 362  
 363      /**
 364       * convert given header string to Header array
 365       *
 366       * All Keys are lowercased.
 367       *
 368       * @author Andreas Gohr <andi@splitbrain.org>
 369       */
 370      function _parseHeaders($string){
 371          $headers = array();
 372          $lines = explode("\n",$string);
 373          foreach($lines as $line){
 374              list($key,$val) = explode(':',$line,2);
 375              $key = strtolower(trim($key));
 376              $val = trim($val);
 377              if(empty($val)) continue;
 378              if(isset($headers[$key])){
 379                  if(is_array($headers[$key])){
 380                      $headers[$key][] = $val;
 381                  }else{
 382                      $headers[$key] = array($headers[$key],$val);
 383                  }
 384              }else{
 385                  $headers[$key] = $val;
 386              }
 387          }
 388          return $headers;
 389      }
 390  
 391      /**
 392       * convert given header array to header string
 393       *
 394       * @author Andreas Gohr <andi@splitbrain.org>
 395       */
 396      function _buildHeaders($headers){
 397          $string = '';
 398          foreach($headers as $key => $value){
 399              if(empty($value)) continue;
 400              $string .= $key.': '.$value.HTTP_NL;
 401          }
 402          return $string;
 403      }
 404  
 405      /**
 406       * get cookies as http header string
 407       *
 408       * @author Andreas Goetz <cpuidle@gmx.de>
 409       */
 410      function _getCookies(){
 411          foreach ($this->cookies as $key => $val){
 412              if ($headers) $headers .= '; ';
 413              $headers .= $key.'='.$val;
 414          }
 415  
 416          if ($headers) $headers = "Cookie: $headers".HTTP_NL;
 417          return $headers;
 418      }
 419  
 420      /**
 421       * Encode data for posting
 422       *
 423       * @todo handle mixed encoding for file upoads
 424       * @author Andreas Gohr <andi@splitbrain.org>
 425       */
 426      function _postEncode($data){
 427          foreach($data as $key => $val){
 428              if($url) $url .= '&';
 429              $url .= $key.'='.urlencode($val);
 430          }
 431          return $url;
 432      }
 433  }
 434  
 435  //Setup VIM: ex: et ts=4 enc=utf-8 :


Généré le : Tue Apr 3 20:47:31 2007 par Balluche grâce à PHPXref 0.7