Ignore:
Timestamp:
2013/08/28 13:55:43 (7 years ago)
Author:
m_uehara
Message:

#2348 r23140 をマージ

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/version-2_13_0/data/module/HTTP/Request.php

    r23126 r23143  
     1<<<<<<< .working 
    12<?php 
    23/** 
     
    15201521} // End class HTTP_Response 
    15211522?> 
     1523======= 
     1524<?php 
     1525/** 
     1526 * Class for performing HTTP requests 
     1527 * 
     1528 * PHP versions 4 and 5 
     1529 * 
     1530 * LICENSE: 
     1531 * 
     1532 * Copyright (c) 2002-2007, Richard Heyes 
     1533 * All rights reserved. 
     1534 * 
     1535 * Redistribution and use in source and binary forms, with or without 
     1536 * modification, are permitted provided that the following conditions 
     1537 * are met: 
     1538 * 
     1539 * o Redistributions of source code must retain the above copyright 
     1540 *   notice, this list of conditions and the following disclaimer. 
     1541 * o Redistributions in binary form must reproduce the above copyright 
     1542 *   notice, this list of conditions and the following disclaimer in the 
     1543 *   documentation and/or other materials provided with the distribution. 
     1544 * o The names of the authors may not be used to endorse or promote 
     1545 *   products derived from this software without specific prior written 
     1546 *   permission. 
     1547 * 
     1548 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
     1549 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
     1550 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
     1551 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
     1552 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
     1553 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
     1554 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
     1555 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
     1556 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
     1557 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
     1558 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
     1559 * 
     1560 * @category    HTTP 
     1561 * @package     HTTP_Request 
     1562 * @author      Richard Heyes <richard@phpguru.org> 
     1563 * @author      Alexey Borzov <avb@php.net> 
     1564 * @copyright   2002-2007 Richard Heyes 
     1565 * @license     http://opensource.org/licenses/bsd-license.php New BSD License 
     1566 * @version     CVS: $Id$ 
     1567 * @link        http://pear.php.net/package/HTTP_Request/ 
     1568 */ 
     1569 
     1570/** 
     1571 * PEAR and PEAR_Error classes (for error handling) 
     1572 */ 
     1573require_once 'PEAR.php'; 
     1574/** 
     1575 * Socket class 
     1576 */ 
     1577require_once 'Net/Socket.php'; 
     1578/** 
     1579 * URL handling class 
     1580 */ 
     1581require_once 'Net/URL.php'; 
     1582 
     1583/**#@+ 
     1584 * Constants for HTTP request methods 
     1585 */ 
     1586define('HTTP_REQUEST_METHOD_GET',     'GET',     true); 
     1587define('HTTP_REQUEST_METHOD_HEAD',    'HEAD',    true); 
     1588define('HTTP_REQUEST_METHOD_POST',    'POST',    true); 
     1589define('HTTP_REQUEST_METHOD_PUT',     'PUT',     true); 
     1590define('HTTP_REQUEST_METHOD_DELETE',  'DELETE',  true); 
     1591define('HTTP_REQUEST_METHOD_OPTIONS', 'OPTIONS', true); 
     1592define('HTTP_REQUEST_METHOD_TRACE',   'TRACE',   true); 
     1593/**#@-*/ 
     1594 
     1595/**#@+ 
     1596 * Constants for HTTP request error codes 
     1597 */ 
     1598define('HTTP_REQUEST_ERROR_FILE',             1); 
     1599define('HTTP_REQUEST_ERROR_URL',              2); 
     1600define('HTTP_REQUEST_ERROR_PROXY',            4); 
     1601define('HTTP_REQUEST_ERROR_REDIRECTS',        8); 
     1602define('HTTP_REQUEST_ERROR_RESPONSE',        16); 
     1603define('HTTP_REQUEST_ERROR_GZIP_METHOD',     32); 
     1604define('HTTP_REQUEST_ERROR_GZIP_READ',       64); 
     1605define('HTTP_REQUEST_ERROR_GZIP_DATA',      128); 
     1606define('HTTP_REQUEST_ERROR_GZIP_CRC',       256); 
     1607/**#@-*/ 
     1608 
     1609/**#@+ 
     1610 * Constants for HTTP protocol versions 
     1611 */ 
     1612define('HTTP_REQUEST_HTTP_VER_1_0', '1.0', true); 
     1613define('HTTP_REQUEST_HTTP_VER_1_1', '1.1', true); 
     1614/**#@-*/ 
     1615 
     1616if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) { 
     1617   /** 
     1618    * Whether string functions are overloaded by their mbstring equivalents 
     1619    */ 
     1620    define('HTTP_REQUEST_MBSTRING', true); 
     1621} else { 
     1622   /** 
     1623    * @ignore 
     1624    */ 
     1625    define('HTTP_REQUEST_MBSTRING', false); 
     1626} 
     1627 
     1628/** 
     1629 * Class for performing HTTP requests 
     1630 * 
     1631 * Simple example (fetches yahoo.com and displays it): 
     1632 * <code> 
     1633 * $a = &new HTTP_Request('http://www.yahoo.com/'); 
     1634 * $a->sendRequest(); 
     1635 * echo $a->getResponseBody(); 
     1636 * </code> 
     1637 * 
     1638 * @category    HTTP 
     1639 * @package     HTTP_Request 
     1640 * @author      Richard Heyes <richard@phpguru.org> 
     1641 * @author      Alexey Borzov <avb@php.net> 
     1642 * @version     Release: 1.4.4 
     1643 */ 
     1644class HTTP_Request 
     1645{ 
     1646   /**#@+ 
     1647    * @access private 
     1648    */ 
     1649    /** 
     1650    * Instance of Net_URL 
     1651    * @var Net_URL 
     1652    */ 
     1653    var $_url; 
     1654 
     1655    /** 
     1656    * Type of request 
     1657    * @var string 
     1658    */ 
     1659    var $_method; 
     1660 
     1661    /** 
     1662    * HTTP Version 
     1663    * @var string 
     1664    */ 
     1665    var $_http; 
     1666 
     1667    /** 
     1668    * Request headers 
     1669    * @var array 
     1670    */ 
     1671    var $_requestHeaders; 
     1672 
     1673    /** 
     1674    * Basic Auth Username 
     1675    * @var string 
     1676    */ 
     1677    var $_user; 
     1678 
     1679    /** 
     1680    * Basic Auth Password 
     1681    * @var string 
     1682    */ 
     1683    var $_pass; 
     1684 
     1685    /** 
     1686    * Socket object 
     1687    * @var Net_Socket 
     1688    */ 
     1689    var $_sock; 
     1690 
     1691    /** 
     1692    * Proxy server 
     1693    * @var string 
     1694    */ 
     1695    var $_proxy_host; 
     1696 
     1697    /** 
     1698    * Proxy port 
     1699    * @var integer 
     1700    */ 
     1701    var $_proxy_port; 
     1702 
     1703    /** 
     1704    * Proxy username 
     1705    * @var string 
     1706    */ 
     1707    var $_proxy_user; 
     1708 
     1709    /** 
     1710    * Proxy password 
     1711    * @var string 
     1712    */ 
     1713    var $_proxy_pass; 
     1714 
     1715    /** 
     1716    * Post data 
     1717    * @var array 
     1718    */ 
     1719    var $_postData; 
     1720 
     1721   /** 
     1722    * Request body 
     1723    * @var string 
     1724    */ 
     1725    var $_body; 
     1726 
     1727   /** 
     1728    * A list of methods that MUST NOT have a request body, per RFC 2616 
     1729    * @var array 
     1730    */ 
     1731    var $_bodyDisallowed = array('TRACE'); 
     1732 
     1733   /** 
     1734    * Methods having defined semantics for request body 
     1735    * 
     1736    * Content-Length header (indicating that the body follows, section 4.3 of 
     1737    * RFC 2616) will be sent for these methods even if no body was added 
     1738    * 
     1739    * @var array 
     1740    */ 
     1741    var $_bodyRequired = array('POST', 'PUT'); 
     1742 
     1743   /** 
     1744    * Files to post 
     1745    * @var array 
     1746    */ 
     1747    var $_postFiles = array(); 
     1748 
     1749    /** 
     1750    * Connection timeout. 
     1751    * @var float 
     1752    */ 
     1753    var $_timeout; 
     1754 
     1755    /** 
     1756    * HTTP_Response object 
     1757    * @var HTTP_Response 
     1758    */ 
     1759    var $_response; 
     1760 
     1761    /** 
     1762    * Whether to allow redirects 
     1763    * @var boolean 
     1764    */ 
     1765    var $_allowRedirects; 
     1766 
     1767    /** 
     1768    * Maximum redirects allowed 
     1769    * @var integer 
     1770    */ 
     1771    var $_maxRedirects; 
     1772 
     1773    /** 
     1774    * Current number of redirects 
     1775    * @var integer 
     1776    */ 
     1777    var $_redirects; 
     1778 
     1779   /** 
     1780    * Whether to append brackets [] to array variables 
     1781    * @var bool 
     1782    */ 
     1783    var $_useBrackets = true; 
     1784 
     1785   /** 
     1786    * Attached listeners 
     1787    * @var array 
     1788    */ 
     1789    var $_listeners = array(); 
     1790 
     1791   /** 
     1792    * Whether to save response body in response object property 
     1793    * @var bool 
     1794    */ 
     1795    var $_saveBody = true; 
     1796 
     1797   /** 
     1798    * Timeout for reading from socket (array(seconds, microseconds)) 
     1799    * @var array 
     1800    */ 
     1801    var $_readTimeout = null; 
     1802 
     1803   /** 
     1804    * Options to pass to Net_Socket::connect. See stream_context_create 
     1805    * @var array 
     1806    */ 
     1807    var $_socketOptions = null; 
     1808   /**#@-*/ 
     1809 
     1810    /** 
     1811    * Constructor 
     1812    * 
     1813    * Sets up the object 
     1814    * @param    string  The url to fetch/access 
     1815    * @param    array   Associative array of parameters which can have the following keys: 
     1816    * <ul> 
     1817    *   <li>method         - Method to use, GET, POST etc (string)</li> 
     1818    *   <li>http           - HTTP Version to use, 1.0 or 1.1 (string)</li> 
     1819    *   <li>user           - Basic Auth username (string)</li> 
     1820    *   <li>pass           - Basic Auth password (string)</li> 
     1821    *   <li>proxy_host     - Proxy server host (string)</li> 
     1822    *   <li>proxy_port     - Proxy server port (integer)</li> 
     1823    *   <li>proxy_user     - Proxy auth username (string)</li> 
     1824    *   <li>proxy_pass     - Proxy auth password (string)</li> 
     1825    *   <li>timeout        - Connection timeout in seconds (float)</li> 
     1826    *   <li>allowRedirects - Whether to follow redirects or not (bool)</li> 
     1827    *   <li>maxRedirects   - Max number of redirects to follow (integer)</li> 
     1828    *   <li>useBrackets    - Whether to append [] to array variable names (bool)</li> 
     1829    *   <li>saveBody       - Whether to save response body in response object property (bool)</li> 
     1830    *   <li>readTimeout    - Timeout for reading / writing data over the socket (array (seconds, microseconds))</li> 
     1831    *   <li>socketOptions  - Options to pass to Net_Socket object (array)</li> 
     1832    * </ul> 
     1833    * @access public 
     1834    */ 
     1835    function HTTP_Request($url = '', $params = array()) 
     1836    { 
     1837        $this->_method         =  HTTP_REQUEST_METHOD_GET; 
     1838        $this->_http           =  HTTP_REQUEST_HTTP_VER_1_1; 
     1839        $this->_requestHeaders = array(); 
     1840        $this->_postData       = array(); 
     1841        $this->_body           = null; 
     1842 
     1843        $this->_user = null; 
     1844        $this->_pass = null; 
     1845 
     1846        $this->_proxy_host = null; 
     1847        $this->_proxy_port = null; 
     1848        $this->_proxy_user = null; 
     1849        $this->_proxy_pass = null; 
     1850 
     1851        $this->_allowRedirects = false; 
     1852        $this->_maxRedirects   = 3; 
     1853        $this->_redirects      = 0; 
     1854 
     1855        $this->_timeout  = null; 
     1856        $this->_response = null; 
     1857 
     1858        foreach ($params as $key => $value) { 
     1859            $this->{'_' . $key} = $value; 
     1860        } 
     1861 
     1862        if (!empty($url)) { 
     1863            $this->setURL($url); 
     1864        } 
     1865 
     1866        // Default useragent 
     1867        $this->addHeader('User-Agent', 'PEAR HTTP_Request class ( http://pear.php.net/ )'); 
     1868 
     1869        // We don't do keep-alives by default 
     1870        $this->addHeader('Connection', 'close'); 
     1871 
     1872        // Basic authentication 
     1873        if (!empty($this->_user)) { 
     1874            $this->addHeader('Authorization', 'Basic ' . base64_encode($this->_user . ':' . $this->_pass)); 
     1875        } 
     1876 
     1877        // Proxy authentication (see bug #5913) 
     1878        if (!empty($this->_proxy_user)) { 
     1879            $this->addHeader('Proxy-Authorization', 'Basic ' . base64_encode($this->_proxy_user . ':' . $this->_proxy_pass)); 
     1880        } 
     1881 
     1882        // Use gzip encoding if possible 
     1883        if (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http && extension_loaded('zlib')) { 
     1884            $this->addHeader('Accept-Encoding', 'gzip'); 
     1885        } 
     1886    } 
     1887 
     1888    /** 
     1889    * Generates a Host header for HTTP/1.1 requests 
     1890    * 
     1891    * @access private 
     1892    * @return string 
     1893    */ 
     1894    function _generateHostHeader() 
     1895    { 
     1896        if ($this->_url->port != 80 AND strcasecmp($this->_url->protocol, 'http') == 0) { 
     1897            $host = $this->_url->host . ':' . $this->_url->port; 
     1898 
     1899        } elseif ($this->_url->port != 443 AND strcasecmp($this->_url->protocol, 'https') == 0) { 
     1900            $host = $this->_url->host . ':' . $this->_url->port; 
     1901 
     1902        } elseif ($this->_url->port == 443 AND strcasecmp($this->_url->protocol, 'https') == 0 AND strpos($this->_url->url, ':443') !== false) { 
     1903            $host = $this->_url->host . ':' . $this->_url->port; 
     1904 
     1905        } else { 
     1906            $host = $this->_url->host; 
     1907        } 
     1908 
     1909        return $host; 
     1910    } 
     1911 
     1912    /** 
     1913    * Resets the object to its initial state (DEPRECATED). 
     1914    * Takes the same parameters as the constructor. 
     1915    * 
     1916    * @param  string $url    The url to be requested 
     1917    * @param  array  $params Associative array of parameters 
     1918    *                        (see constructor for details) 
     1919    * @access public 
     1920    * @deprecated deprecated since 1.2, call the constructor if this is necessary 
     1921    */ 
     1922    function reset($url, $params = array()) 
     1923    { 
     1924        $this->HTTP_Request($url, $params); 
     1925    } 
     1926 
     1927    /** 
     1928    * Sets the URL to be requested 
     1929    * 
     1930    * @param  string The url to be requested 
     1931    * @access public 
     1932    */ 
     1933    function setURL($url) 
     1934    { 
     1935        $this->_url = &new Net_URL($url, $this->_useBrackets); 
     1936 
     1937        if (!empty($this->_url->user) || !empty($this->_url->pass)) { 
     1938            $this->setBasicAuth($this->_url->user, $this->_url->pass); 
     1939        } 
     1940 
     1941        if (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http) { 
     1942            $this->addHeader('Host', $this->_generateHostHeader()); 
     1943        } 
     1944 
     1945        // set '/' instead of empty path rather than check later (see bug #8662) 
     1946        if (empty($this->_url->path)) { 
     1947            $this->_url->path = '/'; 
     1948        } 
     1949    } 
     1950 
     1951   /** 
     1952    * Returns the current request URL 
     1953    * 
     1954    * @return   string  Current request URL 
     1955    * @access   public 
     1956    */ 
     1957    function getUrl() 
     1958    { 
     1959        return empty($this->_url)? '': $this->_url->getUrl(); 
     1960    } 
     1961 
     1962    /** 
     1963    * Sets a proxy to be used 
     1964    * 
     1965    * @param string     Proxy host 
     1966    * @param int        Proxy port 
     1967    * @param string     Proxy username 
     1968    * @param string     Proxy password 
     1969    * @access public 
     1970    */ 
     1971    function setProxy($host, $port = 8080, $user = null, $pass = null) 
     1972    { 
     1973        $this->_proxy_host = $host; 
     1974        $this->_proxy_port = $port; 
     1975        $this->_proxy_user = $user; 
     1976        $this->_proxy_pass = $pass; 
     1977 
     1978        if (!empty($user)) { 
     1979            $this->addHeader('Proxy-Authorization', 'Basic ' . base64_encode($user . ':' . $pass)); 
     1980        } 
     1981    } 
     1982 
     1983    /** 
     1984    * Sets basic authentication parameters 
     1985    * 
     1986    * @param string     Username 
     1987    * @param string     Password 
     1988    */ 
     1989    function setBasicAuth($user, $pass) 
     1990    { 
     1991        $this->_user = $user; 
     1992        $this->_pass = $pass; 
     1993 
     1994        $this->addHeader('Authorization', 'Basic ' . base64_encode($user . ':' . $pass)); 
     1995    } 
     1996 
     1997    /** 
     1998    * Sets the method to be used, GET, POST etc. 
     1999    * 
     2000    * @param string     Method to use. Use the defined constants for this 
     2001    * @access public 
     2002    */ 
     2003    function setMethod($method) 
     2004    { 
     2005        $this->_method = $method; 
     2006    } 
     2007 
     2008    /** 
     2009    * Sets the HTTP version to use, 1.0 or 1.1 
     2010    * 
     2011    * @param string     Version to use. Use the defined constants for this 
     2012    * @access public 
     2013    */ 
     2014    function setHttpVer($http) 
     2015    { 
     2016        $this->_http = $http; 
     2017    } 
     2018 
     2019    /** 
     2020    * Adds a request header 
     2021    * 
     2022    * @param string     Header name 
     2023    * @param string     Header value 
     2024    * @access public 
     2025    */ 
     2026    function addHeader($name, $value) 
     2027    { 
     2028        $this->_requestHeaders[strtolower($name)] = $value; 
     2029    } 
     2030 
     2031    /** 
     2032    * Removes a request header 
     2033    * 
     2034    * @param string     Header name to remove 
     2035    * @access public 
     2036    */ 
     2037    function removeHeader($name) 
     2038    { 
     2039        if (isset($this->_requestHeaders[strtolower($name)])) { 
     2040            unset($this->_requestHeaders[strtolower($name)]); 
     2041        } 
     2042    } 
     2043 
     2044    /** 
     2045    * Adds a querystring parameter 
     2046    * 
     2047    * @param string     Querystring parameter name 
     2048    * @param string     Querystring parameter value 
     2049    * @param bool       Whether the value is already urlencoded or not, default = not 
     2050    * @access public 
     2051    */ 
     2052    function addQueryString($name, $value, $preencoded = false) 
     2053    { 
     2054        $this->_url->addQueryString($name, $value, $preencoded); 
     2055    } 
     2056 
     2057    /** 
     2058    * Sets the querystring to literally what you supply 
     2059    * 
     2060    * @param string     The querystring data. Should be of the format foo=bar&x=y etc 
     2061    * @param bool       Whether data is already urlencoded or not, default = already encoded 
     2062    * @access public 
     2063    */ 
     2064    function addRawQueryString($querystring, $preencoded = true) 
     2065    { 
     2066        $this->_url->addRawQueryString($querystring, $preencoded); 
     2067    } 
     2068 
     2069    /** 
     2070    * Adds postdata items 
     2071    * 
     2072    * @param string     Post data name 
     2073    * @param string     Post data value 
     2074    * @param bool       Whether data is already urlencoded or not, default = not 
     2075    * @access public 
     2076    */ 
     2077    function addPostData($name, $value, $preencoded = false) 
     2078    { 
     2079        if ($preencoded) { 
     2080            $this->_postData[$name] = $value; 
     2081        } else { 
     2082            $this->_postData[$name] = $this->_arrayMapRecursive('urlencode', $value); 
     2083        } 
     2084    } 
     2085     
     2086    function addPostDataArray($array, $preencoded = false) 
     2087    { 
     2088        foreach($array as $key => $val){ 
     2089            $this->addPostData($key, $val, $preencoded); 
     2090        } 
     2091    }    
     2092 
     2093   /** 
     2094    * Recursively applies the callback function to the value 
     2095    * 
     2096    * @param    mixed   Callback function 
     2097    * @param    mixed   Value to process 
     2098    * @access   private 
     2099    * @return   mixed   Processed value 
     2100    */ 
     2101    function _arrayMapRecursive($callback, $value) 
     2102    { 
     2103        if (!is_array($value)) { 
     2104            return call_user_func($callback, $value); 
     2105        } else { 
     2106            $map = array(); 
     2107            foreach ($value as $k => $v) { 
     2108                $map[$k] = $this->_arrayMapRecursive($callback, $v); 
     2109            } 
     2110            return $map; 
     2111        } 
     2112    } 
     2113 
     2114   /** 
     2115    * Adds a file to form-based file upload 
     2116    * 
     2117    * Used to emulate file upload via a HTML form. The method also sets 
     2118    * Content-Type of HTTP request to 'multipart/form-data'. 
     2119    * 
     2120    * If you just want to send the contents of a file as the body of HTTP 
     2121    * request you should use setBody() method. 
     2122    * 
     2123    * @access public 
     2124    * @param  string    name of file-upload field 
     2125    * @param  mixed     file name(s) 
     2126    * @param  mixed     content-type(s) of file(s) being uploaded 
     2127    * @return bool      true on success 
     2128    * @throws PEAR_Error 
     2129    */ 
     2130    function addFile($inputName, $fileName, $contentType = 'application/octet-stream') 
     2131    { 
     2132        if (!is_array($fileName) && !is_readable($fileName)) { 
     2133            return PEAR::raiseError("File '{$fileName}' is not readable", HTTP_REQUEST_ERROR_FILE); 
     2134        } elseif (is_array($fileName)) { 
     2135            foreach ($fileName as $name) { 
     2136                if (!is_readable($name)) { 
     2137                    return PEAR::raiseError("File '{$name}' is not readable", HTTP_REQUEST_ERROR_FILE); 
     2138                } 
     2139            } 
     2140        } 
     2141        $this->addHeader('Content-Type', 'multipart/form-data'); 
     2142        $this->_postFiles[$inputName] = array( 
     2143            'name' => $fileName, 
     2144            'type' => $contentType 
     2145        ); 
     2146        return true; 
     2147    } 
     2148 
     2149    /** 
     2150    * Adds raw postdata (DEPRECATED) 
     2151    * 
     2152    * @param string     The data 
     2153    * @param bool       Whether data is preencoded or not, default = already encoded 
     2154    * @access public 
     2155    * @deprecated       deprecated since 1.3.0, method setBody() should be used instead 
     2156    */ 
     2157    function addRawPostData($postdata, $preencoded = true) 
     2158    { 
     2159        $this->_body = $preencoded ? $postdata : urlencode($postdata); 
     2160    } 
     2161 
     2162   /** 
     2163    * Sets the request body (for POST, PUT and similar requests) 
     2164    * 
     2165    * @param    string  Request body 
     2166    * @access   public 
     2167    */ 
     2168    function setBody($body) 
     2169    { 
     2170        $this->_body = $body; 
     2171    } 
     2172 
     2173    /** 
     2174    * Clears any postdata that has been added (DEPRECATED). 
     2175    * 
     2176    * Useful for multiple request scenarios. 
     2177    * 
     2178    * @access public 
     2179    * @deprecated deprecated since 1.2 
     2180    */ 
     2181    function clearPostData() 
     2182    { 
     2183        $this->_postData = null; 
     2184    } 
     2185 
     2186    /** 
     2187    * Appends a cookie to "Cookie:" header 
     2188    * 
     2189    * @param string $name cookie name 
     2190    * @param string $value cookie value 
     2191    * @access public 
     2192    */ 
     2193    function addCookie($name, $value) 
     2194    { 
     2195        $cookies = isset($this->_requestHeaders['cookie']) ? $this->_requestHeaders['cookie']. '; ' : ''; 
     2196        $this->addHeader('Cookie', $cookies . $name . '=' . $value); 
     2197    } 
     2198 
     2199    /** 
     2200    * Clears any cookies that have been added (DEPRECATED). 
     2201    * 
     2202    * Useful for multiple request scenarios 
     2203    * 
     2204    * @access public 
     2205    * @deprecated deprecated since 1.2 
     2206    */ 
     2207    function clearCookies() 
     2208    { 
     2209        $this->removeHeader('Cookie'); 
     2210    } 
     2211 
     2212    /** 
     2213    * Sends the request 
     2214    * 
     2215    * @access public 
     2216    * @param  bool   Whether to store response body in Response object property, 
     2217    *                set this to false if downloading a LARGE file and using a Listener 
     2218    * @return mixed  PEAR error on error, true otherwise 
     2219    */ 
     2220    function sendRequest($saveBody = true) 
     2221    { 
     2222        if (!is_a($this->_url, 'Net_URL')) { 
     2223            return PEAR::raiseError('No URL given', HTTP_REQUEST_ERROR_URL); 
     2224        } 
     2225 
     2226        $host = isset($this->_proxy_host) ? $this->_proxy_host : $this->_url->host; 
     2227        $port = isset($this->_proxy_port) ? $this->_proxy_port : $this->_url->port; 
     2228 
     2229        if (strcasecmp($this->_url->protocol, 'https') == 0) { 
     2230            // Bug #14127, don't try connecting to HTTPS sites without OpenSSL 
     2231            if (version_compare(PHP_VERSION, '4.3.0', '<') || !extension_loaded('openssl')) { 
     2232                return PEAR::raiseError('Need PHP 4.3.0 or later with OpenSSL support for https:// requests', 
     2233                                        HTTP_REQUEST_ERROR_URL); 
     2234            } elseif (isset($this->_proxy_host)) { 
     2235                return PEAR::raiseError('HTTPS proxies are not supported', HTTP_REQUEST_ERROR_PROXY); 
     2236            } 
     2237            $host = 'ssl://' . $host; 
     2238        } 
     2239 
     2240        // magic quotes may fuck up file uploads and chunked response processing 
     2241        $magicQuotes = ini_get('magic_quotes_runtime'); 
     2242        ini_set('magic_quotes_runtime', false); 
     2243 
     2244        // RFC 2068, section 19.7.1: A client MUST NOT send the Keep-Alive 
     2245        // connection token to a proxy server... 
     2246        if (isset($this->_proxy_host) && !empty($this->_requestHeaders['connection']) && 
     2247            'Keep-Alive' == $this->_requestHeaders['connection']) 
     2248        { 
     2249            $this->removeHeader('connection'); 
     2250        } 
     2251 
     2252        $keepAlive = (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http && empty($this->_requestHeaders['connection'])) || 
     2253                     (!empty($this->_requestHeaders['connection']) && 'Keep-Alive' == $this->_requestHeaders['connection']); 
     2254        $sockets   = &PEAR::getStaticProperty('HTTP_Request', 'sockets'); 
     2255        $sockKey   = $host . ':' . $port; 
     2256        unset($this->_sock); 
     2257 
     2258        // There is a connected socket in the "static" property? 
     2259        if ($keepAlive && !empty($sockets[$sockKey]) && 
     2260            !empty($sockets[$sockKey]->fp)) 
     2261        { 
     2262            $this->_sock =& $sockets[$sockKey]; 
     2263            $err = null; 
     2264        } else { 
     2265            $this->_notify('connect'); 
     2266            $this->_sock =& new Net_Socket(); 
     2267            $err = $this->_sock->connect($host, $port, null, $this->_timeout, $this->_socketOptions); 
     2268        } 
     2269        PEAR::isError($err) or $err = $this->_sock->write($this->_buildRequest()); 
     2270 
     2271        if (!PEAR::isError($err)) { 
     2272            if (!empty($this->_readTimeout)) { 
     2273                $this->_sock->setTimeout($this->_readTimeout[0], $this->_readTimeout[1]); 
     2274            } 
     2275 
     2276            $this->_notify('sentRequest'); 
     2277 
     2278            // Read the response 
     2279            $this->_response = &new HTTP_Response($this->_sock, $this->_listeners); 
     2280            $err = $this->_response->process( 
     2281                $this->_saveBody && $saveBody, 
     2282                HTTP_REQUEST_METHOD_HEAD != $this->_method 
     2283            ); 
     2284 
     2285            if ($keepAlive) { 
     2286                $keepAlive = (isset($this->_response->_headers['content-length']) 
     2287                              || (isset($this->_response->_headers['transfer-encoding']) 
     2288                                  && strtolower($this->_response->_headers['transfer-encoding']) == 'chunked')); 
     2289                if ($keepAlive) { 
     2290                    if (isset($this->_response->_headers['connection'])) { 
     2291                        $keepAlive = strtolower($this->_response->_headers['connection']) == 'keep-alive'; 
     2292                    } else { 
     2293                        $keepAlive = 'HTTP/'.HTTP_REQUEST_HTTP_VER_1_1 == $this->_response->_protocol; 
     2294                    } 
     2295                } 
     2296            } 
     2297        } 
     2298 
     2299        ini_set('magic_quotes_runtime', $magicQuotes); 
     2300 
     2301        if (PEAR::isError($err)) { 
     2302            return $err; 
     2303        } 
     2304 
     2305        if (!$keepAlive) { 
     2306            $this->disconnect(); 
     2307        // Store the connected socket in "static" property 
     2308        } elseif (empty($sockets[$sockKey]) || empty($sockets[$sockKey]->fp)) { 
     2309            $sockets[$sockKey] =& $this->_sock; 
     2310        } 
     2311 
     2312        // Check for redirection 
     2313        if (    $this->_allowRedirects 
     2314            AND $this->_redirects <= $this->_maxRedirects 
     2315            AND $this->getResponseCode() > 300 
     2316            AND $this->getResponseCode() < 399 
     2317            AND !empty($this->_response->_headers['location'])) { 
     2318 
     2319 
     2320            $redirect = $this->_response->_headers['location']; 
     2321 
     2322            // Absolute URL 
     2323            if (preg_match('/^https?:\/\//i', $redirect)) { 
     2324                $this->_url = &new Net_URL($redirect); 
     2325                $this->addHeader('Host', $this->_generateHostHeader()); 
     2326            // Absolute path 
     2327            } elseif ($redirect{0} == '/') { 
     2328                $this->_url->path = $redirect; 
     2329 
     2330            // Relative path 
     2331            } elseif (substr($redirect, 0, 3) == '../' OR substr($redirect, 0, 2) == './') { 
     2332                if (substr($this->_url->path, -1) == '/') { 
     2333                    $redirect = $this->_url->path . $redirect; 
     2334                } else { 
     2335                    $redirect = dirname($this->_url->path) . '/' . $redirect; 
     2336                } 
     2337                $redirect = Net_URL::resolvePath($redirect); 
     2338                $this->_url->path = $redirect; 
     2339 
     2340            // Filename, no path 
     2341            } else { 
     2342                if (substr($this->_url->path, -1) == '/') { 
     2343                    $redirect = $this->_url->path . $redirect; 
     2344                } else { 
     2345                    $redirect = dirname($this->_url->path) . '/' . $redirect; 
     2346                } 
     2347                $this->_url->path = $redirect; 
     2348            } 
     2349 
     2350            $this->_redirects++; 
     2351            return $this->sendRequest($saveBody); 
     2352 
     2353        // Too many redirects 
     2354        } elseif ($this->_allowRedirects AND $this->_redirects > $this->_maxRedirects) { 
     2355            return PEAR::raiseError('Too many redirects', HTTP_REQUEST_ERROR_REDIRECTS); 
     2356        } 
     2357 
     2358        return true; 
     2359    } 
     2360 
     2361    /** 
     2362     * Disconnect the socket, if connected. Only useful if using Keep-Alive. 
     2363     * 
     2364     * @access public 
     2365     */ 
     2366    function disconnect() 
     2367    { 
     2368        if (!empty($this->_sock) && !empty($this->_sock->fp)) { 
     2369            $this->_notify('disconnect'); 
     2370            $this->_sock->disconnect(); 
     2371        } 
     2372    } 
     2373 
     2374    /** 
     2375    * Returns the response code 
     2376    * 
     2377    * @access public 
     2378    * @return mixed     Response code, false if not set 
     2379    */ 
     2380    function getResponseCode() 
     2381    { 
     2382        return isset($this->_response->_code) ? $this->_response->_code : false; 
     2383    } 
     2384 
     2385    /** 
     2386    * Returns the response reason phrase 
     2387    * 
     2388    * @access public 
     2389    * @return mixed     Response reason phrase, false if not set 
     2390    */ 
     2391    function getResponseReason() 
     2392    { 
     2393        return isset($this->_response->_reason) ? $this->_response->_reason : false; 
     2394    } 
     2395 
     2396    /** 
     2397    * Returns either the named header or all if no name given 
     2398    * 
     2399    * @access public 
     2400    * @param string     The header name to return, do not set to get all headers 
     2401    * @return mixed     either the value of $headername (false if header is not present) 
     2402    *                   or an array of all headers 
     2403    */ 
     2404    function getResponseHeader($headername = null) 
     2405    { 
     2406        if (!isset($headername)) { 
     2407            return isset($this->_response->_headers)? $this->_response->_headers: array(); 
     2408        } else { 
     2409            $headername = strtolower($headername); 
     2410            return isset($this->_response->_headers[$headername]) ? $this->_response->_headers[$headername] : false; 
     2411        } 
     2412    } 
     2413 
     2414    /** 
     2415    * Returns the body of the response 
     2416    * 
     2417    * @access public 
     2418    * @return mixed     response body, false if not set 
     2419    */ 
     2420    function getResponseBody() 
     2421    { 
     2422        return isset($this->_response->_body) ? $this->_response->_body : false; 
     2423    } 
     2424 
     2425    /** 
     2426    * Returns cookies set in response 
     2427    * 
     2428    * @access public 
     2429    * @return mixed     array of response cookies, false if none are present 
     2430    */ 
     2431    function getResponseCookies() 
     2432    { 
     2433        return isset($this->_response->_cookies) ? $this->_response->_cookies : false; 
     2434    } 
     2435 
     2436    /** 
     2437    * Builds the request string 
     2438    * 
     2439    * @access private 
     2440    * @return string The request string 
     2441    */ 
     2442    function _buildRequest() 
     2443    { 
     2444        $separator = ini_get('arg_separator.output'); 
     2445        ini_set('arg_separator.output', '&'); 
     2446        $querystring = ($querystring = $this->_url->getQueryString()) ? '?' . $querystring : ''; 
     2447        ini_set('arg_separator.output', $separator); 
     2448 
     2449        $host = isset($this->_proxy_host) ? $this->_url->protocol . '://' . $this->_url->host : ''; 
     2450        $port = (isset($this->_proxy_host) AND $this->_url->port != 80) ? ':' . $this->_url->port : ''; 
     2451        $path = $this->_url->path . $querystring; 
     2452        $url  = $host . $port . $path; 
     2453 
     2454        if (!strlen($url)) { 
     2455            $url = '/'; 
     2456        } 
     2457 
     2458        $request = $this->_method . ' ' . $url . ' HTTP/' . $this->_http . "\r\n"; 
     2459 
     2460        if (in_array($this->_method, $this->_bodyDisallowed) || 
     2461            (0 == strlen($this->_body) && (HTTP_REQUEST_METHOD_POST != $this->_method || 
     2462             (empty($this->_postData) && empty($this->_postFiles))))) 
     2463        { 
     2464            $this->removeHeader('Content-Type'); 
     2465        } else { 
     2466            if (empty($this->_requestHeaders['content-type'])) { 
     2467                // Add default content-type 
     2468                $this->addHeader('Content-Type', 'application/x-www-form-urlencoded'); 
     2469            } elseif ('multipart/form-data' == $this->_requestHeaders['content-type']) { 
     2470                $boundary = 'HTTP_Request_' . md5(uniqid('request') . microtime()); 
     2471                $this->addHeader('Content-Type', 'multipart/form-data; boundary=' . $boundary); 
     2472            } 
     2473        } 
     2474 
     2475        // Request Headers 
     2476        if (!empty($this->_requestHeaders)) { 
     2477            foreach ($this->_requestHeaders as $name => $value) { 
     2478                $canonicalName = implode('-', array_map('ucfirst', explode('-', $name))); 
     2479                $request      .= $canonicalName . ': ' . $value . "\r\n"; 
     2480            } 
     2481        } 
     2482 
     2483        // Method does not allow a body, simply add a final CRLF 
     2484        if (in_array($this->_method, $this->_bodyDisallowed)) { 
     2485 
     2486            $request .= "\r\n"; 
     2487 
     2488        // Post data if it's an array 
     2489        } elseif (HTTP_REQUEST_METHOD_POST == $this->_method && 
     2490                  (!empty($this->_postData) || !empty($this->_postFiles))) { 
     2491 
     2492            // "normal" POST request 
     2493            if (!isset($boundary)) { 
     2494                $postdata = implode('&', array_map( 
     2495                    create_function('$a', 'return $a[0] . \'=\' . $a[1];'), 
     2496                    $this->_flattenArray('', $this->_postData) 
     2497                )); 
     2498 
     2499            // multipart request, probably with file uploads 
     2500            } else { 
     2501                $postdata = ''; 
     2502                if (!empty($this->_postData)) { 
     2503                    $flatData = $this->_flattenArray('', $this->_postData); 
     2504                    foreach ($flatData as $item) { 
     2505                        $postdata .= '--' . $boundary . "\r\n"; 
     2506                        $postdata .= 'Content-Disposition: form-data; name="' . $item[0] . '"'; 
     2507                        $postdata .= "\r\n\r\n" . urldecode($item[1]) . "\r\n"; 
     2508                    } 
     2509                } 
     2510                foreach ($this->_postFiles as $name => $value) { 
     2511                    if (is_array($value['name'])) { 
     2512                        $varname       = $name . ($this->_useBrackets? '[]': ''); 
     2513                    } else { 
     2514                        $varname       = $name; 
     2515                        $value['name'] = array($value['name']); 
     2516                    } 
     2517                    foreach ($value['name'] as $key => $filename) { 
     2518                        $fp       = fopen($filename, 'r'); 
     2519                        $basename = basename($filename); 
     2520                        $type     = is_array($value['type'])? @$value['type'][$key]: $value['type']; 
     2521 
     2522                        $postdata .= '--' . $boundary . "\r\n"; 
     2523                        $postdata .= 'Content-Disposition: form-data; name="' . $varname . '"; filename="' . $basename . '"'; 
     2524                        $postdata .= "\r\nContent-Type: " . $type; 
     2525                        $postdata .= "\r\n\r\n" . fread($fp, filesize($filename)) . "\r\n"; 
     2526                        fclose($fp); 
     2527                    } 
     2528                } 
     2529                $postdata .= '--' . $boundary . "--\r\n"; 
     2530            } 
     2531            $request .= 'Content-Length: ' . 
     2532                        (HTTP_REQUEST_MBSTRING? mb_strlen($postdata, 'iso-8859-1'): strlen($postdata)) . 
     2533                        "\r\n\r\n"; 
     2534            $request .= $postdata; 
     2535 
     2536        // Explicitly set request body 
     2537        } elseif (0 < strlen($this->_body)) { 
     2538 
     2539            $request .= 'Content-Length: ' . 
     2540                        (HTTP_REQUEST_MBSTRING? mb_strlen($this->_body, 'iso-8859-1'): strlen($this->_body)) . 
     2541                        "\r\n\r\n"; 
     2542            $request .= $this->_body; 
     2543 
     2544        // No body: send a Content-Length header nonetheless (request #12900), 
     2545        // but do that only for methods that require a body (bug #14740) 
     2546        } else { 
     2547 
     2548            if (in_array($this->_method, $this->_bodyRequired)) { 
     2549                $request .= "Content-Length: 0\r\n"; 
     2550            } 
     2551            $request .= "\r\n"; 
     2552        } 
     2553 
     2554        return $request; 
     2555    } 
     2556 
     2557   /** 
     2558    * Helper function to change the (probably multidimensional) associative array 
     2559    * into the simple one. 
     2560    * 
     2561    * @param    string  name for item 
     2562    * @param    mixed   item's values 
     2563    * @return   array   array with the following items: array('item name', 'item value'); 
     2564    * @access   private 
     2565    */ 
     2566    function _flattenArray($name, $values) 
     2567    { 
     2568        if (!is_array($values)) { 
     2569            return array(array($name, $values)); 
     2570        } else { 
     2571            $ret = array(); 
     2572            foreach ($values as $k => $v) { 
     2573                if (empty($name)) { 
     2574                    $newName = $k; 
     2575                } elseif ($this->_useBrackets) { 
     2576                    $newName = $name . '[' . $k . ']'; 
     2577                } else { 
     2578                    $newName = $name; 
     2579                } 
     2580                $ret = array_merge($ret, $this->_flattenArray($newName, $v)); 
     2581            } 
     2582            return $ret; 
     2583        } 
     2584    } 
     2585 
     2586 
     2587   /** 
     2588    * Adds a Listener to the list of listeners that are notified of 
     2589    * the object's events 
     2590    * 
     2591    * Events sent by HTTP_Request object 
     2592    * - 'connect': on connection to server 
     2593    * - 'sentRequest': after the request was sent 
     2594    * - 'disconnect': on disconnection from server 
     2595    * 
     2596    * Events sent by HTTP_Response object 
     2597    * - 'gotHeaders': after receiving response headers (headers are passed in $data) 
     2598    * - 'tick': on receiving a part of response body (the part is passed in $data) 
     2599    * - 'gzTick': on receiving a gzip-encoded part of response body (ditto) 
     2600    * - 'gotBody': after receiving the response body (passes the decoded body in $data if it was gzipped) 
     2601    * 
     2602    * @param    HTTP_Request_Listener   listener to attach 
     2603    * @return   boolean                 whether the listener was successfully attached 
     2604    * @access   public 
     2605    */ 
     2606    function attach(&$listener) 
     2607    { 
     2608        if (!is_a($listener, 'HTTP_Request_Listener')) { 
     2609            return false; 
     2610        } 
     2611        $this->_listeners[$listener->getId()] =& $listener; 
     2612        return true; 
     2613    } 
     2614 
     2615 
     2616   /** 
     2617    * Removes a Listener from the list of listeners 
     2618    * 
     2619    * @param    HTTP_Request_Listener   listener to detach 
     2620    * @return   boolean                 whether the listener was successfully detached 
     2621    * @access   public 
     2622    */ 
     2623    function detach(&$listener) 
     2624    { 
     2625        if (!is_a($listener, 'HTTP_Request_Listener') || 
     2626            !isset($this->_listeners[$listener->getId()])) { 
     2627            return false; 
     2628        } 
     2629        unset($this->_listeners[$listener->getId()]); 
     2630        return true; 
     2631    } 
     2632 
     2633 
     2634   /** 
     2635    * Notifies all registered listeners of an event. 
     2636    * 
     2637    * @param    string  Event name 
     2638    * @param    mixed   Additional data 
     2639    * @access   private 
     2640    * @see      HTTP_Request::attach() 
     2641    */ 
     2642    function _notify($event, $data = null) 
     2643    { 
     2644        foreach (array_keys($this->_listeners) as $id) { 
     2645            $this->_listeners[$id]->update($this, $event, $data); 
     2646        } 
     2647    } 
     2648} 
     2649 
     2650 
     2651/** 
     2652 * Response class to complement the Request class 
     2653 * 
     2654 * @category    HTTP 
     2655 * @package     HTTP_Request 
     2656 * @author      Richard Heyes <richard@phpguru.org> 
     2657 * @author      Alexey Borzov <avb@php.net> 
     2658 * @version     Release: 1.4.4 
     2659 */ 
     2660class HTTP_Response 
     2661{ 
     2662    /** 
     2663    * Socket object 
     2664    * @var Net_Socket 
     2665    */ 
     2666    var $_sock; 
     2667 
     2668    /** 
     2669    * Protocol 
     2670    * @var string 
     2671    */ 
     2672    var $_protocol; 
     2673 
     2674    /** 
     2675    * Return code 
     2676    * @var string 
     2677    */ 
     2678    var $_code; 
     2679 
     2680    /** 
     2681    * Response reason phrase 
     2682    * @var string 
     2683    */ 
     2684    var $_reason; 
     2685 
     2686    /** 
     2687    * Response headers 
     2688    * @var array 
     2689    */ 
     2690    var $_headers; 
     2691 
     2692    /** 
     2693    * Cookies set in response 
     2694    * @var array 
     2695    */ 
     2696    var $_cookies; 
     2697 
     2698    /** 
     2699    * Response body 
     2700    * @var string 
     2701    */ 
     2702    var $_body = ''; 
     2703 
     2704   /** 
     2705    * Used by _readChunked(): remaining length of the current chunk 
     2706    * @var string 
     2707    */ 
     2708    var $_chunkLength = 0; 
     2709 
     2710   /** 
     2711    * Attached listeners 
     2712    * @var array 
     2713    */ 
     2714    var $_listeners = array(); 
     2715 
     2716   /** 
     2717    * Bytes left to read from message-body 
     2718    * @var null|int 
     2719    */ 
     2720    var $_toRead; 
     2721 
     2722    /** 
     2723    * Constructor 
     2724    * 
     2725    * @param  Net_Socket    socket to read the response from 
     2726    * @param  array         listeners attached to request 
     2727    */ 
     2728    function HTTP_Response(&$sock, &$listeners) 
     2729    { 
     2730        $this->_sock      =& $sock; 
     2731        $this->_listeners =& $listeners; 
     2732    } 
     2733 
     2734 
     2735   /** 
     2736    * Processes a HTTP response 
     2737    * 
     2738    * This extracts response code, headers, cookies and decodes body if it 
     2739    * was encoded in some way 
     2740    * 
     2741    * @access public 
     2742    * @param  bool      Whether to store response body in object property, set 
     2743    *                   this to false if downloading a LARGE file and using a Listener. 
     2744    *                   This is assumed to be true if body is gzip-encoded. 
     2745    * @param  bool      Whether the response can actually have a message-body. 
     2746    *                   Will be set to false for HEAD requests. 
     2747    * @throws PEAR_Error 
     2748    * @return mixed     true on success, PEAR_Error in case of malformed response 
     2749    */ 
     2750    function process($saveBody = true, $canHaveBody = true) 
     2751    { 
     2752        do { 
     2753            $line = $this->_sock->readLine(); 
     2754            if (!preg_match('!^(HTTP/\d\.\d) (\d{3})(?: (.+))?!', $line, $s)) { 
     2755                return PEAR::raiseError('Malformed response', HTTP_REQUEST_ERROR_RESPONSE); 
     2756            } else { 
     2757                $this->_protocol = $s[1]; 
     2758                $this->_code     = intval($s[2]); 
     2759                $this->_reason   = empty($s[3])? null: $s[3]; 
     2760            } 
     2761            while ('' !== ($header = $this->_sock->readLine())) { 
     2762                $this->_processHeader($header); 
     2763            } 
     2764        } while (100 == $this->_code); 
     2765 
     2766        $this->_notify('gotHeaders', $this->_headers); 
     2767 
     2768        // RFC 2616, section 4.4: 
     2769        // 1. Any response message which "MUST NOT" include a message-body ... 
     2770        // is always terminated by the first empty line after the header fields 
     2771        // 3. ... If a message is received with both a 
     2772        // Transfer-Encoding header field and a Content-Length header field, 
     2773        // the latter MUST be ignored. 
     2774        $canHaveBody = $canHaveBody && $this->_code >= 200 && 
     2775                       $this->_code != 204 && $this->_code != 304; 
     2776 
     2777        // If response body is present, read it and decode 
     2778        $chunked = isset($this->_headers['transfer-encoding']) && ('chunked' == $this->_headers['transfer-encoding']); 
     2779        $gzipped = isset($this->_headers['content-encoding']) && ('gzip' == $this->_headers['content-encoding']); 
     2780        $hasBody = false; 
     2781        if ($canHaveBody && ($chunked || !isset($this->_headers['content-length']) || 
     2782                0 != $this->_headers['content-length'])) 
     2783        { 
     2784            if ($chunked || !isset($this->_headers['content-length'])) { 
     2785                $this->_toRead = null; 
     2786            } else { 
     2787                $this->_toRead = $this->_headers['content-length']; 
     2788            } 
     2789            while (!$this->_sock->eof() && (is_null($this->_toRead) || 0 < $this->_toRead)) { 
     2790                if ($chunked) { 
     2791                    $data = $this->_readChunked(); 
     2792                } elseif (is_null($this->_toRead)) { 
     2793                    $data = $this->_sock->read(4096); 
     2794                } else { 
     2795                    $data = $this->_sock->read(min(4096, $this->_toRead)); 
     2796                    $this->_toRead -= HTTP_REQUEST_MBSTRING? mb_strlen($data, 'iso-8859-1'): strlen($data); 
     2797                } 
     2798                if ('' == $data && (!$this->_chunkLength || $this->_sock->eof())) { 
     2799                    break; 
     2800                } else { 
     2801                    $hasBody = true; 
     2802                    if ($saveBody || $gzipped) { 
     2803                        $this->_body .= $data; 
     2804                    } 
     2805                    $this->_notify($gzipped? 'gzTick': 'tick', $data); 
     2806                } 
     2807            } 
     2808        } 
     2809 
     2810        if ($hasBody) { 
     2811            // Uncompress the body if needed 
     2812            if ($gzipped) { 
     2813                $body = $this->_decodeGzip($this->_body); 
     2814                if (PEAR::isError($body)) { 
     2815                    return $body; 
     2816                } 
     2817                $this->_body = $body; 
     2818                $this->_notify('gotBody', $this->_body); 
     2819            } else { 
     2820                $this->_notify('gotBody'); 
     2821            } 
     2822        } 
     2823        return true; 
     2824    } 
     2825 
     2826 
     2827   /** 
     2828    * Processes the response header 
     2829    * 
     2830    * @access private 
     2831    * @param  string    HTTP header 
     2832    */ 
     2833    function _processHeader($header) 
     2834    { 
     2835        if (false === strpos($header, ':')) { 
     2836            return; 
     2837        } 
     2838        list($headername, $headervalue) = explode(':', $header, 2); 
     2839        $headername  = strtolower($headername); 
     2840        $headervalue = ltrim($headervalue); 
     2841 
     2842        if ('set-cookie' != $headername) { 
     2843            if (isset($this->_headers[$headername])) { 
     2844                $this->_headers[$headername] .= ',' . $headervalue; 
     2845            } else { 
     2846                $this->_headers[$headername]  = $headervalue; 
     2847            } 
     2848        } else { 
     2849            $this->_parseCookie($headervalue); 
     2850        } 
     2851    } 
     2852 
     2853 
     2854   /** 
     2855    * Parse a Set-Cookie header to fill $_cookies array 
     2856    * 
     2857    * @access private 
     2858    * @param  string    value of Set-Cookie header 
     2859    */ 
     2860    function _parseCookie($headervalue) 
     2861    { 
     2862        $cookie = array( 
     2863            'expires' => null, 
     2864            'domain'  => null, 
     2865            'path'    => null, 
     2866            'secure'  => false 
     2867        ); 
     2868 
     2869        // Only a name=value pair 
     2870        if (!strpos($headervalue, ';')) { 
     2871            $pos = strpos($headervalue, '='); 
     2872            $cookie['name']  = trim(substr($headervalue, 0, $pos)); 
     2873            $cookie['value'] = trim(substr($headervalue, $pos + 1)); 
     2874 
     2875        // Some optional parameters are supplied 
     2876        } else { 
     2877            $elements = explode(';', $headervalue); 
     2878            $pos = strpos($elements[0], '='); 
     2879            $cookie['name']  = trim(substr($elements[0], 0, $pos)); 
     2880            $cookie['value'] = trim(substr($elements[0], $pos + 1)); 
     2881 
     2882            for ($i = 1; $i < count($elements); $i++) { 
     2883                if (false === strpos($elements[$i], '=')) { 
     2884                    $elName  = trim($elements[$i]); 
     2885                    $elValue = null; 
     2886                } else { 
     2887                    list ($elName, $elValue) = array_map('trim', explode('=', $elements[$i])); 
     2888                } 
     2889                $elName = strtolower($elName); 
     2890                if ('secure' == $elName) { 
     2891                    $cookie['secure'] = true; 
     2892                } elseif ('expires' == $elName) { 
     2893                    $cookie['expires'] = str_replace('"', '', $elValue); 
     2894                } elseif ('path' == $elName || 'domain' == $elName) { 
     2895                    $cookie[$elName] = urldecode($elValue); 
     2896                } else { 
     2897                    $cookie[$elName] = $elValue; 
     2898                } 
     2899            } 
     2900        } 
     2901        $this->_cookies[] = $cookie; 
     2902    } 
     2903 
     2904 
     2905   /** 
     2906    * Read a part of response body encoded with chunked Transfer-Encoding 
     2907    * 
     2908    * @access private 
     2909    * @return string 
     2910    */ 
     2911    function _readChunked() 
     2912    { 
     2913        // at start of the next chunk? 
     2914        if (0 == $this->_chunkLength) { 
     2915            $line = $this->_sock->readLine(); 
     2916            if (preg_match('/^([0-9a-f]+)/i', $line, $matches)) { 
     2917                $this->_chunkLength = hexdec($matches[1]); 
     2918                // Chunk with zero length indicates the end 
     2919                if (0 == $this->_chunkLength) { 
     2920                    $this->_sock->readLine(); // make this an eof() 
     2921                    return ''; 
     2922                } 
     2923            } else { 
     2924                return ''; 
     2925            } 
     2926        } 
     2927        $data = $this->_sock->read($this->_chunkLength); 
     2928        $this->_chunkLength -= HTTP_REQUEST_MBSTRING? mb_strlen($data, 'iso-8859-1'): strlen($data); 
     2929        if (0 == $this->_chunkLength) { 
     2930            $this->_sock->readLine(); // Trailing CRLF 
     2931        } 
     2932        return $data; 
     2933    } 
     2934 
     2935 
     2936   /** 
     2937    * Notifies all registered listeners of an event. 
     2938    * 
     2939    * @param    string  Event name 
     2940    * @param    mixed   Additional data 
     2941    * @access   private 
     2942    * @see HTTP_Request::_notify() 
     2943    */ 
     2944    function _notify($event, $data = null) 
     2945    { 
     2946        foreach (array_keys($this->_listeners) as $id) { 
     2947            $this->_listeners[$id]->update($this, $event, $data); 
     2948        } 
     2949    } 
     2950 
     2951 
     2952   /** 
     2953    * Decodes the message-body encoded by gzip 
     2954    * 
     2955    * The real decoding work is done by gzinflate() built-in function, this 
     2956    * method only parses the header and checks data for compliance with 
     2957    * RFC 1952 
     2958    * 
     2959    * @access   private 
     2960    * @param    string  gzip-encoded data 
     2961    * @return   string  decoded data 
     2962    */ 
     2963    function _decodeGzip($data) 
     2964    { 
     2965        if (HTTP_REQUEST_MBSTRING) { 
     2966            $oldEncoding = mb_internal_encoding(); 
     2967            mb_internal_encoding('iso-8859-1'); 
     2968        } 
     2969        $length = strlen($data); 
     2970        // If it doesn't look like gzip-encoded data, don't bother 
     2971        if (18 > $length || strcmp(substr($data, 0, 2), "\x1f\x8b")) { 
     2972            return $data; 
     2973        } 
     2974        $method = ord(substr($data, 2, 1)); 
     2975        if (8 != $method) { 
     2976            return PEAR::raiseError('_decodeGzip(): unknown compression method', HTTP_REQUEST_ERROR_GZIP_METHOD); 
     2977        } 
     2978        $flags = ord(substr($data, 3, 1)); 
     2979        if ($flags & 224) { 
     2980            return PEAR::raiseError('_decodeGzip(): reserved bits are set', HTTP_REQUEST_ERROR_GZIP_DATA); 
     2981        } 
     2982 
     2983        // header is 10 bytes minimum. may be longer, though. 
     2984        $headerLength = 10; 
     2985        // extra fields, need to skip 'em 
     2986        if ($flags & 4) { 
     2987            if ($length - $headerLength - 2 < 8) { 
     2988                return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); 
     2989            } 
     2990            $extraLength = unpack('v', substr($data, 10, 2)); 
     2991            if ($length - $headerLength - 2 - $extraLength[1] < 8) { 
     2992                return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); 
     2993            } 
     2994            $headerLength += $extraLength[1] + 2; 
     2995        } 
     2996        // file name, need to skip that 
     2997        if ($flags & 8) { 
     2998            if ($length - $headerLength - 1 < 8) { 
     2999                return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); 
     3000            } 
     3001            $filenameLength = strpos(substr($data, $headerLength), chr(0)); 
     3002            if (false === $filenameLength || $length - $headerLength - $filenameLength - 1 < 8) { 
     3003                return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); 
     3004            } 
     3005            $headerLength += $filenameLength + 1; 
     3006        } 
     3007        // comment, need to skip that also 
     3008        if ($flags & 16) { 
     3009            if ($length - $headerLength - 1 < 8) { 
     3010                return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); 
     3011            } 
     3012            $commentLength = strpos(substr($data, $headerLength), chr(0)); 
     3013            if (false === $commentLength || $length - $headerLength - $commentLength - 1 < 8) { 
     3014                return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); 
     3015            } 
     3016            $headerLength += $commentLength + 1; 
     3017        } 
     3018        // have a CRC for header. let's check 
     3019        if ($flags & 1) { 
     3020            if ($length - $headerLength - 2 < 8) { 
     3021                return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); 
     3022            } 
     3023            $crcReal   = 0xffff & crc32(substr($data, 0, $headerLength)); 
     3024            $crcStored = unpack('v', substr($data, $headerLength, 2)); 
     3025            if ($crcReal != $crcStored[1]) { 
     3026                return PEAR::raiseError('_decodeGzip(): header CRC check failed', HTTP_REQUEST_ERROR_GZIP_CRC); 
     3027            } 
     3028            $headerLength += 2; 
     3029        } 
     3030        // unpacked data CRC and size at the end of encoded data 
     3031        $tmp = unpack('V2', substr($data, -8)); 
     3032        $dataCrc  = $tmp[1]; 
     3033        $dataSize = $tmp[2]; 
     3034 
     3035        // finally, call the gzinflate() function 
     3036        // don't pass $dataSize to gzinflate, see bugs #13135, #14370 
     3037        $unpacked = gzinflate(substr($data, $headerLength, -8)); 
     3038        if (false === $unpacked) { 
     3039            return PEAR::raiseError('_decodeGzip(): gzinflate() call failed', HTTP_REQUEST_ERROR_GZIP_READ); 
     3040        } elseif ($dataSize != strlen($unpacked)) { 
     3041            return PEAR::raiseError('_decodeGzip(): data size check failed', HTTP_REQUEST_ERROR_GZIP_READ); 
     3042        } elseif ((0xffffffff & $dataCrc) != (0xffffffff & crc32($unpacked))) { 
     3043            return PEAR::raiseError('_decodeGzip(): data CRC check failed', HTTP_REQUEST_ERROR_GZIP_CRC); 
     3044        } 
     3045        if (HTTP_REQUEST_MBSTRING) { 
     3046            mb_internal_encoding($oldEncoding); 
     3047        } 
     3048        return $unpacked; 
     3049    } 
     3050} // End class HTTP_Response 
     3051?> 
     3052>>>>>>> .merge-right.r23124 
Note: See TracChangeset for help on using the changeset viewer.