Changeset 4926 for OpenPNE/trunk
- Timestamp:
- Jan 12, 2008, 5:19:46 AM (15 years ago)
- Location:
- OpenPNE/trunk/lib/include/HTTP
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
OpenPNE/trunk/lib/include/HTTP/Request.php
r2 r4926 1 1 <?php 2 // +-----------------------------------------------------------------------+ 3 // | Copyright (c) 2002-2003, Richard Heyes | 4 // | All rights reserved. | 5 // | | 6 // | Redistribution and use in source and binary forms, with or without | 7 // | modification, are permitted provided that the following conditions | 8 // | are met: | 9 // | | 10 // | o Redistributions of source code must retain the above copyright | 11 // | notice, this list of conditions and the following disclaimer. | 12 // | o Redistributions in binary form must reproduce the above copyright | 13 // | notice, this list of conditions and the following disclaimer in the | 14 // | documentation and/or other materials provided with the distribution.| 15 // | o The names of the authors may not be used to endorse or promote | 16 // | products derived from this software without specific prior written | 17 // | permission. | 18 // | | 19 // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 20 // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 21 // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 22 // | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 23 // | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 24 // | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 25 // | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 26 // | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 27 // | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 28 // | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 29 // | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 30 // | | 31 // +-----------------------------------------------------------------------+ 32 // | Author: Richard Heyes <richard@phpguru.org> | 33 // +-----------------------------------------------------------------------+ 34 // 35 // $Id: Request.php,v 1.43 2005/11/06 18:29:14 avb Exp $ 36 // 37 // HTTP_Request Class 38 // 39 // Simple example, (Fetches yahoo.com and displays it): 40 // 41 // $a = &new HTTP_Request('http://www.yahoo.com/'); 42 // $a->sendRequest(); 43 // echo $a->getResponseBody(); 44 // 45 2 /** 3 * Class for performing HTTP requests 4 * 5 * PHP versions 4 and 5 6 * 7 * LICENSE: 8 * 9 * Copyright (c) 2002-2007, Richard Heyes 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 16 * o Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * o Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * o The names of the authors may not be used to endorse or promote 22 * products derived from this software without specific prior written 23 * permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * @category HTTP 38 * @package HTTP_Request 39 * @author Richard Heyes <richard@phpguru.org> 40 * @author Alexey Borzov <avb@php.net> 41 * @copyright 2002-2007 Richard Heyes 42 * @license http://opensource.org/licenses/bsd-license.php New BSD License 43 * @version CVS: $Id: Request.php,v 1.58 2007/10/26 13:45:56 avb Exp $ 44 * @link http://pear.php.net/package/HTTP_Request/ 45 */ 46 47 /** 48 * PEAR and PEAR_Error classes (for error handling) 49 */ 46 50 require_once 'PEAR.php'; 51 /** 52 * Socket class 53 */ 47 54 require_once 'Net/Socket.php'; 55 /** 56 * URL handling class 57 */ 48 58 require_once 'Net/URL.php'; 49 59 60 /**#@+ 61 * Constants for HTTP request methods 62 */ 50 63 define('HTTP_REQUEST_METHOD_GET', 'GET', true); 51 64 define('HTTP_REQUEST_METHOD_HEAD', 'HEAD', true); … … 55 68 define('HTTP_REQUEST_METHOD_OPTIONS', 'OPTIONS', true); 56 69 define('HTTP_REQUEST_METHOD_TRACE', 'TRACE', true); 57 70 /**#@-*/ 71 72 /**#@+ 73 * Constants for HTTP request error codes 74 */ 75 define('HTTP_REQUEST_ERROR_FILE', 1); 76 define('HTTP_REQUEST_ERROR_URL', 2); 77 define('HTTP_REQUEST_ERROR_PROXY', 4); 78 define('HTTP_REQUEST_ERROR_REDIRECTS', 8); 79 define('HTTP_REQUEST_ERROR_RESPONSE', 16); 80 define('HTTP_REQUEST_ERROR_GZIP_METHOD', 32); 81 define('HTTP_REQUEST_ERROR_GZIP_READ', 64); 82 define('HTTP_REQUEST_ERROR_GZIP_DATA', 128); 83 define('HTTP_REQUEST_ERROR_GZIP_CRC', 256); 84 /**#@-*/ 85 86 /**#@+ 87 * Constants for HTTP protocol versions 88 */ 58 89 define('HTTP_REQUEST_HTTP_VER_1_0', '1.0', true); 59 90 define('HTTP_REQUEST_HTTP_VER_1_1', '1.1', true); 60 61 class HTTP_Request { 62 91 /**#@-*/ 92 93 if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) { 94 /** 95 * Whether string functions are overloaded by their mbstring equivalents 96 */ 97 define('HTTP_REQUEST_MBSTRING', true); 98 } else { 99 /** 100 * @ignore 101 */ 102 define('HTTP_REQUEST_MBSTRING', false); 103 } 104 105 /** 106 * Class for performing HTTP requests 107 * 108 * Simple example (fetches yahoo.com and displays it): 109 * <code> 110 * $a = &new HTTP_Request('http://www.yahoo.com/'); 111 * $a->sendRequest(); 112 * echo $a->getResponseBody(); 113 * </code> 114 * 115 * @category HTTP 116 * @package HTTP_Request 117 * @author Richard Heyes <richard@phpguru.org> 118 * @author Alexey Borzov <avb@php.net> 119 * @version Release: 1.4.2 120 */ 121 class HTTP_Request 122 { 123 /**#@+ 124 * @access private 125 */ 63 126 /** 64 127 * Instance of Net_URL 65 * @var objectNet_URL128 * @var Net_URL 66 129 */ 67 130 var $_url; … … 99 162 /** 100 163 * Socket object 101 * @var objectNet_Socket164 * @var Net_Socket 102 165 */ 103 166 var $_sock; … … 159 222 /** 160 223 * HTTP_Response object 161 * @var objectHTTP_Response224 * @var HTTP_Response 162 225 */ 163 226 var $_response; … … 210 273 */ 211 274 var $_socketOptions = null; 275 /**#@-*/ 212 276 213 277 /** … … 238 302 function HTTP_Request($url = '', $params = array()) 239 303 { 240 $this->_sock = &new Net_Socket();241 304 $this->_method = HTTP_REQUEST_METHOD_GET; 242 305 $this->_http = HTTP_REQUEST_HTTP_VER_1_1; … … 271 334 $this->addHeader('User-Agent', 'PEAR HTTP_Request class ( http://pear.php.net/ )'); 272 335 273 // Make sure keepalives dont knobble us336 // We don't do keep-alives by default 274 337 $this->addHeader('Connection', 'close'); 275 338 … … 279 342 } 280 343 344 // Proxy authentication (see bug #5913) 345 if (!empty($this->_proxy_user)) { 346 $this->addHeader('Proxy-Authorization', 'Basic ' . base64_encode($this->_proxy_user . ':' . $this->_proxy_pass)); 347 } 348 281 349 // Use gzip encoding if possible 282 // Avoid gzip encoding if using multibyte functions (see #1781) 283 if (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http && extension_loaded('zlib') && 284 0 == (2 & ini_get('mbstring.func_overload'))) { 285 350 if (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http && extension_loaded('zlib')) { 286 351 $this->addHeader('Accept-Encoding', 'gzip'); 287 352 } … … 344 409 $this->addHeader('Host', $this->_generateHostHeader()); 345 410 } 346 } 347 411 412 // set '/' instead of empty path rather than check later (see bug #8662) 413 if (empty($this->_url->path)) { 414 $this->_url->path = '/'; 415 } 416 } 417 418 /** 419 * Returns the current request URL 420 * 421 * @return string Current request URL 422 * @access public 423 */ 424 function getUrl() 425 { 426 return empty($this->_url)? '': $this->_url->getUrl(); 427 } 428 348 429 /** 349 430 * Sets a proxy to be used … … 506 587 { 507 588 if (!is_array($fileName) && !is_readable($fileName)) { 508 return PEAR::raiseError("File '{$fileName}' is not readable" );589 return PEAR::raiseError("File '{$fileName}' is not readable", HTTP_REQUEST_ERROR_FILE); 509 590 } elseif (is_array($fileName)) { 510 591 foreach ($fileName as $name) { 511 592 if (!is_readable($name)) { 512 return PEAR::raiseError("File '{$name}' is not readable" );593 return PEAR::raiseError("File '{$name}' is not readable", HTTP_REQUEST_ERROR_FILE); 513 594 } 514 595 } … … 528 609 * @param bool Whether data is preencoded or not, default = already encoded 529 610 * @access public 530 * @deprecated deprecated since 1.3.0, method addBody() should be used instead611 * @deprecated deprecated since 1.3.0, method setBody() should be used instead 531 612 */ 532 613 function addRawPostData($postdata, $preencoded = true) … … 596 677 { 597 678 if (!is_a($this->_url, 'Net_URL')) { 598 return PEAR::raiseError('No URL given .');679 return PEAR::raiseError('No URL given', HTTP_REQUEST_ERROR_URL); 599 680 } 600 681 … … 606 687 if (strcasecmp($this->_url->protocol, 'https') == 0 AND function_exists('file_get_contents') AND extension_loaded('openssl')) { 607 688 if (isset($this->_proxy_host)) { 608 return PEAR::raiseError('HTTPS proxies are not supported .');689 return PEAR::raiseError('HTTPS proxies are not supported', HTTP_REQUEST_ERROR_PROXY); 609 690 } 610 691 $host = 'ssl://' . $host; … … 615 696 ini_set('magic_quotes_runtime', false); 616 697 617 // If this is a second request, we may get away without 618 // re-connecting if they're on the same server 619 $err = $this->_sock->connect($host, $port, null, $this->_timeout, $this->_socketOptions); 698 // RFC 2068, section 19.7.1: A client MUST NOT send the Keep-Alive 699 // connection token to a proxy server... 700 if (isset($this->_proxy_host) && !empty($this->_requestHeaders['connection']) && 701 'Keep-Alive' == $this->_requestHeaders['connection']) 702 { 703 $this->removeHeader('connection'); 704 } 705 706 $keepAlive = (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http && empty($this->_requestHeaders['connection'])) || 707 (!empty($this->_requestHeaders['connection']) && 'Keep-Alive' == $this->_requestHeaders['connection']); 708 $sockets = &PEAR::getStaticProperty('HTTP_Request', 'sockets'); 709 $sockKey = $host . ':' . $port; 710 unset($this->_sock); 711 712 // There is a connected socket in the "static" property? 713 if ($keepAlive && !empty($sockets[$sockKey]) && 714 !empty($sockets[$sockKey]->fp)) 715 { 716 $this->_sock =& $sockets[$sockKey]; 717 $err = null; 718 } else { 719 $this->_notify('connect'); 720 $this->_sock =& new Net_Socket(); 721 $err = $this->_sock->connect($host, $port, null, $this->_timeout, $this->_socketOptions); 722 } 620 723 PEAR::isError($err) or $err = $this->_sock->write($this->_buildRequest()); 621 724 … … 629 732 // Read the response 630 733 $this->_response = &new HTTP_Response($this->_sock, $this->_listeners); 631 $err = $this->_response->process($this->_saveBody && $saveBody); 734 $err = $this->_response->process( 735 $this->_saveBody && $saveBody, 736 HTTP_REQUEST_METHOD_HEAD != $this->_method 737 ); 738 739 if ($keepAlive) { 740 $keepAlive = (isset($this->_response->_headers['content-length']) 741 || (isset($this->_response->_headers['transfer-encoding']) 742 && strtolower($this->_response->_headers['transfer-encoding']) == 'chunked')); 743 if ($keepAlive) { 744 if (isset($this->_response->_headers['connection'])) { 745 $keepAlive = strtolower($this->_response->_headers['connection']) == 'keep-alive'; 746 } else { 747 $keepAlive = 'HTTP/'.HTTP_REQUEST_HTTP_VER_1_1 == $this->_response->_protocol; 748 } 749 } 750 } 632 751 } 633 752 … … 638 757 } 639 758 759 if (!$keepAlive) { 760 $this->disconnect(); 761 // Store the connected socket in "static" property 762 } elseif (empty($sockets[$sockKey]) || empty($sockets[$sockKey]->fp)) { 763 $sockets[$sockKey] =& $this->_sock; 764 } 640 765 641 766 // Check for redirection … … 682 807 // Too many redirects 683 808 } elseif ($this->_allowRedirects AND $this->_redirects > $this->_maxRedirects) { 684 return PEAR::raiseError('Too many redirects'); 685 } 686 687 $this->_sock->disconnect(); 809 return PEAR::raiseError('Too many redirects', HTTP_REQUEST_ERROR_REDIRECTS); 810 } 688 811 689 812 return true; 813 } 814 815 /** 816 * Disconnect the socket, if connected. Only useful if using Keep-Alive. 817 * 818 * @access public 819 */ 820 function disconnect() 821 { 822 if (!empty($this->_sock) && !empty($this->_sock->fp)) { 823 $this->_notify('disconnect'); 824 $this->_sock->disconnect(); 825 } 690 826 } 691 827 … … 756 892 $host = isset($this->_proxy_host) ? $this->_url->protocol . '://' . $this->_url->host : ''; 757 893 $port = (isset($this->_proxy_host) AND $this->_url->port != 80) ? ':' . $this->_url->port : ''; 758 $path = (empty($this->_url->path)? '/': $this->_url->path). $querystring;894 $path = $this->_url->path . $querystring; 759 895 $url = $host . $port . $path; 760 896 897 if (!strlen($url)) { 898 $url = '/'; 899 } 900 761 901 $request = $this->_method . ' ' . $url . ' HTTP/' . $this->_http . "\r\n"; 762 902 763 903 if (in_array($this->_method, $this->_bodyDisallowed) || 764 ( HTTP_REQUEST_METHOD_POST != $this->_method && empty($this->_body))||765 (HTTP_REQUEST_METHOD_POST != $this->_method && empty($this->_postData) && empty($this->_postFiles))) {766 904 (0 == strlen($this->_body) && (HTTP_REQUEST_METHOD_POST != $this->_method || 905 (empty($this->_postData) && empty($this->_postFiles))))) 906 { 767 907 $this->removeHeader('Content-Type'); 768 908 } else { … … 786 926 // No post data or wrong method, so simply add a final CRLF 787 927 if (in_array($this->_method, $this->_bodyDisallowed) || 788 (HTTP_REQUEST_METHOD_POST != $this->_method && empty($this->_body))) {928 (HTTP_REQUEST_METHOD_POST != $this->_method && 0 == strlen($this->_body))) { 789 929 790 930 $request .= "\r\n"; … … 834 974 $postdata .= '--' . $boundary . "--\r\n"; 835 975 } 836 $request .= 'Content-Length: ' . strlen($postdata) . "\r\n\r\n"; 976 $request .= 'Content-Length: ' . 977 (HTTP_REQUEST_MBSTRING? mb_strlen($postdata, 'iso-8859-1'): strlen($postdata)) . 978 "\r\n\r\n"; 837 979 $request .= $postdata; 838 980 839 981 // Explicitly set request body 840 } elseif (!empty($this->_body)) { 841 842 $request .= 'Content-Length: ' . strlen($this->_body) . "\r\n\r\n"; 982 } elseif (0 < strlen($this->_body)) { 983 984 $request .= 'Content-Length: ' . 985 (HTTP_REQUEST_MBSTRING? mb_strlen($this->_body, 'iso-8859-1'): strlen($this->_body)) . 986 "\r\n\r\n"; 843 987 $request .= $this->_body; 988 989 // Terminate headers with CRLF on POST request with no body, too 990 } else { 991 992 $request .= "\r\n"; 844 993 } 845 994 … … 854 1003 * @param mixed item's values 855 1004 * @return array array with the following items: array('item name', 'item value'); 1005 * @access private 856 1006 */ 857 1007 function _flattenArray($name, $values) … … 880 1030 * the object's events 881 1031 * 882 * @param object HTTP_Request_Listener instance to attach 883 * @return boolean whether the listener was successfully attached 1032 * Events sent by HTTP_Request object 1033 * - 'connect': on connection to server 1034 * - 'sentRequest': after the request was sent 1035 * - 'disconnect': on disconnection from server 1036 * 1037 * Events sent by HTTP_Response object 1038 * - 'gotHeaders': after receiving response headers (headers are passed in $data) 1039 * - 'tick': on receiving a part of response body (the part is passed in $data) 1040 * - 'gzTick': on receiving a gzip-encoded part of response body (ditto) 1041 * - 'gotBody': after receiving the response body (passes the decoded body in $data if it was gzipped) 1042 * 1043 * @param HTTP_Request_Listener listener to attach 1044 * @return boolean whether the listener was successfully attached 884 1045 * @access public 885 1046 */ … … 897 1058 * Removes a Listener from the list of listeners 898 1059 * 899 * @param object HTTP_Request_Listener instanceto detach900 * @return boolean whether the listener was successfully detached1060 * @param HTTP_Request_Listener listener to detach 1061 * @return boolean whether the listener was successfully detached 901 1062 * @access public 902 1063 */ … … 914 1075 /** 915 1076 * Notifies all registered listeners of an event. 916 *917 * Events sent by HTTP_Request object918 * 'sentRequest': after the request was sent919 * Events sent by HTTP_Response object920 * 'gotHeaders': after receiving response headers (headers are passed in $data)921 * 'tick': on receiving a part of response body (the part is passed in $data)922 * 'gzTick': on receiving a gzip-encoded part of response body (ditto)923 * 'gotBody': after receiving the response body (passes the decoded body in $data if it was gzipped)924 1077 * 925 1078 * @param string Event name 926 1079 * @param mixed Additional data 927 1080 * @access private 1081 * @see HTTP_Request::attach() 928 1082 */ 929 1083 function _notify($event, $data = null) … … 937 1091 938 1092 /** 939 * Response class to complement the Request class 940 */ 1093 * Response class to complement the Request class 1094 * 1095 * @category HTTP 1096 * @package HTTP_Request 1097 * @author Richard Heyes <richard@phpguru.org> 1098 * @author Alexey Borzov <avb@php.net> 1099 * @version Release: 1.4.2 1100 */ 941 1101 class HTTP_Response 942 1102 { 943 1103 /** 944 1104 * Socket object 945 * @var object1105 * @var Net_Socket 946 1106 */ 947 1107 var $_sock; … … 989 1149 var $_listeners = array(); 990 1150 1151 /** 1152 * Bytes left to read from message-body 1153 * @var null|int 1154 */ 1155 var $_toRead; 1156 991 1157 /** 992 1158 * Constructor 993 1159 * 994 * @param object Net_Socket socket to read the response from 995 * @param array listeners attached to request 996 * @return mixed PEAR Error on error, true otherwise 1160 * @param Net_Socket socket to read the response from 1161 * @param array listeners attached to request 997 1162 */ 998 1163 function HTTP_Response(&$sock, &$listeners) … … 1013 1178 * this to false if downloading a LARGE file and using a Listener. 1014 1179 * This is assumed to be true if body is gzip-encoded. 1180 * @param bool Whether the response can actually have a message-body. 1181 * Will be set to false for HEAD requests. 1015 1182 * @throws PEAR_Error 1016 1183 * @return mixed true on success, PEAR_Error in case of malformed response 1017 1184 */ 1018 function process($saveBody = true )1185 function process($saveBody = true, $canHaveBody = true) 1019 1186 { 1020 1187 do { 1021 1188 $line = $this->_sock->readLine(); 1022 1189 if (sscanf($line, 'HTTP/%s %s', $http_version, $returncode) != 2) { 1023 return PEAR::raiseError('Malformed response .');1190 return PEAR::raiseError('Malformed response', HTTP_REQUEST_ERROR_RESPONSE); 1024 1191 } else { 1025 1192 $this->_protocol = 'HTTP/' . $http_version; … … 1032 1199 1033 1200 $this->_notify('gotHeaders', $this->_headers); 1201 1202 // RFC 2616, section 4.4: 1203 // 1. Any response message which "MUST NOT" include a message-body ... 1204 // is always terminated by the first empty line after the header fields 1205 // 3. ... If a message is received with both a 1206 // Transfer-Encoding header field and a Content-Length header field, 1207 // the latter MUST be ignored. 1208 $canHaveBody = $canHaveBody && $this->_code >= 200 && 1209 $this->_code != 204 && $this->_code != 304; 1034 1210 1035 1211 // If response body is present, read it and decode … … 1037 1213 $gzipped = isset($this->_headers['content-encoding']) && ('gzip' == $this->_headers['content-encoding']); 1038 1214 $hasBody = false; 1039 if (!isset($this->_headers['content-length']) || 0 != $this->_headers['content-length']) { 1040 while (!$this->_sock->eof()) { 1215 if ($canHaveBody && ($chunked || !isset($this->_headers['content-length']) || 1216 0 != $this->_headers['content-length'])) 1217 { 1218 if ($chunked || !isset($this->_headers['content-length'])) { 1219 $this->_toRead = null; 1220 } else { 1221 $this->_toRead = $this->_headers['content-length']; 1222 } 1223 while (!$this->_sock->eof() && (is_null($this->_toRead) || 0 < $this->_toRead)) { 1041 1224 if ($chunked) { 1042 1225 $data = $this->_readChunked(); 1226 } elseif (is_null($this->_toRead)) { 1227 $data = $this->_sock->read(4096); 1043 1228 } else { 1044 $data = $this->_sock->read(4096); 1229 $data = $this->_sock->read(min(4096, $this->_toRead)); 1230 $this->_toRead -= HTTP_REQUEST_MBSTRING? mb_strlen($data, 'iso-8859-1'): strlen($data); 1045 1231 } 1046 1232 if ('' == $data) { … … 1055 1241 } 1056 1242 } 1243 1057 1244 if ($hasBody) { 1058 1245 // Uncompress the body if needed 1059 1246 if ($gzipped) { 1060 $this->_body = gzinflate(substr($this->_body, 10)); 1247 $body = $this->_decodeGzip($this->_body); 1248 if (PEAR::isError($body)) { 1249 return $body; 1250 } 1251 $this->_body = $body; 1061 1252 $this->_notify('gotBody', $this->_body); 1062 1253 } else { … … 1076 1267 function _processHeader($header) 1077 1268 { 1269 if (false === strpos($header, ':')) { 1270 return; 1271 } 1078 1272 list($headername, $headervalue) = explode(':', $header, 2); 1079 1273 $headername = strtolower($headername); … … 1166 1360 } 1167 1361 $data = $this->_sock->read($this->_chunkLength); 1168 $this->_chunkLength -= strlen($data);1362 $this->_chunkLength -= HTTP_REQUEST_MBSTRING? mb_strlen($data, 'iso-8859-1'): strlen($data); 1169 1363 if (0 == $this->_chunkLength) { 1170 1364 $this->_sock->readLine(); // Trailing CRLF … … 1188 1382 } 1189 1383 } 1384 1385 1386 /** 1387 * Decodes the message-body encoded by gzip 1388 * 1389 * The real decoding work is done by gzinflate() built-in function, this 1390 * method only parses the header and checks data for compliance with 1391 * RFC 1952 1392 * 1393 * @access private 1394 * @param string gzip-encoded data 1395 * @return string decoded data 1396 */ 1397 function _decodeGzip($data) 1398 { 1399 if (HTTP_REQUEST_MBSTRING) { 1400 $oldEncoding = mb_internal_encoding(); 1401 mb_internal_encoding('iso-8859-1'); 1402 } 1403 $length = strlen($data); 1404 // If it doesn't look like gzip-encoded data, don't bother 1405 if (18 > $length || strcmp(substr($data, 0, 2), "\x1f\x8b")) { 1406 return $data; 1407 } 1408 $method = ord(substr($data, 2, 1)); 1409 if (8 != $method) { 1410 return PEAR::raiseError('_decodeGzip(): unknown compression method', HTTP_REQUEST_ERROR_GZIP_METHOD); 1411 } 1412 $flags = ord(substr($data, 3, 1)); 1413 if ($flags & 224) { 1414 return PEAR::raiseError('_decodeGzip(): reserved bits are set', HTTP_REQUEST_ERROR_GZIP_DATA); 1415 } 1416 1417 // header is 10 bytes minimum. may be longer, though. 1418 $headerLength = 10; 1419 // extra fields, need to skip 'em 1420 if ($flags & 4) { 1421 if ($length - $headerLength - 2 < 8) { 1422 return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); 1423 } 1424 $extraLength = unpack('v', substr($data, 10, 2)); 1425 if ($length - $headerLength - 2 - $extraLength[1] < 8) { 1426 return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); 1427 } 1428 $headerLength += $extraLength[1] + 2; 1429 } 1430 // file name, need to skip that 1431 if ($flags & 8) { 1432 if ($length - $headerLength - 1 < 8) { 1433 return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); 1434 } 1435 $filenameLength = strpos(substr($data, $headerLength), chr(0)); 1436 if (false === $filenameLength || $length - $headerLength - $filenameLength - 1 < 8) { 1437 return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); 1438 } 1439 $headerLength += $filenameLength + 1; 1440 } 1441 // comment, need to skip that also 1442 if ($flags & 16) { 1443 if ($length - $headerLength - 1 < 8) { 1444 return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); 1445 } 1446 $commentLength = strpos(substr($data, $headerLength), chr(0)); 1447 if (false === $commentLength || $length - $headerLength - $commentLength - 1 < 8) { 1448 return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); 1449 } 1450 $headerLength += $commentLength + 1; 1451 } 1452 // have a CRC for header. let's check 1453 if ($flags & 1) { 1454 if ($length - $headerLength - 2 < 8) { 1455 return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); 1456 } 1457 $crcReal = 0xffff & crc32(substr($data, 0, $headerLength)); 1458 $crcStored = unpack('v', substr($data, $headerLength, 2)); 1459 if ($crcReal != $crcStored[1]) { 1460 return PEAR::raiseError('_decodeGzip(): header CRC check failed', HTTP_REQUEST_ERROR_GZIP_CRC); 1461 } 1462 $headerLength += 2; 1463 } 1464 // unpacked data CRC and size at the end of encoded data 1465 $tmp = unpack('V2', substr($data, -8)); 1466 $dataCrc = $tmp[1]; 1467 $dataSize = $tmp[2]; 1468 1469 // finally, call the gzinflate() function 1470 $unpacked = @gzinflate(substr($data, $headerLength, -8), $dataSize); 1471 if (false === $unpacked) { 1472 return PEAR::raiseError('_decodeGzip(): gzinflate() call failed', HTTP_REQUEST_ERROR_GZIP_READ); 1473 } elseif ($dataSize != strlen($unpacked)) { 1474 return PEAR::raiseError('_decodeGzip(): data size check failed', HTTP_REQUEST_ERROR_GZIP_READ); 1475 } elseif ((0xffffffff & $dataCrc) != (0xffffffff & crc32($unpacked))) { 1476 return PEAR::raiseError('_decodeGzip(): data CRC check failed', HTTP_REQUEST_ERROR_GZIP_CRC); 1477 } 1478 if (HTTP_REQUEST_MBSTRING) { 1479 mb_internal_encoding($oldEncoding); 1480 } 1481 return $unpacked; 1482 } 1190 1483 } // End class HTTP_Response 1191 1484 ?> -
OpenPNE/trunk/lib/include/HTTP/Request/Listener.php
r2 r4926 1 1 <?php 2 // +-----------------------------------------------------------------------+ 3 // | Copyright (c) 2002-2003, Richard Heyes | 4 // | All rights reserved. | 5 // | | 6 // | Redistribution and use in source and binary forms, with or without | 7 // | modification, are permitted provided that the following conditions | 8 // | are met: | 9 // | | 10 // | o Redistributions of source code must retain the above copyright | 11 // | notice, this list of conditions and the following disclaimer. | 12 // | o Redistributions in binary form must reproduce the above copyright | 13 // | notice, this list of conditions and the following disclaimer in the | 14 // | documentation and/or other materials provided with the distribution.| 15 // | o The names of the authors may not be used to endorse or promote | 16 // | products derived from this software without specific prior written | 17 // | permission. | 18 // | | 19 // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 20 // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 21 // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 22 // | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 23 // | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 24 // | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 25 // | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 26 // | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 27 // | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 28 // | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 29 // | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 30 // | | 31 // +-----------------------------------------------------------------------+ 32 // | Author: Alexey Borzov <avb@php.net> | 33 // +-----------------------------------------------------------------------+ 34 // 35 // $Id: Listener.php,v 1.2 2003/10/26 10:28:29 avb Exp $ 36 // 2 /** 3 * Listener for HTTP_Request and HTTP_Response objects 4 * 5 * PHP versions 4 and 5 6 * 7 * LICENSE: 8 * 9 * Copyright (c) 2002-2007, Richard Heyes 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 16 * o Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * o Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * o The names of the authors may not be used to endorse or promote 22 * products derived from this software without specific prior written 23 * permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * @category HTTP 38 * @package HTTP_Request 39 * @author Alexey Borzov <avb@php.net> 40 * @copyright 2002-2007 Richard Heyes 41 * @license http://opensource.org/licenses/bsd-license.php New BSD License 42 * @version CVS: $Id: Listener.php,v 1.3 2007/05/18 10:33:31 avb Exp $ 43 * @link http://pear.php.net/package/HTTP_Request/ 44 */ 37 45 38 46 /** 47 * Listener for HTTP_Request and HTTP_Response objects 48 * 39 49 * This class implements the Observer part of a Subject-Observer 40 * design pattern. It listens to the events sent by a 41 * HTTP_Request or HTTP_Response instance. 50 * design pattern. 42 51 * 43 * @package HTTP_Request 44 * @author Alexey Borzov <avb@php.net> 45 * @version $Revision: 1.2 $ 52 * @category HTTP 53 * @package HTTP_Request 54 * @author Alexey Borzov <avb@php.net> 55 * @version Release: 1.4.2 46 56 */ 47 57 class HTTP_Request_Listener
Note: See TracChangeset
for help on using the changeset viewer.