| [ Index ] |
|
Code source de Dotclear 2.0-beta6 |
1 <?php 2 # ***** BEGIN LICENSE BLOCK ***** 3 # This file is part of Clearbricks. 4 # Copyright (c) 2006 Olivier Meunier and contributors. All rights 5 # reserved. 6 # 7 # Clearbricks is free software; you can redistribute it and/or modify 8 # it under the terms of the GNU General Public License as published by 9 # the Free Software Foundation; either version 2 of the License, or 10 # (at your option) any later version. 11 # 12 # Clearbricks is distributed in the hope that it will be useful, 13 # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 # GNU General Public License for more details. 16 # 17 # You should have received a copy of the GNU General Public License 18 # along with Clearbricks; if not, write to the Free Software 19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 # 21 # ***** END LICENSE BLOCK ***** 22 # 23 # Fully based on Simon Willison's HTTP Client 24 # 25 # Version 0.9, 6th April 2003 - Simon Willison ( http://simon.incutio.com/ ) 26 # Manual: http://scripts.incutio.com/httpclient/ 27 # 28 # Changes: 29 # - Charset support in POST requests 30 # - Proxy support through HTTP_PROXY_HOST and HTTP_PROXY_PORT or setProxy() 31 # - SSL support 32 # - Handles redirects on other hosts 33 # - Configurable output 34 35 /** 36 @ingroup CB_NET 37 @brief Client class for HTTP protocol. 38 39 Features: 40 41 - Implements a useful subset of the HTTP 1.0 and 1.1 protocols. 42 - Includes cookie support. 43 - Ability to set the user agent and referal fields. 44 - Can automatically handle redirected pages. 45 - Can be used for multiple requests, with any cookies sent by the server resent 46 for each additional request. 47 - Support for gzip encoded content, which can dramatically reduce the amount of 48 bandwidth used in a transaction. 49 - Object oriented, with static methods providing a useful shortcut for simple 50 requests. 51 - The ability to only read the page headers - useful for implementing tools such 52 as link checkers. 53 - Support for file uploads. 54 55 */ 56 class netHttp extends netSocket 57 { 58 protected $host; ///< <b>string</b> Server host 59 protected $port; ///< <b>integer</b> Server port 60 protected $path; ///< <b>string</b> Query path 61 protected $method; ///< <b>string</b> HTTP method 62 protected $postdata = ''; ///< <b>string</b> POST query string 63 protected $post_charset; ///< <b>string</b> POST charset 64 protected $cookies = array(); ///< <b>array</b> Cookies sent 65 protected $referer; ///< <b>string</b> HTTP referer 66 protected $accept = 'text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,image/jpeg,image/gif,*/*'; ///< <b>string</b> HTTP accept header 67 protected $accept_encoding = 'gzip'; ///< <b>string</b> HTTP accept encoding 68 protected $accept_language = 'en-us'; ///< <b>string</b> HTTP accept language 69 protected $user_agent = 'Clearbricks HTTP Client'; ///< <b>string</b> HTTP User Agent 70 protected $timeout = 10; ///< <b>integer</b> Connection timeout 71 protected $use_ssl = false; ///< <b>boolean</b> Use SSL connection 72 protected $use_gzip = false; ///< <b>boolean</b> Use gzip transfert 73 protected $persist_cookies = true; ///< <b>boolean</b> Allow persistant cookies 74 protected $persist_referers = true; ///< <b>boolean</b> Allow persistant referers 75 protected $debug = false; ///< <b>boolean</b> Use debug mode 76 protected $handle_redirects = true; ///< <b>boolean</b> Follow redirects 77 protected $max_redirects = 5; ///< <b>integer</b> Maximum redirects to follow 78 protected $headers_only = false; ///< <b>boolean</b> Retrieve only headers 79 80 protected $username; ///< <b>string</b> Authentication user name 81 protected $password; ///< <b>string</b> Authentication password 82 83 protected $proxy_host; ///< <b>string</b> Proxy server host 84 protected $proxy_port; ///< <b>integer</b> Proxy server port 85 86 # Response vars 87 protected $status; ///< <b>integer</b> HTTP Status code 88 protected $status_string; ///< <b>string</b> HTTP Status string 89 protected $headers = array(); ///< <b>array</b> Response headers 90 protected $content = ''; ///< <b>string</b> Response body 91 92 # Tracker variables 93 protected $redirect_count = 0; ///< <b>integer</b> Internal redirects count 94 protected $cookie_host = ''; ///< <b>string</b> Internal cookie host 95 96 # Output module (null is this->content) 97 protected $output = null; ///< <b>string</b> Output stream name 98 protected $output_h = null; ///< <b>resource</b> Output resource 99 100 /** 101 Constructor. Takes the web server host, an optional port and timeout. 102 103 @param host <b>string</b> Server host 104 @param port <b>integer</b> Server port 105 @param timeout <b>integer</b> Connection timeout 106 */ 107 public function __construct($host,$port=80,$timeout=null) 108 { 109 $this->setHost($host,$port); 110 111 if (defined('HTTP_PROXY_HOST') && defined('HTTP_PROXY_PORT')) { 112 $this->setProxy(HTTP_PROXY_HOST,HTTP_PROXY_PORT); 113 } 114 115 if ($timeout) { 116 $this->setTimeout($timeout); 117 } 118 $this->_timeout =& $this->timeout; 119 } 120 121 /** 122 Executes a GET request for the specified path. If <var>$data</var> is 123 specified, appends it to a query string as part of the get request. 124 <var>$data</var> can be an array of key value pairs, in which case a 125 matching query string will be constructed. Returns true on success. 126 127 @param path <b>string</b> Request path 128 @param data <b>array</b> Request parameters 129 @return <b>boolean</b> 130 */ 131 public function get($path,$data=false) 132 { 133 $this->path = $path; 134 $this->method = 'GET'; 135 136 if ($data) { 137 $this->path .= '?'.$this->buildQueryString($data); 138 } 139 140 return $this->doRequest(); 141 } 142 143 /** 144 Executes a POST request for the specified path. If <var>$data</var> is 145 specified, appends it to a query string as part of the get request. 146 <var>$data</var> can be an array of key value pairs, in which case a 147 matching query string will be constructed. Returns true on success. 148 149 @param path <b>string</b> Request path 150 @param data <b>array</b> Request parameters 151 @param charset <b>string</b> Request charset 152 @return <b>boolean</b> 153 */ 154 public function post($path,$data,$charset=null) 155 { 156 if ($charset) { 157 $this->post_charset = $charset; 158 } 159 $this->path = $path; 160 $this->method = 'POST'; 161 $this->postdata = $this->buildQueryString($data); 162 return $this->doRequest(); 163 } 164 165 /** 166 Prepares Query String for HTTP request. <var>$data</var> is an associative 167 array of arguments. 168 169 @param data <b>array</b> Query data 170 @return <b>string</b> 171 */ 172 protected function buildQueryString($data) 173 { 174 if (is_array($data)) 175 { 176 $qs = array(); 177 # Change data in to postable data 178 foreach ($data as $key => $val) 179 { 180 if (is_array($val)) { 181 foreach ($val as $val2) { 182 $qs[] = urlencode($key).'='.urlencode($val2); 183 } 184 } else { 185 $qs[] = urlencode($key).'='.urlencode($val); 186 } 187 } 188 $qs = implode('&',$qs); 189 } else { 190 $qs = $data; 191 } 192 193 return $qs; 194 } 195 196 /** 197 Sends HTTP request and stores status, headers, content object properties. 198 199 @return <b>boolean</b> 200 */ 201 protected function doRequest() 202 { 203 if ($this->proxy_host && $this->proxy_port) { 204 if ($this->use_ssl) { 205 throw new Exception('SSL support is not available through a proxy'); 206 } 207 $this->_host = $this->proxy_host; 208 $this->_port = $this->proxy_port; 209 $this->_transport = ''; 210 } else { 211 $this->_host = $this->host; 212 $this->_port = $this->port; 213 $this->_transport = $this->use_ssl ? 'ssl://' : ''; 214 } 215 216 #Reset all the variables that should not persist between requests 217 $this->headers = array(); 218 $in_headers = true; 219 $this->outputOpen(); 220 221 $request = $this->buildRequest(); 222 $this->debug('Request',implode("\r",$request)); 223 224 $this->open(); 225 $this->debug('Connecting to '.$this->_transport.$this->_host.':'.$this->_port); 226 foreach($this->write($request) as $index => $line) 227 { 228 # Deal with first line of returned data 229 if ($index == 0) 230 { 231 $line = rtrim($line,"\r\n"); 232 if (!preg_match('/HTTP\/(\\d\\.\\d)\\s*(\\d+)\\s*(.*)/', $line, $m)) { 233 throw new Exception('Status code line invalid: '.$line); 234 } 235 $http_version = $m[1]; # not used 236 $this->status = $m[2]; 237 $this->status_string = $m[3]; # not used 238 $this->debug($line); 239 continue; 240 } 241 242 # Read headers 243 if ($in_headers) 244 { 245 $line = rtrim($line,"\r\n"); 246 if ($line == '') 247 { 248 $in_headers = false; 249 $this->debug('Received Headers',$this->headers); 250 if ($this->headers_only) { 251 break; 252 } 253 continue; 254 } 255 256 if (!preg_match('/([^:]+):\\s*(.*)/', $line, $m)) { 257 # Skip to the next header 258 continue; 259 } 260 $key = strtolower(trim($m[1])); 261 $val = trim($m[2]); 262 # Deal with the possibility of multiple headers of same name 263 if (isset($this->headers[$key])) { 264 if (is_array($this->headers[$key])) { 265 $this->headers[$key][] = $val; 266 } else { 267 $this->headers[$key] = array($this->headers[$key], $val); 268 } 269 } else { 270 $this->headers[$key] = $val; 271 } 272 continue; 273 } 274 275 # We're not in the headers, so append the line to the contents 276 $this->outputWrite($line); 277 } 278 $this->close(); 279 $this->outputClose(); 280 281 # If data is compressed, uncompress it 282 if ($this->getHeader('content-encoding')) { 283 $this->debug('Content is gzip encoded, unzipping it'); 284 # See http://www.php.net/manual/en/function.gzencode.php 285 $this->content = gzinflate(substr($this->content, 10)); 286 } 287 288 # If $persist_cookies, deal with any cookies 289 if ($this->persist_cookies && $this->getHeader('set-cookie') && $this->host == $this->cookie_host) 290 { 291 $cookies = $this->headers['set-cookie']; 292 if (!is_array($cookies)) { 293 $cookies = array($cookies); 294 } 295 296 foreach ($cookies as $cookie) 297 { 298 if (preg_match('/([^=]+)=([^;]+);/', $cookie, $m)) { 299 $this->cookies[$m[1]] = $m[2]; 300 } 301 } 302 303 # Record domain of cookies for security reasons 304 $this->cookie_host = $this->host; 305 } 306 307 # If $persist_referers, set the referer ready for the next request 308 if ($this->persist_referers) { 309 $this->debug('Persisting referer: '.$this->getRequestURL()); 310 $this->referer = $this->getRequestURL(); 311 } 312 313 # Finally, if handle_redirects and a redirect is sent, do that 314 if ($this->handle_redirects) 315 { 316 if (++$this->redirect_count >= $this->max_redirects) 317 { 318 $this->redirect_count = 0; 319 throw new Exception('Number of redirects exceeded maximum ('.$this->max_redirects.')'); 320 } 321 322 $location = isset($this->headers['location']) ? $this->headers['location'] : ''; 323 $uri = isset($this->headers['uri']) ? $this->headers['uri'] : ''; 324 if ($location || $uri) 325 { 326 if (self::readUrl($location.$uri,$r_ssl,$r_host,$r_port,$r_path,$r_user,$r_pass)) 327 { 328 # If we try to move on another host, remove cookies, user and pass 329 if ($r_host != $this->host || $r_port != $this->port) { 330 $this->cookies = array(); 331 $this->setAuthorization(null,null); 332 $this->setHost($r_host,$r_port); 333 } 334 $this->useSSL($r_ssl); 335 $this->debug('Redirect to: '.$location.$uri); 336 return $this->get($r_path); 337 } 338 } 339 $this->redirect_count = 0; 340 } 341 return true; 342 } 343 344 /** 345 Prepares HTTP request and returns an array of HTTP headers. 346 347 @return <b>array</b> 348 */ 349 protected function buildRequest() 350 { 351 $headers = array(); 352 353 if ($this->proxy_host) { 354 $path = $this->getRequestURL(); 355 } else { 356 $path = $this->path; 357 } 358 359 # Using 1.1 leads to all manner of problems, such as "chunked" encoding 360 $headers[] = $this->method.' '.$path.' HTTP/1.0'; 361 362 $headers[] = 'Host: '.$this->host; 363 $headers[] = 'User-Agent: '.$this->user_agent; 364 $headers[] = 'Accept: '.$this->accept; 365 366 if ($this->use_gzip) { 367 $headers[] = 'Accept-encoding: '.$this->accept_encoding; 368 } 369 $headers[] = 'Accept-language: '.$this->accept_language; 370 371 if ($this->referer) { 372 $headers[] = 'Referer: '.$this->referer; 373 } 374 375 # Cookies 376 if ($this->cookies) { 377 $cookie = 'Cookie: '; 378 foreach ($this->cookies as $key => $value) { 379 $cookie .= $key.'='.$value.';'; 380 } 381 $headers[] = $cookie; 382 } 383 384 # Basic authentication 385 if ($this->username && $this->password) { 386 $headers[] = 'Authorization: BASIC '.base64_encode($this->username.':'.$this->password); 387 } 388 389 # If this is a POST, set the content type and length 390 if ($this->postdata) { 391 $content_type = 'Content-Type: application/x-www-form-urlencoded'; 392 if ($this->post_charset) { 393 $content_type .= '; charset='.$this->post_charset; 394 } 395 $headers[] = $content_type; 396 $headers[] = 'Content-Length: '.strlen($this->postdata); 397 $headers[] = ''; 398 $headers[] = $this->postdata; 399 } 400 401 return $headers; 402 } 403 404 /** 405 Initializes output handler if <var>$output</var> property is not null and 406 is a valid stream. 407 */ 408 protected function outputOpen() 409 { 410 if ($this->output) { 411 if (($this->output_h = @fopen($this->output,'wb')) === false) { 412 throw new Exception('Unable to open output stream '.$this->output); 413 } 414 } else { 415 $this->content = ''; 416 } 417 } 418 419 /** 420 Closes output module if exists. 421 */ 422 protected function outputClose() 423 { 424 if ($this->output && is_resource($this->output_h)) { 425 fclose($this->output_h); 426 } 427 } 428 429 /** 430 Writes data to output module. 431 */ 432 protected function outputWrite($c) 433 { 434 if ($this->output && is_resource($this->output_h)) { 435 fwrite($this->output_h,$c); 436 } else { 437 $this->content .= $c; 438 } 439 } 440 441 /** 442 Returns the status code of the response - 200 means OK, 404 means file not 443 found, etc. 444 445 @return <b>string</b> 446 */ 447 public function getStatus() 448 { 449 return $this->status; 450 } 451 452 /** 453 Returns the content of the HTTP response. This is usually an HTML document. 454 455 @return <b>string</b> 456 */ 457 public function getContent() 458 { 459 return $this->content; 460 } 461 462 /** 463 Returns the HTTP headers returned by the server as an associative array. 464 465 @return <b>array</b> 466 */ 467 public function getHeaders() 468 { 469 return $this->headers; 470 } 471 472 /** 473 Returns the specified response header, or false if it does not exist. 474 475 @param header <b>string</b> Header name 476 @return <b>string</b> 477 */ 478 public function getHeader($header) 479 { 480 $header = strtolower($header); 481 if (isset($this->headers[$header])) { 482 return $this->headers[$header]; 483 } else { 484 return false; 485 } 486 } 487 488 /** 489 Returns an array of cookies set by the server. 490 491 @return <b>array</b> 492 */ 493 public function getCookies() 494 { 495 return $this->cookies; 496 } 497 498 /** 499 Returns the full URL that has been requested. 500 501 @return <b>string</b> 502 */ 503 public function getRequestURL() 504 { 505 $url = 'http'.($this->use_ssl ? 's' : '').'://'.$this->host; 506 if (!$this->use_ssl && $this->port != 80 || $this->use_ssl && $this->port != 443) { 507 $url .= ':'.$this->port; 508 } 509 $url .= $this->path; 510 return $url; 511 } 512 513 /** 514 Sets server host and port. 515 516 @param host <b>string</b> Server host 517 @param port <b>integer</b> Server port 518 */ 519 public function setHost($host,$port=80) 520 { 521 $this->host = $host; 522 $this->port = abs((integer) $port); 523 } 524 525 /** 526 Sets proxy host and port. 527 528 @param host <b>string</b> Proxy host 529 @param port <b>integer</b> Proxy port 530 */ 531 public function setProxy($host,$port='8080') 532 { 533 $this->proxy_host = $host; 534 $this->proxy_port = abs((integer) $port); 535 } 536 537 /** 538 Sets connection timeout. 539 540 @param t <b>integer</b> Connection timeout 541 */ 542 public function setTimeout($t) 543 { 544 $this->timeout = abs((integer) $t); 545 } 546 547 /** 548 Sets the user agent string to be used in the request. Default is 549 "Clearbricks HTTP Client". 550 551 @param string <b>string</b> User agent string 552 */ 553 public function setUserAgent($string) 554 { 555 $this->user_agent = $string; 556 } 557 558 /** 559 Sets the HTTP authorization username and password to be used in requests. 560 Don't forget to unset this in subsequent requests to different servers. 561 562 @param username <b>string</b> User name 563 @param password <b>integer</b> Password 564 */ 565 public function setAuthorization($username,$password) 566 { 567 $this->username = $username; 568 $this->password = $password; 569 } 570 571 /** 572 Sets the cookies to be sent in the request. Takes an array of name value 573 pairs. 574 575 @param array <b>array</b> Cookies array 576 */ 577 public function setCookies($array) 578 { 579 $this->cookies = $array; 580 } 581 582 /** 583 Sets SSL connection usage. 584 */ 585 public function useSSL($boolean) 586 { 587 if ($boolean) { 588 if (!in_array('ssl',stream_get_transports())) { 589 throw new Exception('SSL support is not available'); 590 } 591 $this->use_ssl = true; 592 } else { 593 $this->use_ssl = false; 594 } 595 } 596 597 /** 598 Specify if the client should request gzip encoded content from the server 599 (saves bandwidth but can increase processor time). Default behaviour is 600 FALSE. 601 */ 602 public function useGzip($boolean) 603 { 604 $this->use_gzip = (boolean) $boolean; 605 } 606 607 /** 608 Specify if the client should persist cookies between requests. Default 609 behaviour is TRUE. 610 */ 611 public function setPersistCookies($boolean) 612 { 613 $this->persist_cookies = (boolean) $boolean; 614 } 615 616 /** 617 Specify if the client should use the URL of the previous request as the 618 referral of a subsequent request. Default behaviour is TRUE. 619 */ 620 public function setPersistReferers($boolean) 621 { 622 $this->persist_referers = (boolean) $boolean; 623 } 624 625 /** 626 Specify if the client should automatically follow redirected requests. 627 Default behaviour is TRUE. 628 */ 629 public function setHandleRedirects($boolean) 630 { 631 $this->handle_redirects = (boolean) $boolean; 632 } 633 634 /** 635 Set the maximum number of redirects allowed before the client quits 636 (mainly to prevent infinite loops) Default is 5. 637 */ 638 public function setMaxRedirects($num) 639 { 640 $this->max_redirects = abs((integer) $num); 641 } 642 643 /** 644 If TRUE, the client only retrieves the headers from a page. This could be 645 useful for implementing things like link checkers. Defaults to FALSE. 646 */ 647 public function setHeadersOnly($boolean) 648 { 649 $this->headers_only = (boolean) $boolean; 650 } 651 652 /** 653 Should the client run in debug mode? Default behaviour is FALSE. 654 */ 655 public function setDebug($boolean) 656 { 657 $this->debug = (boolean) $boolean; 658 } 659 660 /** 661 Output module init. 662 663 @param out <b>string</b> Output stream 664 */ 665 public function setOutput($out) 666 { 667 $this->output = $out; 668 } 669 670 /** 671 Static method designed for running simple GET requests. Returns content or 672 false on failure. 673 674 @param url <b>string</b> Request URL 675 @param output <b>string</b> Optionnal output stream 676 @return <b>string</b> 677 */ 678 public static function quickGet($url,$output=null) 679 { 680 if (($client = self::initClient($url,$path)) === false) { 681 return false; 682 } 683 $client->setOutput($output); 684 $client->get($path); 685 return $client->getStatus() == 200 ? $client->getContent() : false; 686 } 687 688 /** 689 Static method designed for running simple POST requests. Returns content or 690 false on failure. 691 692 @param url <b>string</b> Request URL 693 @param data <b>array</b> Array of parameters 694 @param output <b>string</b> Optionnal output stream 695 @return <b>string</b> 696 */ 697 public static function quickPost($url,$data,$output=null) 698 { 699 if (($client = self::initClient($url,$path)) === false) { 700 return false; 701 } 702 $client->setOutput($output); 703 $client->post($path,$data); 704 return $client->getStatus() == 200 ? $client->getContent() : false; 705 } 706 707 /** 708 Returns a new instance of the class. <var>$path</var> is an output variable. 709 710 @param url <b>string</b> Request URL 711 @param[out] path <b>string</b> Resulting path 712 @return <b>netHttp</b> 713 */ 714 public static function initClient($url,&$path) 715 { 716 if (!self::readUrl($url,$ssl,$host,$port,$path,$user,$pass)) { 717 return false; 718 } 719 720 $client = new self($host,$port); 721 $client->useSSL($ssl); 722 $client->setAuthorization($user,$pass); 723 724 return $client; 725 } 726 727 /** 728 Parses an URL and fills <var>$ssl</var>, <var>$host</var>, <var>$port</var>, 729 <var>$path</var>, <var>$user</var> and <var>$pass</var> variables. Returns 730 true on succes. 731 */ 732 public static function readURL($url,&$ssl,&$host,&$port,&$path,&$user,&$pass) 733 { 734 $bits = parse_url($url); 735 736 if (empty($bits['host'])) { 737 return false; 738 } 739 740 if (empty($bits['scheme']) || !preg_match('%^http[s]?$%',$bits['scheme'])) { 741 return false; 742 } 743 744 $scheme = isset($bits['scheme']) ? $bits['scheme'] : 'http'; 745 $host = isset($bits['host']) ? $bits['host'] : null; 746 $port = isset($bits['port']) ? $bits['port'] : null; 747 $path = isset($bits['path']) ? $bits['path'] : '/'; 748 $user = isset($bits['user']) ? $bits['user'] : null; 749 $pass = isset($bits['pass']) ? $bits['pass'] : null; 750 751 $ssl = $scheme == 'https'; 752 753 if (!$port) { 754 $port = $ssl ? 443 : 80; 755 } 756 757 if (isset($bits['query'])) { 758 $path .= '?'.$bits['query']; 759 } 760 761 return true; 762 } 763 764 /** 765 This method is the method the class calls whenever there is debugging 766 information available. $msg is a debugging message and $object is an 767 optional object to be displayed (usually an array). Default behaviour is to 768 display the message and the object in a red bordered div. If you wish 769 debugging information to be handled in a different way you can do so by 770 creating a new class that extends HttpClient and over-riding the debug() 771 method in that class. 772 773 @param msg <b>string</b> Debug message 774 @param object <b>mixed</b> Variable to print_r 775 */ 776 protected function debug($msg,$object=false) 777 { 778 if ($this->debug) { 779 echo "-----------------------------------------------------------\n"; 780 echo '-- netHttp Debug: '.$msg."\n"; 781 if ($object) { 782 print_r($object); 783 echo "\n"; 784 } 785 echo "-----------------------------------------------------------\n\n"; 786 } 787 } 788 } 789 790 /* Compatibility to Incutio HttpClient class 791 This will be removed soon! */ 792 class HttpClient extends netHttp 793 { 794 public function getError() 795 { 796 return null; 797 } 798 } 799 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Fri Feb 23 22:16:06 2007 | par Balluche grâce à PHPXref 0.7 |