Changeset 23164


Ignore:
Timestamp:
2013/08/30 11:10:30 (7 years ago)
Author:
m_uehara
Message:

#2348 r23143 のミスを修正

File:
1 edited

Legend:

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

    r23143 r23164  
    1 <<<<<<< .working 
    21<?php 
    32/** 
     
    561560        } 
    562561    } 
     562     
     563    function addPostDataArray($array, $preencoded = false) 
     564    { 
     565        foreach($array as $key => $val){ 
     566            $this->addPostData($key, $val, $preencoded); 
     567        } 
     568    }    
    563569 
    564570   /** 
     
    15211527} // End class HTTP_Response 
    15221528?> 
    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  */ 
    1573 require_once 'PEAR.php'; 
    1574 /** 
    1575  * Socket class 
    1576  */ 
    1577 require_once 'Net/Socket.php'; 
    1578 /** 
    1579  * URL handling class 
    1580  */ 
    1581 require_once 'Net/URL.php'; 
    1582  
    1583 /**#@+ 
    1584  * Constants for HTTP request methods 
    1585  */ 
    1586 define('HTTP_REQUEST_METHOD_GET',     'GET',     true); 
    1587 define('HTTP_REQUEST_METHOD_HEAD',    'HEAD',    true); 
    1588 define('HTTP_REQUEST_METHOD_POST',    'POST',    true); 
    1589 define('HTTP_REQUEST_METHOD_PUT',     'PUT',     true); 
    1590 define('HTTP_REQUEST_METHOD_DELETE',  'DELETE',  true); 
    1591 define('HTTP_REQUEST_METHOD_OPTIONS', 'OPTIONS', true); 
    1592 define('HTTP_REQUEST_METHOD_TRACE',   'TRACE',   true); 
    1593 /**#@-*/ 
    1594  
    1595 /**#@+ 
    1596  * Constants for HTTP request error codes 
    1597  */ 
    1598 define('HTTP_REQUEST_ERROR_FILE',             1); 
    1599 define('HTTP_REQUEST_ERROR_URL',              2); 
    1600 define('HTTP_REQUEST_ERROR_PROXY',            4); 
    1601 define('HTTP_REQUEST_ERROR_REDIRECTS',        8); 
    1602 define('HTTP_REQUEST_ERROR_RESPONSE',        16); 
    1603 define('HTTP_REQUEST_ERROR_GZIP_METHOD',     32); 
    1604 define('HTTP_REQUEST_ERROR_GZIP_READ',       64); 
    1605 define('HTTP_REQUEST_ERROR_GZIP_DATA',      128); 
    1606 define('HTTP_REQUEST_ERROR_GZIP_CRC',       256); 
    1607 /**#@-*/ 
    1608  
    1609 /**#@+ 
    1610  * Constants for HTTP protocol versions 
    1611  */ 
    1612 define('HTTP_REQUEST_HTTP_VER_1_0', '1.0', true); 
    1613 define('HTTP_REQUEST_HTTP_VER_1_1', '1.1', true); 
    1614 /**#@-*/ 
    1615  
    1616 if (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  */ 
    1644 class 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  */ 
    2660 class 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.