source: trunk/phpgwapi/inc/class.net_http_client.inc.php @ 6057

Revision 6057, 26.0 KB checked in by marcosw, 12 years ago (diff)

Ticket #2398 - Compatibilizacao com PHP-5.3 em alguns módulos do expresso

  • Property svn:eol-style set to native
  • Property svn:executable set to *
Line 
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 )
94define( "DBGTRACE", 1 ); // to debug methods calls
95define( "DBGINDATA", 2 ); // to debug data received
96define( "DBGOUTDATA", 4 ); // to debug data sent
97define( "DBGLOW", 8 ); // to debug low-level (usually internal) methods
98define( "DBGSOCK", 16 ); // to debug socket-level code
99
100/// internal errors
101define( "ECONNECTION", -1 ); // connection failed
102define( "EBADRESPONSE", -2 ); // response status line is not http compliant
103
104define( "CRLF", "\r\n" );
105
106
107class 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 ) = preg_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?>
Note: See TracBrowser for help on using the repository browser.