Ignore:
Timestamp:
2006/10/26 18:36:12 (20 years ago)
Author:
kakinaka
Message:

* empty log message *

File:
1 edited

Legend:

Unmodified
Added
Removed
  • temp/trunk/data/module/Request.php

    r6907 r6908  
    5353//require_once REQUEST_PHP_DIR . '/Net/URL.php'; 
    5454 
    55 require_once 'PEAR.php'; 
    56  
     55require_once 'Net/Socket.php'; 
     56require_once 'Net/URL.php'; 
     57 
     58define('HTTP_REQUEST_METHOD_GET',     'GET',     true); 
     59define('HTTP_REQUEST_METHOD_HEAD',    'HEAD',    true); 
     60define('HTTP_REQUEST_METHOD_POST',    'POST',    true); 
     61define('HTTP_REQUEST_METHOD_PUT',     'PUT',     true); 
     62define('HTTP_REQUEST_METHOD_DELETE',  'DELETE',  true); 
     63define('HTTP_REQUEST_METHOD_OPTIONS', 'OPTIONS', true); 
     64define('HTTP_REQUEST_METHOD_TRACE',   'TRACE',   true); 
     65 
     66define('HTTP_REQUEST_HTTP_VER_1_0', '1.0', true); 
     67define('HTTP_REQUEST_HTTP_VER_1_1', '1.1', true); 
     68 
     69class HTTP_Request { 
     70 
     71    /** 
     72    * Instance of Net_URL 
     73    * @var object Net_URL 
     74    */ 
     75    var $_url; 
     76 
     77    /** 
     78    * Type of request 
     79    * @var string 
     80    */ 
     81    var $_method; 
     82 
     83    /** 
     84    * HTTP Version 
     85    * @var string 
     86    */ 
     87    var $_http; 
     88 
     89    /** 
     90    * Request headers 
     91    * @var array 
     92    */ 
     93    var $_requestHeaders; 
     94 
     95    /** 
     96    * Basic Auth Username 
     97    * @var string 
     98    */ 
     99    var $_user; 
     100     
     101    /** 
     102    * Basic Auth Password 
     103    * @var string 
     104    */ 
     105    var $_pass; 
     106 
     107    /** 
     108    * Socket object 
     109    * @var object Net_Socket 
     110    */ 
     111    var $_sock; 
     112     
     113    /** 
     114    * Proxy server 
     115    * @var string 
     116    */ 
     117    var $_proxy_host; 
     118     
     119    /** 
     120    * Proxy port 
     121    * @var integer 
     122    */ 
     123    var $_proxy_port; 
     124     
     125    /** 
     126    * Proxy username 
     127    * @var string 
     128    */ 
     129    var $_proxy_user; 
     130     
     131    /** 
     132    * Proxy password 
     133    * @var string 
     134    */ 
     135    var $_proxy_pass; 
     136 
     137    /** 
     138    * Post data 
     139    * @var array 
     140    */ 
     141    var $_postData; 
     142 
     143   /** 
     144    * Request body   
     145    * @var string 
     146    */ 
     147    var $_body; 
     148 
     149   /** 
     150    * A list of methods that MUST NOT have a request body, per RFC 2616 
     151    * @var array 
     152    */ 
     153    var $_bodyDisallowed = array('TRACE'); 
     154 
     155   /** 
     156    * Files to post  
     157    * @var array 
     158    */ 
     159    var $_postFiles = array(); 
     160 
     161    /** 
     162    * Connection timeout. 
     163    * @var float 
     164    */ 
     165    var $_timeout; 
     166     
     167    /** 
     168    * HTTP_Response object 
     169    * @var object HTTP_Response 
     170    */ 
     171    var $_response; 
     172     
     173    /** 
     174    * Whether to allow redirects 
     175    * @var boolean 
     176    */ 
     177    var $_allowRedirects; 
     178     
     179    /** 
     180    * Maximum redirects allowed 
     181    * @var integer 
     182    */ 
     183    var $_maxRedirects; 
     184     
     185    /** 
     186    * Current number of redirects 
     187    * @var integer 
     188    */ 
     189    var $_redirects; 
     190 
     191   /** 
     192    * Whether to append brackets [] to array variables 
     193    * @var bool 
     194    */ 
     195    var $_useBrackets = true; 
     196 
     197   /** 
     198    * Attached listeners 
     199    * @var array 
     200    */ 
     201    var $_listeners = array(); 
     202 
     203   /** 
     204    * Whether to save response body in response object property   
     205    * @var bool 
     206    */ 
     207    var $_saveBody = true; 
     208 
     209   /** 
     210    * Timeout for reading from socket (array(seconds, microseconds)) 
     211    * @var array 
     212    */ 
     213    var $_readTimeout = null; 
     214 
     215   /** 
     216    * Options to pass to Net_Socket::connect. See stream_context_create 
     217    * @var array 
     218    */ 
     219    var $_socketOptions = null; 
     220 
     221    /** 
     222    * Constructor 
     223    * 
     224    * Sets up the object 
     225    * @param    string  The url to fetch/access 
     226    * @param    array   Associative array of parameters which can have the following keys: 
     227    * <ul> 
     228    *   <li>method         - Method to use, GET, POST etc (string)</li> 
     229    *   <li>http           - HTTP Version to use, 1.0 or 1.1 (string)</li> 
     230    *   <li>user           - Basic Auth username (string)</li> 
     231    *   <li>pass           - Basic Auth password (string)</li> 
     232    *   <li>proxy_host     - Proxy server host (string)</li> 
     233    *   <li>proxy_port     - Proxy server port (integer)</li> 
     234    *   <li>proxy_user     - Proxy auth username (string)</li> 
     235    *   <li>proxy_pass     - Proxy auth password (string)</li> 
     236    *   <li>timeout        - Connection timeout in seconds (float)</li> 
     237    *   <li>allowRedirects - Whether to follow redirects or not (bool)</li> 
     238    *   <li>maxRedirects   - Max number of redirects to follow (integer)</li> 
     239    *   <li>useBrackets    - Whether to append [] to array variable names (bool)</li> 
     240    *   <li>saveBody       - Whether to save response body in response object property (bool)</li> 
     241    *   <li>readTimeout    - Timeout for reading / writing data over the socket (array (seconds, microseconds))</li> 
     242    *   <li>socketOptions  - Options to pass to Net_Socket object (array)</li> 
     243    * </ul> 
     244    * @access public 
     245    */ 
     246    function HTTP_Request($url = '', $params = array()) 
     247    { 
     248        $this->_method         =  HTTP_REQUEST_METHOD_GET; 
     249        $this->_http           =  HTTP_REQUEST_HTTP_VER_1_1; 
     250        $this->_requestHeaders = array(); 
     251        $this->_postData       = array(); 
     252        $this->_body           = null; 
     253 
     254        $this->_user = null; 
     255        $this->_pass = null; 
     256 
     257        $this->_proxy_host = null; 
     258        $this->_proxy_port = null; 
     259        $this->_proxy_user = null; 
     260        $this->_proxy_pass = null; 
     261 
     262        $this->_allowRedirects = false; 
     263        $this->_maxRedirects   = 3; 
     264        $this->_redirects      = 0; 
     265 
     266        $this->_timeout  = null; 
     267        $this->_response = null; 
     268 
     269        foreach ($params as $key => $value) { 
     270            $this->{'_' . $key} = $value; 
     271        } 
     272 
     273        if (!empty($url)) { 
     274            $this->setURL($url); 
     275        } 
     276 
     277        // Default useragent 
     278        $this->addHeader('User-Agent', 'PEAR HTTP_Request class ( http://pear.php.net/ )'); 
     279 
     280        // We don't do keep-alives by default 
     281        $this->addHeader('Connection', 'close'); 
     282 
     283        // Basic authentication 
     284        if (!empty($this->_user)) { 
     285            $this->addHeader('Authorization', 'Basic ' . base64_encode($this->_user . ':' . $this->_pass)); 
     286        } 
     287 
     288        // Proxy authentication (see bug #5913) 
     289        if (!empty($this->_proxy_user)) { 
     290            $this->addHeader('Proxy-Authorization', 'Basic ' . base64_encode($this->_proxy_user . ':' . $this->_proxy_pass)); 
     291        } 
     292 
     293        // Use gzip encoding if possible 
     294        // Avoid gzip encoding if using multibyte functions (see #1781) 
     295        if (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http && extension_loaded('zlib') && 
     296            0 == (2 & ini_get('mbstring.func_overload'))) { 
     297 
     298            $this->addHeader('Accept-Encoding', 'gzip'); 
     299        } 
     300    } 
     301     
     302    /** 
     303    * Generates a Host header for HTTP/1.1 requests 
     304    * 
     305    * @access private 
     306    * @return string 
     307    */ 
     308    function _generateHostHeader() 
     309    { 
     310        if ($this->_url->port != 80 AND strcasecmp($this->_url->protocol, 'http') == 0) { 
     311            $host = $this->_url->host . ':' . $this->_url->port; 
     312 
     313        } elseif ($this->_url->port != 443 AND strcasecmp($this->_url->protocol, 'https') == 0) { 
     314            $host = $this->_url->host . ':' . $this->_url->port; 
     315 
     316        } elseif ($this->_url->port == 443 AND strcasecmp($this->_url->protocol, 'https') == 0 AND strpos($this->_url->url, ':443') !== false) { 
     317            $host = $this->_url->host . ':' . $this->_url->port; 
     318         
     319        } else { 
     320            $host = $this->_url->host; 
     321        } 
     322 
     323        return $host; 
     324    } 
     325     
     326    /** 
     327    * Resets the object to its initial state (DEPRECATED). 
     328    * Takes the same parameters as the constructor. 
     329    * 
     330    * @param  string $url    The url to be requested 
     331    * @param  array  $params Associative array of parameters 
     332    *                        (see constructor for details) 
     333    * @access public 
     334    * @deprecated deprecated since 1.2, call the constructor if this is necessary 
     335    */ 
     336    function reset($url, $params = array()) 
     337    { 
     338        $this->HTTP_Request($url, $params); 
     339    } 
     340 
     341    /** 
     342    * Sets the URL to be requested 
     343    * 
     344    * @param  string The url to be requested 
     345    * @access public 
     346    */ 
     347    function setURL($url) 
     348    { 
     349        $this->_url = &new Net_URL($url, $this->_useBrackets); 
     350 
     351        if (!empty($this->_url->user) || !empty($this->_url->pass)) { 
     352            $this->setBasicAuth($this->_url->user, $this->_url->pass); 
     353        } 
     354 
     355        if (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http) { 
     356            $this->addHeader('Host', $this->_generateHostHeader()); 
     357        } 
     358 
     359        // set '/' instead of empty path rather than check later (see bug #8662) 
     360        if (empty($this->_url->path)) { 
     361            $this->_url->path = '/'; 
     362        }  
     363    } 
     364     
     365   /** 
     366    * Returns the current request URL   
     367    * 
     368    * @return   string  Current request URL 
     369    * @access   public 
     370    */ 
     371    function getUrl($url) 
     372    { 
     373        return empty($this->_url)? '': $this->_url->getUrl(); 
     374    } 
     375 
     376    /** 
     377    * Sets a proxy to be used 
     378    * 
     379    * @param string     Proxy host 
     380    * @param int        Proxy port 
     381    * @param string     Proxy username 
     382    * @param string     Proxy password 
     383    * @access public 
     384    */ 
     385    function setProxy($host, $port = 8080, $user = null, $pass = null) 
     386    { 
     387        $this->_proxy_host = $host; 
     388        $this->_proxy_port = $port; 
     389        $this->_proxy_user = $user; 
     390        $this->_proxy_pass = $pass; 
     391 
     392        if (!empty($user)) { 
     393            $this->addHeader('Proxy-Authorization', 'Basic ' . base64_encode($user . ':' . $pass)); 
     394        } 
     395    } 
     396 
     397    /** 
     398    * Sets basic authentication parameters 
     399    * 
     400    * @param string     Username 
     401    * @param string     Password 
     402    */ 
     403    function setBasicAuth($user, $pass) 
     404    { 
     405        $this->_user = $user; 
     406        $this->_pass = $pass; 
     407 
     408        $this->addHeader('Authorization', 'Basic ' . base64_encode($user . ':' . $pass)); 
     409    } 
     410 
     411    /** 
     412    * Sets the method to be used, GET, POST etc. 
     413    * 
     414    * @param string     Method to use. Use the defined constants for this 
     415    * @access public 
     416    */ 
     417    function setMethod($method) 
     418    { 
     419        $this->_method = $method; 
     420    } 
     421 
     422    /** 
     423    * Sets the HTTP version to use, 1.0 or 1.1 
     424    * 
     425    * @param string     Version to use. Use the defined constants for this 
     426    * @access public 
     427    */ 
     428    function setHttpVer($http) 
     429    { 
     430        $this->_http = $http; 
     431    } 
     432 
     433    /** 
     434    * Adds a request header 
     435    * 
     436    * @param string     Header name 
     437    * @param string     Header value 
     438    * @access public 
     439    */ 
     440    function addHeader($name, $value) 
     441    { 
     442        $this->_requestHeaders[strtolower($name)] = $value; 
     443    } 
     444 
     445    /** 
     446    * Removes a request header 
     447    * 
     448    * @param string     Header name to remove 
     449    * @access public 
     450    */ 
     451    function removeHeader($name) 
     452    { 
     453        if (isset($this->_requestHeaders[strtolower($name)])) { 
     454            unset($this->_requestHeaders[strtolower($name)]); 
     455        } 
     456    } 
     457 
     458    /** 
     459    * Adds a querystring parameter 
     460    * 
     461    * @param string     Querystring parameter name 
     462    * @param string     Querystring parameter value 
     463    * @param bool       Whether the value is already urlencoded or not, default = not 
     464    * @access public 
     465    */ 
     466    function addQueryString($name, $value, $preencoded = false) 
     467    { 
     468        $this->_url->addQueryString($name, $value, $preencoded); 
     469    }     
     470     
     471    /** 
     472    * Sets the querystring to literally what you supply 
     473    * 
     474    * @param string     The querystring data. Should be of the format foo=bar&x=y etc 
     475    * @param bool       Whether data is already urlencoded or not, default = already encoded 
     476    * @access public 
     477    */ 
     478    function addRawQueryString($querystring, $preencoded = true) 
     479    { 
     480        $this->_url->addRawQueryString($querystring, $preencoded); 
     481    } 
     482 
     483    /** 
     484    * Adds postdata items 
     485    * 
     486    * @param string     Post data name 
     487    * @param string     Post data value 
     488    * @param bool       Whether data is already urlencoded or not, default = not 
     489    * @access public 
     490    */ 
     491    function addPostData($name, $value, $preencoded = false) 
     492    { 
     493        if ($preencoded) { 
     494            $this->_postData[$name] = $value; 
     495        } else { 
     496            $this->_postData[$name] = $this->_arrayMapRecursive('urlencode', $value); 
     497        } 
     498    } 
     499 
     500   /** 
     501    * Recursively applies the callback function to the value 
     502    *  
     503    * @param    mixed   Callback function 
     504    * @param    mixed   Value to process 
     505    * @access   private 
     506    * @return   mixed   Processed value 
     507    */ 
     508    function _arrayMapRecursive($callback, $value) 
     509    { 
     510        if (!is_array($value)) { 
     511            return call_user_func($callback, $value); 
     512        } else { 
     513            $map = array(); 
     514            foreach ($value as $k => $v) { 
     515                $map[$k] = $this->_arrayMapRecursive($callback, $v); 
     516            } 
     517            return $map; 
     518        } 
     519    } 
     520 
     521   /** 
     522    * Adds a file to upload 
     523    *  
     524    * This also changes content-type to 'multipart/form-data' for proper upload 
     525    *  
     526    * @access public 
     527    * @param  string    name of file-upload field 
     528    * @param  mixed     file name(s) 
     529    * @param  mixed     content-type(s) of file(s) being uploaded 
     530    * @return bool      true on success 
     531    * @throws PEAR_Error 
     532    */ 
     533    function addFile($inputName, $fileName, $contentType = 'application/octet-stream') 
     534    { 
     535        if (!is_array($fileName) && !is_readable($fileName)) { 
     536            return PEAR::raiseError("File '{$fileName}' is not readable"); 
     537        } elseif (is_array($fileName)) { 
     538            foreach ($fileName as $name) { 
     539                if (!is_readable($name)) { 
     540                    return PEAR::raiseError("File '{$name}' is not readable"); 
     541                } 
     542            } 
     543        } 
     544        $this->addHeader('Content-Type', 'multipart/form-data'); 
     545        $this->_postFiles[$inputName] = array( 
     546            'name' => $fileName, 
     547            'type' => $contentType 
     548        ); 
     549        return true; 
     550    } 
     551 
     552    /** 
     553    * Adds raw postdata (DEPRECATED) 
     554    * 
     555    * @param string     The data 
     556    * @param bool       Whether data is preencoded or not, default = already encoded 
     557    * @access public 
     558    * @deprecated       deprecated since 1.3.0, method setBody() should be used instead 
     559    */ 
     560    function addRawPostData($postdata, $preencoded = true) 
     561    { 
     562        $this->_body = $preencoded ? $postdata : urlencode($postdata); 
     563    } 
     564 
     565   /** 
     566    * Sets the request body (for POST, PUT and similar requests) 
     567    * 
     568    * @param    string  Request body 
     569    * @access   public 
     570    */ 
     571    function setBody($body) 
     572    { 
     573        $this->_body = $body; 
     574    } 
     575 
     576    /** 
     577    * Clears any postdata that has been added (DEPRECATED).  
     578    *  
     579    * Useful for multiple request scenarios. 
     580    * 
     581    * @access public 
     582    * @deprecated deprecated since 1.2 
     583    */ 
     584    function clearPostData() 
     585    { 
     586        $this->_postData = null; 
     587    } 
     588 
     589    /** 
     590    * Appends a cookie to "Cookie:" header 
     591    *  
     592    * @param string $name cookie name 
     593    * @param string $value cookie value 
     594    * @access public 
     595    */ 
     596    function addCookie($name, $value) 
     597    { 
     598        $cookies = isset($this->_requestHeaders['cookie']) ? $this->_requestHeaders['cookie']. '; ' : ''; 
     599        $this->addHeader('Cookie', $cookies . $name . '=' . $value); 
     600    } 
     601     
     602    /** 
     603    * Clears any cookies that have been added (DEPRECATED).  
     604    *  
     605    * Useful for multiple request scenarios 
     606    * 
     607    * @access public 
     608    * @deprecated deprecated since 1.2 
     609    */ 
     610    function clearCookies() 
     611    { 
     612        $this->removeHeader('Cookie'); 
     613    } 
     614 
     615    /** 
     616    * Sends the request 
     617    * 
     618    * @access public 
     619    * @param  bool   Whether to store response body in Response object property, 
     620    *                set this to false if downloading a LARGE file and using a Listener 
     621    * @return mixed  PEAR error on error, true otherwise 
     622    */ 
     623    function sendRequest($saveBody = true) 
     624    { 
     625        if (!is_a($this->_url, 'Net_URL')) { 
     626            return PEAR::raiseError('No URL given.'); 
     627        } 
     628 
     629        $host = isset($this->_proxy_host) ? $this->_proxy_host : $this->_url->host; 
     630        $port = isset($this->_proxy_port) ? $this->_proxy_port : $this->_url->port; 
     631 
     632        // 4.3.0 supports SSL connections using OpenSSL. The function test determines 
     633        // we running on at least 4.3.0 
     634        if (strcasecmp($this->_url->protocol, 'https') == 0 AND function_exists('file_get_contents') AND extension_loaded('openssl')) { 
     635            if (isset($this->_proxy_host)) { 
     636                return PEAR::raiseError('HTTPS proxies are not supported.'); 
     637            } 
     638            $host = 'ssl://' . $host; 
     639        } 
     640 
     641        // magic quotes may fuck up file uploads and chunked response processing 
     642        $magicQuotes = ini_get('magic_quotes_runtime'); 
     643        ini_set('magic_quotes_runtime', false); 
     644 
     645        // RFC 2068, section 19.7.1: A client MUST NOT send the Keep-Alive  
     646        // connection token to a proxy server... 
     647        if (isset($this->_proxy_host) && !empty($this->_requestHeaders['connection']) && 
     648            'Keep-Alive' == $this->_requestHeaders['connection']) 
     649        { 
     650            $this->removeHeader('connection'); 
     651        } 
     652 
     653        $keepAlive = (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http && empty($this->_requestHeaders['connection'])) || 
     654                     (!empty($this->_requestHeaders['connection']) && 'Keep-Alive' == $this->_requestHeaders['connection']); 
     655        $sockets   = &PEAR::getStaticProperty('HTTP_Request', 'sockets'); 
     656        $sockKey   = $host . ':' . $port; 
     657        unset($this->_sock); 
     658 
     659        // There is a connected socket in the "static" property? 
     660        if ($keepAlive && !empty($sockets[$sockKey]) && 
     661            !empty($sockets[$sockKey]->fp))  
     662        { 
     663            $this->_sock =& $sockets[$sockKey]; 
     664            $err = null; 
     665        } else { 
     666            $this->_notify('connect'); 
     667            $this->_sock =& new Net_Socket(); 
     668            $err = $this->_sock->connect($host, $port, null, $this->_timeout, $this->_socketOptions); 
     669        } 
     670        PEAR::isError($err) or $err = $this->_sock->write($this->_buildRequest()); 
     671 
     672        if (!PEAR::isError($err)) { 
     673            if (!empty($this->_readTimeout)) { 
     674                $this->_sock->setTimeout($this->_readTimeout[0], $this->_readTimeout[1]); 
     675            } 
     676 
     677            $this->_notify('sentRequest'); 
     678 
     679            // Read the response 
     680            $this->_response = &new HTTP_Response($this->_sock, $this->_listeners); 
     681            $err = $this->_response->process( 
     682                $this->_saveBody && $saveBody, 
     683                HTTP_REQUEST_METHOD_HEAD != $this->_method 
     684            ); 
     685 
     686            if ($keepAlive) { 
     687                $keepAlive = (isset($this->_response->_headers['content-length']) 
     688                              || (isset($this->_response->_headers['transfer-encoding']) 
     689                                  && strtolower($this->_response->_headers['transfer-encoding']) == 'chunked')); 
     690                if ($keepAlive) { 
     691                    if (isset($this->_response->_headers['connection'])) { 
     692                        $keepAlive = strtolower($this->_response->_headers['connection']) == 'keep-alive'; 
     693                    } else { 
     694                        $keepAlive = 'HTTP/'.HTTP_REQUEST_HTTP_VER_1_1 == $this->_response->_protocol; 
     695                    } 
     696                } 
     697            } 
     698        } 
     699 
     700        ini_set('magic_quotes_runtime', $magicQuotes); 
     701 
     702        if (PEAR::isError($err)) { 
     703            return $err; 
     704        } 
     705 
     706        if (!$keepAlive) { 
     707            $this->disconnect(); 
     708        // Store the connected socket in "static" property 
     709        } elseif (empty($sockets[$sockKey]) || empty($sockets[$sockKey]->fp)) { 
     710            $sockets[$sockKey] =& $this->_sock; 
     711        } 
     712 
     713        // Check for redirection 
     714        if (    $this->_allowRedirects 
     715            AND $this->_redirects <= $this->_maxRedirects 
     716            AND $this->getResponseCode() > 300 
     717            AND $this->getResponseCode() < 399 
     718            AND !empty($this->_response->_headers['location'])) { 
     719 
     720             
     721            $redirect = $this->_response->_headers['location']; 
     722 
     723            // Absolute URL 
     724            if (preg_match('/^https?:\/\//i', $redirect)) { 
     725                $this->_url = &new Net_URL($redirect); 
     726                $this->addHeader('Host', $this->_generateHostHeader()); 
     727            // Absolute path 
     728            } elseif ($redirect{0} == '/') { 
     729                $this->_url->path = $redirect; 
     730             
     731            // Relative path 
     732            } elseif (substr($redirect, 0, 3) == '../' OR substr($redirect, 0, 2) == './') { 
     733                if (substr($this->_url->path, -1) == '/') { 
     734                    $redirect = $this->_url->path . $redirect; 
     735                } else { 
     736                    $redirect = dirname($this->_url->path) . '/' . $redirect; 
     737                } 
     738                $redirect = Net_URL::resolvePath($redirect); 
     739                $this->_url->path = $redirect; 
     740                 
     741            // Filename, no path 
     742            } else { 
     743                if (substr($this->_url->path, -1) == '/') { 
     744                    $redirect = $this->_url->path . $redirect; 
     745                } else { 
     746                    $redirect = dirname($this->_url->path) . '/' . $redirect; 
     747                } 
     748                $this->_url->path = $redirect; 
     749            } 
     750 
     751            $this->_redirects++; 
     752            return $this->sendRequest($saveBody); 
     753 
     754        // Too many redirects 
     755        } elseif ($this->_allowRedirects AND $this->_redirects > $this->_maxRedirects) { 
     756            return PEAR::raiseError('Too many redirects'); 
     757        } 
     758 
     759        return true; 
     760    } 
     761 
     762    /** 
     763     * Disconnect the socket, if connected. Only useful if using Keep-Alive. 
     764     * 
     765     * @access public 
     766     */ 
     767    function disconnect() 
     768    { 
     769        if (!empty($this->_sock) && !empty($this->_sock->fp)) { 
     770            $this->_notify('disconnect'); 
     771            $this->_sock->disconnect(); 
     772        } 
     773    } 
     774 
     775    /** 
     776    * Returns the response code 
     777    * 
     778    * @access public 
     779    * @return mixed     Response code, false if not set 
     780    */ 
     781    function getResponseCode() 
     782    { 
     783        return isset($this->_response->_code) ? $this->_response->_code : false; 
     784    } 
     785 
     786    /** 
     787    * Returns either the named header or all if no name given 
     788    * 
     789    * @access public 
     790    * @param string     The header name to return, do not set to get all headers 
     791    * @return mixed     either the value of $headername (false if header is not present) 
     792    *                   or an array of all headers 
     793    */ 
     794    function getResponseHeader($headername = null) 
     795    { 
     796        if (!isset($headername)) { 
     797            return isset($this->_response->_headers)? $this->_response->_headers: array(); 
     798        } else { 
     799            $headername = strtolower($headername); 
     800            return isset($this->_response->_headers[$headername]) ? $this->_response->_headers[$headername] : false; 
     801        } 
     802    } 
     803 
     804    /** 
     805    * Returns the body of the response 
     806    * 
     807    * @access public 
     808    * @return mixed     response body, false if not set 
     809    */ 
     810    function getResponseBody() 
     811    { 
     812        return isset($this->_response->_body) ? $this->_response->_body : false; 
     813    } 
     814 
     815    /** 
     816    * Returns cookies set in response 
     817    *  
     818    * @access public 
     819    * @return mixed     array of response cookies, false if none are present 
     820    */ 
     821    function getResponseCookies() 
     822    { 
     823        return isset($this->_response->_cookies) ? $this->_response->_cookies : false; 
     824    } 
     825 
     826    /** 
     827    * Builds the request string 
     828    * 
     829    * @access private 
     830    * @return string The request string 
     831    */ 
     832    function _buildRequest() 
     833    { 
     834        $separator = ini_get('arg_separator.output'); 
     835        ini_set('arg_separator.output', '&'); 
     836        $querystring = ($querystring = $this->_url->getQueryString()) ? '?' . $querystring : ''; 
     837        ini_set('arg_separator.output', $separator); 
     838 
     839        $host = isset($this->_proxy_host) ? $this->_url->protocol . '://' . $this->_url->host : ''; 
     840        $port = (isset($this->_proxy_host) AND $this->_url->port != 80) ? ':' . $this->_url->port : ''; 
     841        $path = $this->_url->path . $querystring; 
     842        $url  = $host . $port . $path; 
     843 
     844        $request = $this->_method . ' ' . $url . ' HTTP/' . $this->_http . "\r\n"; 
     845 
     846        if (in_array($this->_method, $this->_bodyDisallowed) || 
     847            (empty($this->_body) && (HTTP_REQUEST_METHOD_POST != $this->_method || 
     848             (empty($this->_postData) && empty($this->_postFiles))))) 
     849        { 
     850            $this->removeHeader('Content-Type'); 
     851        } else { 
     852            if (empty($this->_requestHeaders['content-type'])) { 
     853                // Add default content-type 
     854                $this->addHeader('Content-Type', 'application/x-www-form-urlencoded'); 
     855            } elseif ('multipart/form-data' == $this->_requestHeaders['content-type']) { 
     856                $boundary = 'HTTP_Request_' . md5(uniqid('request') . microtime()); 
     857                $this->addHeader('Content-Type', 'multipart/form-data; boundary=' . $boundary); 
     858            } 
     859        } 
     860 
     861        // Request Headers 
     862        if (!empty($this->_requestHeaders)) { 
     863            foreach ($this->_requestHeaders as $name => $value) { 
     864                $canonicalName = implode('-', array_map('ucfirst', explode('-', $name))); 
     865                $request      .= $canonicalName . ': ' . $value . "\r\n"; 
     866            } 
     867        } 
     868 
     869        // No post data or wrong method, so simply add a final CRLF 
     870        if (in_array($this->_method, $this->_bodyDisallowed) ||  
     871            (HTTP_REQUEST_METHOD_POST != $this->_method && empty($this->_body))) { 
     872 
     873            $request .= "\r\n"; 
     874 
     875        // Post data if it's an array 
     876        } elseif (HTTP_REQUEST_METHOD_POST == $this->_method &&  
     877                  (!empty($this->_postData) || !empty($this->_postFiles))) { 
     878 
     879            // "normal" POST request 
     880            if (!isset($boundary)) { 
     881                $postdata = implode('&', array_map( 
     882                    create_function('$a', 'return $a[0] . \'=\' . $a[1];'),  
     883                    $this->_flattenArray('', $this->_postData) 
     884                )); 
     885 
     886            // multipart request, probably with file uploads 
     887            } else { 
     888                $postdata = ''; 
     889                if (!empty($this->_postData)) { 
     890                    $flatData = $this->_flattenArray('', $this->_postData); 
     891                    foreach ($flatData as $item) { 
     892                        $postdata .= '--' . $boundary . "\r\n"; 
     893                        $postdata .= 'Content-Disposition: form-data; name="' . $item[0] . '"'; 
     894                        $postdata .= "\r\n\r\n" . urldecode($item[1]) . "\r\n"; 
     895                    } 
     896                } 
     897                foreach ($this->_postFiles as $name => $value) { 
     898                    if (is_array($value['name'])) { 
     899                        $varname       = $name . ($this->_useBrackets? '[]': ''); 
     900                    } else { 
     901                        $varname       = $name; 
     902                        $value['name'] = array($value['name']); 
     903                    } 
     904                    foreach ($value['name'] as $key => $filename) { 
     905                        $fp   = fopen($filename, 'r'); 
     906                        $data = fread($fp, filesize($filename)); 
     907                        fclose($fp); 
     908                        $basename = basename($filename); 
     909                        $type     = is_array($value['type'])? @$value['type'][$key]: $value['type']; 
     910 
     911                        $postdata .= '--' . $boundary . "\r\n"; 
     912                        $postdata .= 'Content-Disposition: form-data; name="' . $varname . '"; filename="' . $basename . '"'; 
     913                        $postdata .= "\r\nContent-Type: " . $type; 
     914                        $postdata .= "\r\n\r\n" . $data . "\r\n"; 
     915                    } 
     916                } 
     917                $postdata .= '--' . $boundary . "--\r\n"; 
     918            } 
     919            $request .= 'Content-Length: ' . strlen($postdata) . "\r\n\r\n"; 
     920            $request .= $postdata; 
     921 
     922        // Explicitly set request body 
     923        } elseif (!empty($this->_body)) { 
     924 
     925            $request .= 'Content-Length: ' . strlen($this->_body) . "\r\n\r\n"; 
     926            $request .= $this->_body; 
     927        } 
     928         
     929        return $request; 
     930    } 
     931 
     932   /** 
     933    * Helper function to change the (probably multidimensional) associative array 
     934    * into the simple one. 
     935    * 
     936    * @param    string  name for item 
     937    * @param    mixed   item's values 
     938    * @return   array   array with the following items: array('item name', 'item value'); 
     939    */ 
     940    function _flattenArray($name, $values) 
     941    { 
     942        if (!is_array($values)) { 
     943            return array(array($name, $values)); 
     944        } else { 
     945            $ret = array(); 
     946            foreach ($values as $k => $v) { 
     947                if (empty($name)) { 
     948                    $newName = $k; 
     949                } elseif ($this->_useBrackets) { 
     950                    $newName = $name . '[' . $k . ']'; 
     951                } else { 
     952                    $newName = $name; 
     953                } 
     954                $ret = array_merge($ret, $this->_flattenArray($newName, $v)); 
     955            } 
     956            return $ret; 
     957        } 
     958    } 
     959 
     960 
     961   /** 
     962    * Adds a Listener to the list of listeners that are notified of 
     963    * the object's events 
     964    *  
     965    * @param    object   HTTP_Request_Listener instance to attach 
     966    * @return   boolean  whether the listener was successfully attached 
     967    * @access   public 
     968    */ 
     969    function attach(&$listener) 
     970    { 
     971        if (!is_a($listener, 'HTTP_Request_Listener')) { 
     972            return false; 
     973        } 
     974        $this->_listeners[$listener->getId()] =& $listener; 
     975        return true; 
     976    } 
     977 
     978 
     979   /** 
     980    * Removes a Listener from the list of listeners  
     981    *  
     982    * @param    object   HTTP_Request_Listener instance to detach 
     983    * @return   boolean  whether the listener was successfully detached 
     984    * @access   public 
     985    */ 
     986    function detach(&$listener) 
     987    { 
     988        if (!is_a($listener, 'HTTP_Request_Listener') ||  
     989            !isset($this->_listeners[$listener->getId()])) { 
     990            return false; 
     991        } 
     992        unset($this->_listeners[$listener->getId()]); 
     993        return true; 
     994    } 
     995 
     996 
     997   /** 
     998    * Notifies all registered listeners of an event. 
     999    *  
     1000    * Events sent by HTTP_Request object 
     1001    * - 'connect': on connection to server 
     1002    * - 'sentRequest': after the request was sent 
     1003    * - 'disconnect': on disconnection from server 
     1004    *  
     1005    * Events sent by HTTP_Response object 
     1006    * - 'gotHeaders': after receiving response headers (headers are passed in $data) 
     1007    * - 'tick': on receiving a part of response body (the part is passed in $data) 
     1008    * - 'gzTick': on receiving a gzip-encoded part of response body (ditto) 
     1009    * - 'gotBody': after receiving the response body (passes the decoded body in $data if it was gzipped) 
     1010    *  
     1011    * @param    string  Event name 
     1012    * @param    mixed   Additional data 
     1013    * @access   private 
     1014    */ 
     1015    function _notify($event, $data = null) 
     1016    { 
     1017        foreach (array_keys($this->_listeners) as $id) { 
     1018            $this->_listeners[$id]->update($this, $event, $data); 
     1019        } 
     1020    } 
     1021} 
     1022 
     1023 
     1024/** 
     1025* Response class to complement the Request class 
     1026*/ 
     1027class HTTP_Response 
     1028{ 
     1029    /** 
     1030    * Socket object 
     1031    * @var object 
     1032    */ 
     1033    var $_sock; 
     1034 
     1035    /** 
     1036    * Protocol 
     1037    * @var string 
     1038    */ 
     1039    var $_protocol; 
     1040     
     1041    /** 
     1042    * Return code 
     1043    * @var string 
     1044    */ 
     1045    var $_code; 
     1046     
     1047    /** 
     1048    * Response headers 
     1049    * @var array 
     1050    */ 
     1051    var $_headers; 
     1052 
     1053    /** 
     1054    * Cookies set in response   
     1055    * @var array 
     1056    */ 
     1057    var $_cookies; 
     1058 
     1059    /** 
     1060    * Response body 
     1061    * @var string 
     1062    */ 
     1063    var $_body = ''; 
     1064 
     1065   /** 
     1066    * Used by _readChunked(): remaining length of the current chunk 
     1067    * @var string 
     1068    */ 
     1069    var $_chunkLength = 0; 
     1070 
     1071   /** 
     1072    * Attached listeners 
     1073    * @var array 
     1074    */ 
     1075    var $_listeners = array(); 
     1076 
     1077   /** 
     1078    * Bytes left to read from message-body 
     1079    * @var null|int 
     1080    */ 
     1081    var $_toRead; 
     1082 
     1083    /** 
     1084    * Constructor 
     1085    * 
     1086    * @param  object Net_Socket     socket to read the response from 
     1087    * @param  array                 listeners attached to request 
     1088    * @return mixed PEAR Error on error, true otherwise 
     1089    */ 
     1090    function HTTP_Response(&$sock, &$listeners) 
     1091    { 
     1092        $this->_sock      =& $sock; 
     1093        $this->_listeners =& $listeners; 
     1094    } 
     1095 
     1096 
     1097   /** 
     1098    * Processes a HTTP response 
     1099    *  
     1100    * This extracts response code, headers, cookies and decodes body if it  
     1101    * was encoded in some way 
     1102    * 
     1103    * @access public 
     1104    * @param  bool      Whether to store response body in object property, set 
     1105    *                   this to false if downloading a LARGE file and using a Listener. 
     1106    *                   This is assumed to be true if body is gzip-encoded. 
     1107    * @param  bool      Whether the response can actually have a message-body. 
     1108    *                   Will be set to false for HEAD requests. 
     1109    * @throws PEAR_Error 
     1110    * @return mixed     true on success, PEAR_Error in case of malformed response 
     1111    */ 
     1112    function process($saveBody = true, $canHaveBody = true) 
     1113    { 
     1114        do { 
     1115            $line = $this->_sock->readLine(); 
     1116            if (sscanf($line, 'HTTP/%s %s', $http_version, $returncode) != 2) { 
     1117                return PEAR::raiseError('Malformed response.'); 
     1118            } else { 
     1119                $this->_protocol = 'HTTP/' . $http_version; 
     1120                $this->_code     = intval($returncode); 
     1121            } 
     1122            while ('' !== ($header = $this->_sock->readLine())) { 
     1123                $this->_processHeader($header); 
     1124            } 
     1125        } while (100 == $this->_code); 
     1126 
     1127        $this->_notify('gotHeaders', $this->_headers); 
     1128 
     1129        // RFC 2616, section 4.4: 
     1130        // 1. Any response message which "MUST NOT" include a message-body ...  
     1131        // is always terminated by the first empty line after the header fields  
     1132        // 3. ... If a message is received with both a 
     1133        // Transfer-Encoding header field and a Content-Length header field, 
     1134        // the latter MUST be ignored. 
     1135        $canHaveBody = $canHaveBody && $this->_code >= 200 &&  
     1136                       $this->_code != 204 && $this->_code != 304; 
     1137 
     1138        // If response body is present, read it and decode 
     1139        $chunked = isset($this->_headers['transfer-encoding']) && ('chunked' == $this->_headers['transfer-encoding']); 
     1140        $gzipped = isset($this->_headers['content-encoding']) && ('gzip' == $this->_headers['content-encoding']); 
     1141        $hasBody = false; 
     1142        if ($canHaveBody && ($chunked || !isset($this->_headers['content-length']) ||  
     1143                0 != $this->_headers['content-length'])) 
     1144        { 
     1145            if ($chunked || !isset($this->_headers['content-length'])) { 
     1146                $this->_toRead = null; 
     1147            } else { 
     1148                $this->_toRead = $this->_headers['content-length']; 
     1149            } 
     1150            while (!$this->_sock->eof() && (is_null($this->_toRead) || 0 < $this->_toRead)) { 
     1151                if ($chunked) { 
     1152                    $data = $this->_readChunked(); 
     1153                } elseif (is_null($this->_toRead)) { 
     1154                    $data = $this->_sock->read(4096); 
     1155                } else { 
     1156                    $data = $this->_sock->read(min(4096, $this->_toRead)); 
     1157                    $this->_toRead -= strlen($data); 
     1158                } 
     1159                if ('' == $data) { 
     1160                    break; 
     1161                } else { 
     1162                    $hasBody = true; 
     1163                    if ($saveBody || $gzipped) { 
     1164                        $this->_body .= $data; 
     1165                    } 
     1166                    $this->_notify($gzipped? 'gzTick': 'tick', $data); 
     1167                } 
     1168            } 
     1169        } 
     1170 
     1171        if ($hasBody) { 
     1172            // Uncompress the body if needed 
     1173            if ($gzipped) { 
     1174                $body = $this->_decodeGzip($this->_body); 
     1175                if (PEAR::isError($body)) { 
     1176                    return $body; 
     1177                } 
     1178                $this->_body = $body; 
     1179                $this->_notify('gotBody', $this->_body); 
     1180            } else { 
     1181                $this->_notify('gotBody'); 
     1182            } 
     1183        } 
     1184        return true; 
     1185    } 
     1186 
     1187 
     1188   /** 
     1189    * Processes the response header 
     1190    * 
     1191    * @access private 
     1192    * @param  string    HTTP header 
     1193    */ 
     1194    function _processHeader($header) 
     1195    { 
     1196        if (false === strpos($header, ':')) { 
     1197            return; 
     1198        } 
     1199        list($headername, $headervalue) = explode(':', $header, 2); 
     1200        $headername  = strtolower($headername); 
     1201        $headervalue = ltrim($headervalue); 
     1202         
     1203        if ('set-cookie' != $headername) { 
     1204            if (isset($this->_headers[$headername])) { 
     1205                $this->_headers[$headername] .= ',' . $headervalue; 
     1206            } else { 
     1207                $this->_headers[$headername]  = $headervalue; 
     1208            } 
     1209        } else { 
     1210            $this->_parseCookie($headervalue); 
     1211        } 
     1212    } 
     1213 
     1214 
     1215   /** 
     1216    * Parse a Set-Cookie header to fill $_cookies array 
     1217    * 
     1218    * @access private 
     1219    * @param  string    value of Set-Cookie header 
     1220    */ 
     1221    function _parseCookie($headervalue) 
     1222    { 
     1223        $cookie = array( 
     1224            'expires' => null, 
     1225            'domain'  => null, 
     1226            'path'    => null, 
     1227            'secure'  => false 
     1228        ); 
     1229 
     1230        // Only a name=value pair 
     1231        if (!strpos($headervalue, ';')) { 
     1232            $pos = strpos($headervalue, '='); 
     1233            $cookie['name']  = trim(substr($headervalue, 0, $pos)); 
     1234            $cookie['value'] = trim(substr($headervalue, $pos + 1)); 
     1235 
     1236        // Some optional parameters are supplied 
     1237        } else { 
     1238            $elements = explode(';', $headervalue); 
     1239            $pos = strpos($elements[0], '='); 
     1240            $cookie['name']  = trim(substr($elements[0], 0, $pos)); 
     1241            $cookie['value'] = trim(substr($elements[0], $pos + 1)); 
     1242 
     1243            for ($i = 1; $i < count($elements); $i++) { 
     1244                if (false === strpos($elements[$i], '=')) { 
     1245                    $elName  = trim($elements[$i]); 
     1246                    $elValue = null; 
     1247                } else { 
     1248                    list ($elName, $elValue) = array_map('trim', explode('=', $elements[$i])); 
     1249                } 
     1250                $elName = strtolower($elName); 
     1251                if ('secure' == $elName) { 
     1252                    $cookie['secure'] = true; 
     1253                } elseif ('expires' == $elName) { 
     1254                    $cookie['expires'] = str_replace('"', '', $elValue); 
     1255                } elseif ('path' == $elName || 'domain' == $elName) { 
     1256                    $cookie[$elName] = urldecode($elValue); 
     1257                } else { 
     1258                    $cookie[$elName] = $elValue; 
     1259                } 
     1260            } 
     1261        } 
     1262        $this->_cookies[] = $cookie; 
     1263    } 
     1264 
     1265 
     1266   /** 
     1267    * Read a part of response body encoded with chunked Transfer-Encoding 
     1268    *  
     1269    * @access private 
     1270    * @return string 
     1271    */ 
     1272    function _readChunked() 
     1273    { 
     1274        // at start of the next chunk? 
     1275        if (0 == $this->_chunkLength) { 
     1276            $line = $this->_sock->readLine(); 
     1277            if (preg_match('/^([0-9a-f]+)/i', $line, $matches)) { 
     1278                $this->_chunkLength = hexdec($matches[1]);  
     1279                // Chunk with zero length indicates the end 
     1280                if (0 == $this->_chunkLength) { 
     1281                    $this->_sock->readLine(); // make this an eof() 
     1282                    return ''; 
     1283                } 
     1284            } else { 
     1285                return ''; 
     1286            } 
     1287        } 
     1288        $data = $this->_sock->read($this->_chunkLength); 
     1289        $this->_chunkLength -= strlen($data); 
     1290        if (0 == $this->_chunkLength) { 
     1291            $this->_sock->readLine(); // Trailing CRLF 
     1292        } 
     1293        return $data; 
     1294    } 
     1295 
     1296 
     1297   /** 
     1298    * Notifies all registered listeners of an event. 
     1299    *  
     1300    * @param    string  Event name 
     1301    * @param    mixed   Additional data 
     1302    * @access   private 
     1303    * @see HTTP_Request::_notify() 
     1304    */ 
     1305    function _notify($event, $data = null) 
     1306    { 
     1307        foreach (array_keys($this->_listeners) as $id) { 
     1308            $this->_listeners[$id]->update($this, $event, $data); 
     1309        } 
     1310    } 
     1311 
     1312 
     1313   /** 
     1314    * Decodes the message-body encoded by gzip 
     1315    * 
     1316    * The real decoding work is done by gzinflate() built-in function, this 
     1317    * method only parses the header and checks data for compliance with 
     1318    * RFC 1952   
     1319    * 
     1320    * @access   private 
     1321    * @param    string  gzip-encoded data 
     1322    * @return   string  decoded data 
     1323    */ 
     1324    function _decodeGzip($data) 
     1325    { 
     1326        $length = strlen($data); 
     1327        // If it doesn't look like gzip-encoded data, don't bother 
     1328        if (18 > $length || strcmp(substr($data, 0, 2), "\x1f\x8b")) { 
     1329            return $data; 
     1330        } 
     1331        $method = ord(substr($data, 2, 1)); 
     1332        if (8 != $method) { 
     1333            return PEAR::raiseError('_decodeGzip(): unknown compression method'); 
     1334        } 
     1335        $flags = ord(substr($data, 3, 1)); 
     1336        if ($flags & 224) { 
     1337            return PEAR::raiseError('_decodeGzip(): reserved bits are set'); 
     1338        } 
     1339 
     1340        // header is 10 bytes minimum. may be longer, though. 
     1341        $headerLength = 10; 
     1342        // extra fields, need to skip 'em 
     1343        if ($flags & 4) { 
     1344            if ($length - $headerLength - 2 < 8) { 
     1345                return PEAR::raiseError('_decodeGzip(): data too short'); 
     1346            } 
     1347            $extraLength = unpack('v', substr($data, 10, 2)); 
     1348            if ($length - $headerLength - 2 - $extraLength[1] < 8) { 
     1349                return PEAR::raiseError('_decodeGzip(): data too short'); 
     1350            } 
     1351            $headerLength += $extraLength[1] + 2; 
     1352        } 
     1353        // file name, need to skip that 
     1354        if ($flags & 8) { 
     1355            if ($length - $headerLength - 1 < 8) { 
     1356                return PEAR::raiseError('_decodeGzip(): data too short'); 
     1357            } 
     1358            $filenameLength = strpos(substr($data, $headerLength), chr(0)); 
     1359            if (false === $filenameLength || $length - $headerLength - $filenameLength - 1 < 8) { 
     1360                return PEAR::raiseError('_decodeGzip(): data too short'); 
     1361            } 
     1362            $headerLength += $filenameLength + 1; 
     1363        } 
     1364        // comment, need to skip that also 
     1365        if ($flags & 16) { 
     1366            if ($length - $headerLength - 1 < 8) { 
     1367                return PEAR::raiseError('_decodeGzip(): data too short'); 
     1368            } 
     1369            $commentLength = strpos(substr($data, $headerLength), chr(0)); 
     1370            if (false === $commentLength || $length - $headerLength - $commentLength - 1 < 8) { 
     1371                return PEAR::raiseError('_decodeGzip(): data too short'); 
     1372            } 
     1373            $headerLength += $commentLength + 1; 
     1374        } 
     1375        // have a CRC for header. let's check 
     1376        if ($flags & 1) { 
     1377            if ($length - $headerLength - 2 < 8) { 
     1378                return PEAR::raiseError('_decodeGzip(): data too short'); 
     1379            } 
     1380            $crcReal   = 0xffff & crc32(substr($data, 0, $headerLength)); 
     1381            $crcStored = unpack('v', substr($data, $headerLength, 2)); 
     1382            if ($crcReal != $crcStored[1]) { 
     1383                return PEAR::raiseError('_decodeGzip(): header CRC check failed'); 
     1384            } 
     1385            $headerLength += 2; 
     1386        } 
     1387        // unpacked data CRC and size at the end of encoded data 
     1388        $tmp = unpack('V2', substr($data, -8)); 
     1389        $dataCrc  = $tmp[1]; 
     1390        $dataSize = $tmp[2]; 
     1391 
     1392        // finally, call the gzinflate() function 
     1393        $unpacked = @gzinflate(substr($data, $headerLength, -8), $dataSize); 
     1394        if (false === $unpacked) { 
     1395            return PEAR::raiseError('_decodeGzip(): gzinflate() call failed'); 
     1396        } elseif ($dataSize != strlen($unpacked)) { 
     1397            return PEAR::raiseError('_decodeGzip(): data size check failed'); 
     1398        } elseif ($dataCrc != crc32($unpacked)) { 
     1399            return PEAR::raiseError('_decodeGzip(): data CRC check failed'); 
     1400        } 
     1401        return $unpacked; 
     1402    } 
     1403} // End class HTTP_Response 
    571404?> 
Note: See TracChangeset for help on using the changeset viewer.