| [ Index ] |
|
Code source de eGroupWare 1.2.106-2 |
1 <?php 2 /**************************************************************************\ 3 * eGroupWare API - HTTP and WebDAV protocol class * 4 * http://www.egroupware.org/api * 5 * Original Author: Leo West <west_leo@yahoo-REMOVE-.com> * 6 * ------------------------------------------------------------------------ * 7 * This library is not part of eGroupWare, but is used by eGroupWare. * 8 * ------------------------------------------------------------------------ * 9 * This program is free software; you can redistribute it and/or modify it * 10 * under the terms of the GNU General Public License as published by the * 11 * Free Software Foundation; either version 2 of the License, or (at your * 12 * option) any later version. * 13 * This program is distributed in the hope that it will be useful, * 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 16 * GNU General Public License for more details. * 17 * You should have received a copy of the GNU General Public License * 18 * along with this program; if not, write to the Free Software * 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 20 \**************************************************************************/ 21 22 23 /* 24 25 net_http_client class 26 27 @DESCRIPTION 28 29 HTTP Client component 30 suppots methods HEAD, GET, POST 31 1.0 and 1.1 compliant 32 WebDAV methods tested against Apache/mod_dav 33 Documentation @ http://lwest.free.fr/doc/php/lib/net_http_client-en.html 34 35 @SYNOPSIS 36 37 include "Net/HTTP/Client.php"; 38 39 $http = new net_http_client(); 40 $http->connect( "localhost", 80 ) or die( "connect problem" ); 41 $status = $http->get( "/index.html" ); 42 if( $status != 200 ) 43 die( "Problem : " . $http->getStatusMessage() . "\n" ); 44 $http->disconnect(); 45 46 47 48 @CHANGES 49 0.1 initial version 50 0.2 documentation completed 51 + getHeaders(), getBody() 52 o Post(), Connect() 53 0.3 DAV enhancements: 54 + Put() method 55 0.4 continued DAV support 56 + Delete(), Move(), MkCol(), Propfind() methods 57 o added url property, remove host and port properties 58 o Connect, net_http_client (use of this.url) 59 o processBody() : use non-blocking to fix a socket pblm 60 0.5 debug support 61 + setDebug() 62 + debug levels definitions (DBG*) 63 0.6 + Lock() method 64 + setCredentials() method and fix - thanks Thomas Olsen 65 + support for Get( full_url ) 66 o fix POST call (duplicate content-length) - thanks to Javier Sixto 67 0.7 + OPTIONS method support 68 + addCookie and removeCookies methods 69 o fix the "0" problem 70 o undeifned variable warning fixed 71 72 73 @VERSION 74 0.7 75 76 @INFORMATIONS 77 78 Compatibility : PHP 4 >= 4.0b4 79 created : May 2001 80 LastModified : Sep 2002 81 82 83 @AUTHOR 84 Leo West <west_leo@yahoo-REMOVE-.com> 85 86 @TODO 87 remaining WebDAV methods: UNLOCK PROPPATCH 88 89 90 */ 91 92 93 /// debug levels , use it as Client::setDebug( DBGSOCK & DBGTRACE ) 94 define( "DBGTRACE", 1 ); // to debug methods calls 95 define( "DBGINDATA", 2 ); // to debug data received 96 define( "DBGOUTDATA", 4 ); // to debug data sent 97 define( "DBGLOW", 8 ); // to debug low-level (usually internal) methods 98 define( "DBGSOCK", 16 ); // to debug socket-level code 99 100 /// internal errors 101 define( "ECONNECTION", -1 ); // connection failed 102 define( "EBADRESPONSE", -2 ); // response status line is not http compliant 103 104 define( "CRLF", "\r\n" ); 105 106 107 class net_http_client 108 { 109 110 // @private 111 /// array containg server URL, similar to array returned by parseurl() 112 var $url; 113 /// server response code eg. "304" 114 var $reply; 115 /// server response line eg. "200 OK" 116 var $replyString; 117 /// HTPP protocol version used 118 var $protocolVersion = "1.0"; 119 /// internal buffers 120 var $requestHeaders, $requestBody; 121 /// TCP socket identifier 122 var $socket = false; 123 /// proxy informations 124 var $useProxy = false; 125 var $proxyHost, $proxyPort; 126 /// debugging flag 127 var $debug = 0; 128 129 /** 130 * net_http_client 131 * constructor 132 * Note : when host and port are defined, the connection is immediate 133 * @seeAlso connect 134 **/ 135 function net_http_client( $host= NULL, $port= NULL ) 136 { 137 if( $this->debug & DBGTRACE ) echo "net_http_client( $host, $port )\n"; 138 139 if( $host != NULL ) { 140 $this->connect( $host, $port ); 141 } 142 } 143 144 /** 145 * turn on debug messages 146 * @param level a combinaison of debug flags 147 * @see debug flags ( DBG..) defined at top of file 148 **/ 149 function setDebug( $level ) 150 { 151 if( $this->debug & DBGTRACE ) echo "setDebug( $level )\n"; 152 $this->debug = $level; 153 } 154 155 156 /** 157 * turn on proxy support 158 * @param proxyHost proxy host address eg "proxy.mycorp.com" 159 * @param proxyPort proxy port usually 80 or 8080 160 **/ 161 function setProxy( $proxyHost, $proxyPort ) 162 { 163 if( $this->debug & DBGTRACE ) echo "setProxy( $proxyHost, $proxyPort )\n"; 164 $this->useProxy = true; 165 $this->proxyHost = $proxyHost; 166 $this->proxyPort = $proxyPort; 167 } 168 169 170 /** 171 * setProtocolVersion 172 * define the HTTP protocol version to use 173 * @param version string the version number with one decimal: "0.9", "1.0", "1.1" 174 * when using 1.1, you MUST set the mandatory headers "Host" 175 * @return boolean false if the version number is bad, true if ok 176 **/ 177 function setProtocolVersion( $version ) 178 { 179 if( $this->debug & DBGTRACE ) echo "setProtocolVersion( $version )\n"; 180 181 if( $version > 0 and $version <= 1.1 ) { 182 $this->protocolVersion = $version; 183 return true; 184 } else { 185 return false; 186 } 187 } 188 189 /** 190 * set a username and password to access a protected resource 191 * Only "Basic" authentication scheme is supported yet 192 * @param username string - identifier 193 * @param password string - clear password 194 **/ 195 function setCredentials( $username, $password ) 196 { 197 $hdrvalue = base64_encode( "$username:$password" ); 198 $this->addHeader( "Authorization", "Basic $hdrvalue" ); 199 } 200 201 /** 202 * define a set of HTTP headers to be sent to the server 203 * header names are lowercased to avoid duplicated headers 204 * @param headers hash array containing the headers as headerName => headerValue pairs 205 **/ 206 function setHeaders( $headers ) 207 { 208 if( $this->debug & DBGTRACE ) echo "setHeaders( $headers ) \n"; 209 if( is_array( $headers )) { 210 foreach( $headers as $name => $value ) { 211 $this->requestHeaders[$name] = $value; 212 } 213 } 214 } 215 216 /** 217 * addHeader 218 * set a unique request header 219 * @param headerName the header name 220 * @param headerValue the header value, ( unencoded) 221 **/ 222 function addHeader( $headerName, $headerValue ) 223 { 224 if( $this->debug & DBGTRACE ) echo "addHeader( $headerName, $headerValue )\n"; 225 $this->requestHeaders[$headerName] = $headerValue; 226 } 227 228 /** 229 * removeHeader 230 * unset a request header 231 * @param headerName the header name 232 **/ 233 function removeHeader( $headerName ) 234 { 235 if( $this->debug & DBGTRACE ) echo "removeHeader( $headerName) \n"; 236 unset( $this->requestHeaders[$headerName] ); 237 } 238 239 /** 240 * addCookie 241 * set a session cookie, that will be used in the next requests. 242 * this is a hack as cookie are usually set by the server, but you may need it 243 * it is your responsabilty to unset the cookie if you request another host 244 * to keep a session on the server 245 * @param string the name of the cookie 246 * @param string the value for the cookie 247 **/ 248 function addCookie( $cookiename, $cookievalue ) 249 { 250 if( $this->debug & DBGTRACE ) echo "addCookie( $cookiename, $cookievalue ) \n"; 251 $cookie = $cookiename . "=" . $cookievalue; 252 $this->requestHeaders["Cookie"] = $cookie; 253 } 254 255 /** 256 * removeCookie 257 * unset cookies currently in use 258 **/ 259 function removeCookies() 260 { 261 if( $this->debug & DBGTRACE ) echo "removeCookies() \n"; 262 unset( $this->requestHeaders["Cookie"] ); 263 } 264 265 /** 266 * Connect 267 * open the connection to the server 268 * @param host string server address (or IP) 269 * @param port string server listening port - defaults to 80 270 * @return boolean false is connection failed, true otherwise 271 **/ 272 function Connect( $host, $port = NULL ) 273 { 274 if( $this->debug & DBGTRACE ) echo "Connect( $host, $port ) \n"; 275 276 $this->url['scheme'] = "http"; 277 $this->url['host'] = $host; 278 if( $port != NULL ) 279 $this->url['port'] = $port; 280 return true; 281 } 282 283 /** 284 * Disconnect 285 * close the connection to the server 286 **/ 287 function Disconnect() 288 { 289 if( $this->debug & DBGTRACE ) echo "Disconnect()\n"; 290 if( $this->socket ) 291 fclose( $this->socket ); 292 } 293 294 /** 295 * head 296 * issue a HEAD request 297 * @param uri string URI of the document 298 * @return string response status code (200 if ok) 299 * @seeAlso getHeaders() 300 **/ 301 function Head( $uri ) 302 { 303 if( $this->debug & DBGTRACE ) echo "Head( $uri )\n"; 304 $this->responseHeaders = $this->responseBody = ""; 305 $uri = $this->makeUri( $uri ); 306 if( $this->sendCommand( "HEAD $uri HTTP/$this->protocolVersion" ) ) 307 $this->processReply(); 308 return $this->reply; 309 } 310 311 312 /** 313 * get 314 * issue a GET http request 315 * @param uri URI (path on server) or full URL of the document 316 * @return string response status code (200 if ok) 317 * @seeAlso getHeaders(), getBody() 318 **/ 319 function Get( $url ) 320 { 321 if( $this->debug & DBGTRACE ) echo "Get( $url )\n"; 322 $this->responseHeaders = $this->responseBody = ""; 323 $uri = $this->makeUri( $url ); 324 325 if( $this->sendCommand( "GET $uri HTTP/$this->protocolVersion" ) ) 326 $this->processReply(); 327 return $this->reply; 328 } 329 330 /** 331 * Options 332 * issue a OPTIONS http request 333 * @param uri URI (path on server) or full URL of the document 334 * @return array list of options supported by the server or NULL in case of error 335 **/ 336 function Options( $url ) 337 { 338 if( $this->debug & DBGTRACE ) echo "Options( $url )\n"; 339 $this->responseHeaders = $this->responseBody = ""; 340 $uri = $this->makeUri( $url ); 341 342 if( $this->sendCommand( "OPTIONS $uri HTTP/$this->protocolVersion" ) ) 343 $this->processReply(); 344 if( @$this->responseHeaders["Allow"] == NULL ) 345 return NULL; 346 else 347 return explode( ",", $this->responseHeaders["Allow"] ); 348 } 349 350 /** 351 * Post 352 * issue a POST http request 353 * @param uri string URI of the document 354 * @param query_params array parameters to send in the form "parameter name" => value 355 * @return string response status code (200 if ok) 356 * @example 357 * $params = array( "login" => "tiger", "password" => "secret" ); 358 * $http->post( "/login.php", $params ); 359 **/ 360 function Post( $uri, $query_params="" ) 361 { 362 if( $this->debug & DBGTRACE ) echo "Post( $uri, $query_params )\n"; 363 $uri = $this->makeUri( $uri ); 364 if( is_array($query_params) ) { 365 $postArray = array(); 366 foreach( $query_params as $k=>$v ) { 367 $postArray[] = urlencode($k) . "=" . urlencode($v); 368 } 369 $this->requestBody = implode( "&", $postArray); 370 } 371 // set the content type for post parameters 372 $this->addHeader( 'Content-Type', "application/x-www-form-urlencoded" ); 373 // done in sendCommand() $this->addHeader( 'Content-Length', strlen($this->requestBody) ); 374 375 if( $this->sendCommand( "POST $uri HTTP/$this->protocolVersion" ) ) 376 $this->processReply(); 377 $this->removeHeader('Content-Type'); 378 $this->removeHeader('Content-Length'); 379 $this->requestBody = ""; 380 return $this->reply; 381 } 382 383 /** 384 * Put 385 * Send a PUT request 386 * PUT is the method to sending a file on the server. it is *not* widely supported 387 * @param uri the location of the file on the server. dont forget the heading "/" 388 * @param filecontent the content of the file. binary content accepted 389 * @return string response status code 201 (Created) if ok 390 * @see RFC2518 "HTTP Extensions for Distributed Authoring WEBDAV" 391 **/ 392 function Put( $uri, $filecontent ) 393 { 394 if( $this->debug & DBGTRACE ) echo "Put( $uri, [filecontent not displayed )\n"; 395 $uri = $this->makeUri( $uri ); 396 $this->requestBody = $filecontent; 397 if( $this->sendCommand( "PUT $uri HTTP/$this->protocolVersion" ) ) 398 $this->processReply(); 399 return $this->reply; 400 } 401 402 /** 403 * Send a MOVE HTTP-DAV request 404 * Move (rename) a file on the server 405 * @param srcUri the current file location on the server. dont forget the heading "/" 406 * @param destUri the destination location on the server. this is *not* a full URL 407 * @param overwrite boolean - true to overwrite an existing destinationn default if yes 408 * @return string response status code 204 (Unchanged) if ok 409 * @see RFC2518 "HTTP Extensions for Distributed Authoring WEBDAV" 410 **/ 411 function Move( $srcUri, $destUri, $overwrite=true, $scope=0 ) 412 { 413 if( $this->debug & DBGTRACE ) echo "Move( $srcUri, $destUri, $overwrite )\n"; 414 if( $overwrite ) 415 $this->requestHeaders['Overwrite'] = "T"; 416 else 417 $this->requestHeaders['Overwrite'] = "F"; 418 /* 419 $destUrl = $this->url['scheme'] . "://" . $this->url['host']; 420 if( $this->url['port'] != "" ) 421 $destUrl .= ":" . $this->url['port']; 422 $destUrl .= $destUri; 423 $this->requestHeaders['Destination'] = $destUrl; 424 */ 425 $this->requestHeaders['Destination'] = $destUri; 426 $this->requestHeaders['Depth']=$scope; 427 428 if( $this->sendCommand( "MOVE $srcUri HTTP/$this->protocolVersion" ) ) 429 $this->processReply(); 430 return $this->reply; 431 } 432 433 /** 434 * Send a COPY HTTP-DAV request 435 * Copy a file -allready on the server- into a new location 436 * @param srcUri the current file location on the server. dont forget the heading "/" 437 * @param destUri the destination location on the server. this is *not* a full URL 438 * @param overwrite boolean - true to overwrite an existing destination - overwrite by default 439 * @return string response status code 204 (Unchanged) if ok 440 * @see RFC2518 "HTTP Extensions for Distributed Authoring WEBDAV" 441 **/ 442 function Copy( $srcUri, $destUri, $overwrite=true, $scope=0) 443 { 444 if( $this->debug & DBGTRACE ) echo "Copy( $srcUri, $destUri, $overwrite )\n"; 445 if( $overwrite ) 446 $this->requestHeaders['Overwrite'] = "T"; 447 else 448 $this->requestHeaders['Overwrite'] = "F"; 449 450 /* 451 $destUrl = $this->url['scheme'] . "://" . $this->url['host']; 452 if( $this->url['port'] != "" ) 453 $destUrl .= ":" . $this->url['port']; 454 $destUrl .= $destUri; 455 $this->requestHeaders['Destination'] = $destUrl; 456 */ 457 458 $this->requestHeaders['Destination'] = $destUri; 459 $this->requestHeaders['Depth']=$scope; 460 461 if( $this->sendCommand( "COPY $srcUri HTTP/$this->protocolVersion" ) ) 462 $this->processReply(); 463 return $this->reply; 464 } 465 466 467 /** 468 * Send a MKCOL HTTP-DAV request 469 * Create a collection (directory) on the server 470 * @param uri the directory location on the server. dont forget the heading "/" 471 * @return string response status code 201 (Created) if ok 472 * @see RFC2518 "HTTP Extensions for Distributed Authoring WEBDAV" 473 **/ 474 function MkCol( $uri ) 475 { 476 if( $this->debug & DBGTRACE ) echo "Mkcol( $uri )\n"; 477 // $this->requestHeaders['Overwrite'] = "F"; 478 $this->requestHeaders['Depth']=0; 479 if( $this->sendCommand( "MKCOL $uri HTTP/$this->protocolVersion" ) ) 480 $this->processReply(); 481 return $this->reply; 482 } 483 484 /** 485 * Delete a file on the server using the "DELETE" HTTP-DAV request 486 * This HTTP method is *not* widely supported 487 * Only partially supports "collection" deletion, as the XML response is not parsed 488 * @param uri the location of the file on the server. dont forget the heading "/" 489 * @return string response status code 204 (Unchanged) if ok 490 * @see RFC2518 "HTTP Extensions for Distributed Authoring WEBDAV" 491 **/ 492 function Delete( $uri, $scope=0) 493 { 494 if( $this->debug & DBGTRACE ) echo "Delete( $uri )\n"; 495 $this->requestHeaders['Depth'] = $scope; 496 if( $this->sendCommand( "DELETE $uri HTTP/$this->protocolVersion" ) ){ 497 $this->processReply(); 498 } 499 return $this->reply; 500 } 501 502 /** 503 504 * PropFind 505 * implements the PROPFIND method 506 * PROPFIND retrieves meta informations about a resource on the server 507 * XML reply is not parsed, you'll need to do it 508 * @param uri the location of the file on the server. dont forget the heading "/" 509 * @param scope set the scope of the request. 510 * O : infos about the node only 511 * 1 : infos for the node and its direct children ( one level) 512 * Infinity : infos for the node and all its children nodes (recursive) 513 * @return string response status code - 207 (Multi-Status) if OK 514 * @see RFC2518 "HTTP Extensions for Distributed Authoring WEBDAV" 515 **/ 516 function PropFind( $uri, $scope=0 ) 517 { 518 $this->requestBody = ''; 519 if( $this->debug & DBGTRACE ) echo "Propfind( $uri, $scope )\n"; 520 $prev_depth=$this->requestHeaders['Depth']; 521 $this->requestHeaders['Depth'] = $scope; 522 if( $this->sendCommand( "PROPFIND $uri HTTP/$this->protocolVersion" ) ) 523 $this->processReply(); 524 $this->requestHeaders['Depth']=$prev_depth; 525 return $this->reply; 526 } 527 528 529 /** 530 * Lock - WARNING: EXPERIMENTAL 531 * Lock a ressource on the server. XML reply is not parsed, you'll need to do it 532 * @param $uri URL (relative) of the resource to lock 533 * @param $lockScope - use "exclusive" for an eclusive lock, "inclusive" for a shared lock 534 * @param $lockType - acces type of the lock : "write" 535 * @param $lockScope - use "exclusive" for an eclusive lock, "inclusive" for a shared lock 536 * @param $lockOwner - an url representing the owner for this lock 537 * @return server reply code, 200 if ok 538 **/ 539 function Lock( $uri, $lockScope, $lockType, $lockOwner ) 540 { 541 $body = "<?xml version=\"1.0\" encoding=\"utf-8\" ?> 542 <D:lockinfo xmlns:D='DAV:'> 543 <D:lockscope><D:$lockScope/></D:lockscope>\n<D:locktype><D:$lockType/></D:locktype> 544 <D:owner><D:href>$lockOwner</D:href></D:owner> 545 </D:lockinfo>\n"; 546 547 $this->requestBody = utf8_encode( $body ); 548 if( $this->sendCommand( "LOCK $uri HTTP/$this->protocolVersion" ) ) 549 $this->processReply(); 550 return $this->reply; 551 } 552 553 554 /** 555 * Unlock - WARNING: EXPERIMENTAL 556 * unlock a ressource on the server 557 * @param $uri URL (relative) of the resource to unlock 558 * @param $lockToken the lock token given at lock time, eg: opaquelocktoken:e71d4fae-5dec-22d6-fea5-00a0c91e6be4 559 * @return server reply code, 204 if ok 560 **/ 561 function Unlock( $uri, $lockToken ) 562 { 563 $this->addHeader( "Lock-Token", "<$lockToken>" ); 564 if( $this->sendCommand( "UNLOCK $uri HTTP/$this->protocolVersion" ) ) 565 $this->processReply(); 566 return $this->reply; 567 } 568 569 /** 570 * getHeaders 571 * return the response headers 572 * to be called after a Get() or Head() call 573 * @return array headers received from server in the form headername => value 574 * @seeAlso get, head 575 **/ 576 function getHeaders() 577 { 578 if( $this->debug & DBGTRACE ) echo "getHeaders()\n"; 579 if( $this->debug & DBGINDATA ) { 580 echo "DBG.INDATA responseHeaders="; print_r( $this->responseHeaders ); 581 } 582 return $this->responseHeaders; 583 } 584 585 /** 586 * getHeader 587 * return the response header "headername" 588 * @param headername the name of the header 589 * @return header value or NULL if no such header is defined 590 **/ 591 function getHeader( $headername ) 592 { 593 if( $this->debug & DBGTRACE ) echo "getHeaderName( $headername )\n"; 594 return $this->responseHeaders[$headername]; 595 } 596 597 /** 598 * getBody 599 * return the response body 600 * invoke it after a Get() call for instance, to retrieve the response 601 * @return string body content 602 * @seeAlso get, head 603 **/ 604 function getBody() 605 { 606 if( $this->debug & DBGTRACE ) echo "getBody()\n"; 607 return $this->responseBody; 608 } 609 610 /** 611 * getStatus return the server response's status code 612 * @return string a status code 613 * code are divided in classes (where x is a digit) 614 * - 20x : request processed OK 615 * - 30x : document moved 616 * - 40x : client error ( bad url, document not found, etc...) 617 * - 50x : server error 618 * @see RFC2616 "Hypertext Transfer Protocol -- HTTP/1.1" 619 **/ 620 function getStatus() 621 { 622 return $this->reply; 623 } 624 625 626 /** 627 * getStatusMessage return the full response status, of the form "CODE Message" 628 * eg. "404 Document not found" 629 * @return string the message 630 **/ 631 function getStatusMessage() 632 { 633 return $this->replyString; 634 } 635 636 637 638 639 /********************************************* 640 * @scope only protected or private methods below 641 **/ 642 643 /** 644 * send a request 645 * data sent are in order 646 * a) the command 647 * b) the request headers if they are defined 648 * c) the request body if defined 649 * @return string the server repsonse status code 650 **/ 651 function sendCommand( $command ) 652 { 653 if( $this->debug & DBGLOW ) echo "sendCommand( $command )\n"; 654 $this->responseHeaders = array(); 655 $this->responseBody = ""; 656 // connect if necessary 657 if( $this->socket == false or feof( $this->socket) ) { 658 659 if( $this->useProxy ) { 660 $host = $this->proxyHost; 661 $port = $this->proxyPort; 662 } else { 663 $host = $this->url['host']; 664 $port = $this->url['port']; 665 } 666 if( $port == "" ) $port = 80; 667 $this->socket = fsockopen( $host, $port, &$this->reply, &$this->replyString ); 668 if( $this->debug & DBGSOCK ) echo "connexion( $host, $port) - $this->socket\n"; 669 if( ! $this->socket ) { 670 if( $this->debug & DBGSOCK ) echo "FAILED : $this->replyString ($this->reply)\n"; 671 return false; 672 } 673 } 674 675 if( $this->requestBody != "" ) { 676 $this->addHeader( "Content-Length", strlen( $this->requestBody ) ); 677 } 678 else { 679 $this->removeHeader( "Content-Length"); 680 } 681 682 $this->request = $command; 683 $cmd = $command . CRLF; 684 if( is_array( $this->requestHeaders) ) { 685 foreach( $this->requestHeaders as $k => $v ) { 686 $cmd .= "$k: $v" . CRLF; 687 } 688 } 689 690 if( $this->requestBody != "" ) { 691 $cmd .= CRLF . $this->requestBody; 692 } 693 694 // unset body (in case of successive requests) 695 $this->requestBody = ""; 696 if( $this->debug & DBGOUTDATA ) echo "DBG.OUTDATA Sending\n$cmd\n"; 697 698 fputs( $this->socket, $cmd . CRLF ); 699 return true; 700 } 701 702 function processReply() 703 { 704 if( $this->debug & DBGLOW ) echo "processReply()\n"; 705 706 $this->replyString = trim(fgets( $this->socket,1024) ); 707 if( preg_match( "|^HTTP/\S+ (\d+) |i", $this->replyString, $a )) { 708 $this->reply = $a[1]; 709 } else { 710 $this->reply = EBADRESPONSE; 711 } 712 if( $this->debug & DBGINDATA ) echo "replyLine: $this->replyString\n"; 713 714 // get response headers and body 715 $this->responseHeaders = $this->processHeader(); 716 $this->responseBody = $this->processBody(); 717 if ($this->responseHeaders['Connection'] == 'close') { 718 if( $this->debug & DBGINDATA ) echo "connection closed at server request!"; 719 fclose($this->socket); 720 $this->socket=false; 721 } 722 723 // if( $this->responseHeaders['set-cookie'] ) 724 // $this->addHeader( "cookie", $this->responseHeaders['set-cookie'] ); 725 return $this->reply; 726 } 727 728 /** 729 * processHeader() reads header lines from socket until the line equals $lastLine 730 * @scope protected 731 * @return array of headers with header names as keys and header content as values 732 **/ 733 function processHeader( $lastLine = CRLF ) 734 { 735 if( $this->debug & DBGLOW ) echo "processHeader( [lastLine] )\n"; 736 $headers = array(); 737 $finished = false; 738 739 while ( ( ! $finished ) && ( ! feof($this->socket)) ) { 740 $str = fgets( $this->socket, 1024 ); 741 if( $this->debug & DBGINDATA ) echo "HEADER : $str;"; 742 $finished = ( $str == $lastLine ); 743 if ( !$finished ) { 744 list( $hdr, $value ) = split( ": ", $str, 2 ); 745 // nasty workaround broken multiple same headers (eg. Set-Cookie headers) @FIXME 746 if( isset( $headers[$hdr]) ) 747 $headers[$hdr] .= "; " . trim($value); 748 else 749 $headers[$hdr] = trim($value); 750 } 751 } 752 return $headers; 753 } 754 755 /** 756 * processBody() reads the body from the socket 757 * the body is the "real" content of the reply 758 * @return string body content 759 * @scope private 760 **/ 761 function processBody() 762 { 763 $failureCount = 0; 764 765 $data=''; 766 if( $this->debug & DBGLOW ) echo "processBody()\n"; 767 768 if ( $this->responseHeaders['Transfer-Encoding']=='chunked' ) 769 { 770 // chunked encoding 771 if( $this->debug & DBGSOCK ) echo "DBG.SOCK chunked encoding..\n"; 772 $length = fgets($this->socket, 1024); 773 $length = hexdec($length); 774 775 while (true) { 776 if ($length == 0) { break; } 777 $data .= fread($this->socket, $length); 778 if( $this->debug & DBGSOCK ) echo "DBG.SOCK chunked encoding: read $length bytes\n"; 779 fgets($this->socket, 1024); 780 $length = fgets($this->socket, 1024); 781 $length = hexdec($length); 782 } 783 fgets($this->socket, 1024); 784 785 } 786 else if ($this->responseHeaders['Content-Length'] ) 787 { 788 $length = $this->responseHeaders['Content-Length']; 789 while (!feof($this->socket)) { 790 $data .= fread($this->socket, 1024); 791 } 792 if( $this->debug & DBGSOCK ) echo "DBG.SOCK socket_read using Content-Length ($length)\n"; 793 794 } 795 else { 796 if( $this->debug & DBGSOCK ) echo "Not chunked, dont know how big?..\n"; 797 $data = ""; 798 $counter = 0; 799 socket_set_blocking( $this->socket, true ); 800 socket_set_timeout($this->socket,2); 801 $ts1=time(); 802 do{ 803 $status = socket_get_status( $this->socket ); 804 /* if( $this->debug & DBGSOCK ) 805 echo " Socket status: "; print_r($status); 806 */ if( feof($this->socket)) { 807 if( $this->debug & DBGSOCK ) echo "DBG.SOCK eof met, finished socket_read\n"; 808 break; 809 } 810 if( $status['unread_bytes'] > 0 ) { 811 $buffer = fread( $this->socket, $status['unread_bytes'] ); 812 $counter = 0; 813 } else { 814 $ts=time(); 815 $buffer = fread( $this->socket, 1024 ); 816 817 sleep(0.1); 818 $failureCount++; 819 //print "elapsed ".(time()-$ts)."<br>"; 820 } 821 $data .= $buffer; 822 823 824 } while( $status['unread_bytes'] > 0 || $counter++ < 10 ); 825 //print "total ".(time()-$ts1)."<br>"; 826 827 if( $this->debug & DBGSOCK ) { 828 echo "DBG.SOCK Counter:$counter\nRead failure #: $failureCount\n"; 829 echo " Socket status: "; print_r($status); 830 } 831 socket_set_blocking( $this->socket, true ); 832 } 833 $len = strlen($data); 834 if( $this->debug & DBGSOCK ) echo "DBG.SOCK read $len bytes"; 835 836 return $data; 837 } 838 839 840 /** 841 * Calculate and return the URI to be sent ( proxy purpose ) 842 * @param the local URI 843 * @return URI to be used in the HTTP request 844 * @scope private 845 **/ 846 847 function makeUri( $uri ) 848 { 849 $a = parse_url( $uri ); 850 851 if( isset($a['scheme']) && isset($a['host']) ) { 852 $this->url = $a; 853 } else { 854 unset( $this->url['query']); 855 unset( $this->url['fragment']); 856 $this->url = array_merge( $this->url, $a ); 857 } 858 if( $this->useProxy ) { 859 $requesturi= "http://" . $this->url['host'] . ( empty($this->url['port']) ? "" : ":" . $this->url['port'] ) . $this->url['path'] . ( empty($this->url['query']) ? "" : "?" . $this->url['query'] ); 860 } else { 861 $requesturi = $this->url['path'] . (empty( $this->url['query'] ) ? "" : "?" . $this->url['query']); 862 } 863 return $requesturi; 864 } 865 866 } // end class net_http_client 867 868 869 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Sun Feb 25 17:20:01 2007 | par Balluche grâce à PHPXref 0.7 |