HTTP协议学习贴(含PHP实现学习)
来源:http://www.phpchina.cn/bbs/viewthread.php?tid=566&extra=&page=1
作者:feifengxlq
相关:http://bbs.0511.com/archiver/?tid-4344.html
HTTP协议基础(一)
HTTP(HyperTextTransferProtocol)是超文本传输协议的缩写,它用于传送WWW方式的数据,关于HTTP协议的详细内容请参考RFC2616。HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求,请求头包含请求的方法、URI、协议版本、以及包含请求修饰符、客户信息和内容的类似于MIME的消息结构。服务器以一个状态行作为响应,相应的内容包括消息协议的版本,成功或者错误编码加上包含服务器信息、实体元信息以及可能的实体内容。
通常HTTP消息包括客户机向服务器的请求消息和服务器向客户机的响应消息。这两种类型的消息由一个起始行,一个或者多个头域,一个只是头域结束的空行和可选的消息体组成。HTTP的头域包括通用头,请求头,响应头和实体头四个部分。每个头域由一个域名,冒号(:)和域值三部分组成。域名是大小写无关的,域值前可以添加任何数量的空格符,头域可以被扩展为多行,在每行开始处,使用至少一个空格或制表符。
通用头域
通用头域包含请求和响应消息都支持的头域,通用头域包含Cache-Control、Connection、Date、Pragma、Transfer-Encoding、Upgrade、Via。对通用头域的扩展要求通讯双方都支持此扩展,如果存在不支持的通用头域,一般将会作为实体头域处理。下面简单介绍几个在UPnP消息中使用的通用头域。
Cache-Control头域
Cache-Control指定请求和响应遵循的缓存机制。在请求消息或响应消息中设置Cache-Control并不会修改另一个消息处理过程中的缓存处理过程。请求时的缓存指令包括no-cache、no-store、max-age、max-stale、min-fresh、only-if-cached,响应消息中的指令包括public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age。各个消息中的指令含义如下:
Public指示响应可被任何缓存区缓存。
Private指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效。
no-cache指示请求或响应消息不能缓存
no-store用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。
max-age指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。
min-fresh指示客户机可以接收响应时间小于当前时间加上指定时间的响应。
max-stale指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。
Date头域
Date头域表示消息发送的时间,时间的描述格式由rfc822定义。例如,Date:Mon,31Dec200104:25:57GMT。Date描述的时间表示世界标准时,换算成本地时间,需要知道用户所在的时区。
Pragma头域
Pragma头域用来包含实现特定的指令,最常用的是Pragma:no-cache。在HTTP/1.1协议中,它的含义和Cache-Control:no-cache相同。
请求消息
请求消息的第一行为下面的格式:
MethodSPRequest-URISPHTTP-VersionCRLFMethod表示对于Request-URI完成的方法,这个字段是大小写敏感的,包括OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE。方法GET和HEAD应该被所有的通用WEB服务器支持,其他所有方法的实现是可选的。GET方法取回由Request-URI标识的信息。HEAD方法也是取回由Request-URI标识的信息,只是可以在响应时,不返回消息体。POST方法可以请求服务器接收包含在请求中的实体信息,可以用于提交表单,向新闻组、BBS、邮件群组和数据库发送消息。
SP表示空格。Request-URI遵循URI格式,在此字段为星号(*)时,说明请求并不用于某个特定的资源地址,而是用于服务器本身。HTTP-Version表示支持的HTTP版本,例如为HTTP/1.1。CRLF表示换行回车符。请求头域允许客户端向服务器传递关于请求或者关于客户机的附加信息。请求头域可能包含下列字段Accept、Accept-Charset、Accept-Encoding、Accept-Language、Authorization、From、Host、If-Modified-Since、If-Match、If-None-Match、If-Range、If-Range、If-Unmodified-Since、Max-Forwards、Proxy-Authorization、Range、Referer、User-Agent。对请求头域的扩展要求通讯双方都支持,如果存在不支持的请求头域,一般将会作为实体头域处理。
典型的请求消息:
GEThttp://download.microtool.de:80/somedata.exe
Host:download.microtool.de
Accept:*/*
Pragma:no-cache
Cache-Control:no-cache
Referer:http://download.microtool.de/
User-Agent:Mozilla/4.04[en](Win95;I;Nav)
Range:bytes=554554-
上例第一行表示HTTP客户端(可能是浏览器、下载程序)通过GET方法获得指定URL下的文件。棕色的部分表示请求头域的信息,绿色的部分表示通用头部分。
Host头域
Host头域指定请求资源的Intenet主机和端口号,必须表示请求url的原始服务器或网关的位置。HTTP/1.1请求必须包含主机头域,否则系统会以400状态码返回。
Referer头域
Referer头域允许客户端指定请求uri的源资源地址,这可以允许服务器生成回退链表,可用来登陆、优化cache等。他也允许废除的或错误的连接由于维护的目的被追踪。如果请求的uri没有自己的uri地址,Referer不能被发送。如果指定的是部分uri地址,则此地址应该是一个相对地址。
Range头域
Range头域可以请求实体的一个或者多个子范围。例如,
表示头500个字节:bytes=0-499
表示第二个500字节:bytes=500-999
表示最后500个字节:bytes=-500
表示500字节以后的范围:bytes=500-
第一个和最后一个字节:bytes=0-0,-1
同时指定几个范围:bytes=500-600,601-999
但是服务器可以忽略此请求头,如果无条件GET包含Range请求头,响应会以状态码206(PartialContent)返回而不是以200(OK)。
User-Agent头域
User-Agent头域的内容包含发出请求的用户信息。
响应消息
响应消息的第一行为下面的格式:
HTTP-VersionSPStatus-CodeSPReason-PhraseCRLF
HTTP-Version表示支持的HTTP版本,例如为HTTP/1.1。Status-Code是一个三个数字的结果代码。Reason-Phrase给Status-Code提供一个简单的文本描述。Status-Code主要用于机器自动识别,Reason-Phrase主要用于帮助用户理解。Status-Code的第一个数字定义响应的类别,后两个数字没有分类的作用。第一个数字可能取5个不同的值:
1xx:信息响应类,表示接收到请求并且继续处理
2xx:处理成功响应类,表示动作被成功接收、理解和接受
3xx:重定向响应类,为了完成指定的动作,必须接受进一步处理
4xx:客户端错误,客户请求包含语法错误或者是不能正确执行
5xx:服务端错误,服务器不能正确执行一个正确的请求
响应头域允许服务器传递不能放在状态行的附加信息,这些域主要描述服务器的信息和Request-URI进一步的信息。响应头域包含Age、Location、Proxy-Authenticate、Public、Retry-After、Server、Vary、Warning、WWW-Authenticate。对响应头域的扩展要求通讯双方都支持,如果存在不支持的响应头域,一般将会作为实体头域处理。
典型的响应消息:
HTTP/1.0200OK
Date:Mon,31Dec200104:25:57GMT
Server:Apache/1.3.14(Unix)
Content-type:text/html
Last-modified:Tue,17Apr200106:46:28GMT
Etag:"a030f020ac7c01:1e9f"
Content-length:39725426
Content-range:bytes554554-40279979/40279980
上例第一行表示HTTP服务端响应一个GET方法。棕色的部分表示响应头域的信息,绿色的部分表示通用头部分,红色的部分表示实体头域的信息。
Location响应头
Location响应头用于重定向接收者到一个新URI地址。
Server响应头
Server响应头包含处理请求的原始服务器的软件信息。此域能包含多个产品标识和注释,产品标识一般按照重要性排序。
实体
请求消息和响应消息都可以包含实体信息,实体信息一般由实体头域和实体组成。实体头域包含关于实体的原信息,实体头包括Allow、Content-Base、Content-Encoding、Content-Language、Content-Length、Content-Location、Content-MD5、Content-Range、Content-Type、Etag、Expires、Last-Modified、extension-header。extension-header允许客户端定义新的实体头,但是这些域可能无法未接受方识别。实体可以是一个经过编码的字节流,它的编码方式由Content-Encoding或Content-Type定义,它的长度由Content-Length或Content-Range定义。
Content-Type实体头
Content-Type实体头用于向接收方指示实体的介质类型,指定HEAD方法送到接收方的实体介质类型,或GET方法发送的请求介质类型Content-Range实体头
Content-Range实体头用于指定整个实体中的一部分的插入位置,他也指示了整个实体的长度。在服务器向客户返回一个部分响应,它必须描述响应覆盖的范围和整个实体长度。一般格式:
Content-Range:bytes-unitSPfirst-byte-pos-last-byte-pos/entity-legth
例如,传送头500个字节次字段的形式:Content-Range:bytes0-499/1234如果一个http消息包含此节(例如,对范围请求的响应或对一系列范围的重叠请求),Content-Range表示传送的范围,Content-Length表示实际传送的字节数。
Last-modified实体头
Last-modified实体头指定服务器上保存内容的最后修订时间。
HTTP协议基础(二)
HTTP 协议定义服务器端和客户端之间文件传输的沟通方式。目前HTTP协议的版本是Http1.1。RFC 2616描述了HTTP协议的具体信息。
这个协议已经成为浏览器和Web站点之间的标准。
当我上网的时候底层是如何进行交互的?
当访问者点击一个超链接的时候,将会给浏览器提交一个URL地址。通过这个URL地址,浏览器便知道去链接那个网站并去取得具体的页面文件(也可能是一张图片,一个pdf文件)。
HTTP工作的基础就是,连接一个服务器并开始传输文件到浏览器。
HTTP传输的基本过程
在http传输的过程中,被称为客户端的请求者向服务器请求一个文件。
最基本的过程是:
1 客户端连接一个主机;
2 服务器接收连接,
3 客户端请求一个文件,
4 服务器发送一个应答.
实例
我们看几个典型的过程
首先,我们想访问本页面。在浏览器上敲入“http://www.maketop.net/resource/rs_041112_02.php”.浏览器将连接www.maketop.net然后发送:
>> GET /resource/rs_041112_02.php Http1.1
>> Host: www.maketop.net
>> Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg,
>> Accept-Language: en
>> Accept-Encoding: gzip, deflate
>> User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 Firefox/0.10
>> Connection: Keep-Alive
>>
解释:浏览器请求页面“/resource/rs_041112_02.php”。并使用HTTP1.1协议。并告诉服务器你的浏览器是Firefox0.10。操作系统是Windows XP。 浏览器希望保持与www.maketop.net之间的连接,并请求获得多的文件,包括网页中的图片。翻译成语言上面是:
>> 用HTTP1.1协议获得 /resource/rs_041112_02.php
>> 访问的主机是: www.maketop.net
>> 接收的文件包括了: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg,
>> 使用的语言是: en
>> 接收的编码方式(浏览器能够解释的)是: gzip, deflate
>> 用户的浏览器信息:Windows XP的操作系统 Firefox/0.10的浏览器
>> 保持连接: 还要去图片
>>
www.maketop.net的服务器发出响应:
<< HTTP/1.1 200 OK
<< Date: Mon, 12 Mar 2004 19:12:16 GMT
<< Server: Apache/1.3.31 (Unix) mod_throttle/3.1.2
<< Last-Modified: Fri, 22 Sep 2004 14:16:18
<< ETag: "dd7b6e-d29-39cb69b2"
<< Accept-Ranges: bytes
<< Content-Length: 3369
<< Connection: close
<< Content-Type: text/html
<<
<< File content goes here
浏览器并从服务器的响应中获得服务器的信息:比如运行在Apache。
上面翻译成翻译成语言上面就是
<< HTTP1.1协议方式有效
<< 当前时间是: Mon, 12 Mar 2004 19:12:16 GMT
<< 服务器是: Apache/1.3.31 (Unix) mod_throttle/3.1.2
<< 最后一次修改: Fri, 22 Sep 2004 14:16:18
<< ETag: "dd7b6e-d29-39cb69b2"
<< Accept-Ranges: bytes
<< Content-Length: 3369
<< Connection: close
<< Content-Type: text/html
<<
<< File content goes here
PHP实现代码学习(一)
define( 'HTTP_V10', '1.0');
define( 'HTTP_V11', '1.1');
define( 'HTTP_STATUS_CONTINUE', 100 );
define( 'HTTP_STATUS_SWITCHING_PROTOCOLS', 101 );
define( 'HTTP_STATUS_OK', 200 );
define( 'HTTP_STATUS_CREATED', 201 );
define( 'HTTP_STATUS_ACCEPTED', 202 );
define( 'HTTP_STATUS_NON_AUTHORITATIVE', 203 );
define( 'HTTP_STATUS_NO_CONTENT', 204 );
define( 'HTTP_STATUS_RESET_CONTENT', 205 );
define( 'HTTP_STATUS_PARTIAL_CONTENT', 206 );
define( 'HTTP_STATUS_MULTIPLE_CHOICES', 300 );
define( 'HTTP_STATUS_MOVED_PERMANENTLY', 301 );
define( 'HTTP_STATUS_FOUND', 302 );
define( 'HTTP_STATUS_SEE_OTHER', 303 );
define( 'HTTP_STATUS_NOT_MODIFIED', 304 );
define( 'HTTP_STATUS_USE_PROXY', 305 );
define( 'HTTP_STATUS_TEMPORARY_REDIRECT', 307 );
define( 'HTTP_STATUS_BAD_REQUEST', 400 );
define( 'HTTP_STATUS_UNAUTHORIZED', 401 );
define( 'HTTP_STATUS_FORBIDDEN', 403 );
define( 'HTTP_STATUS_NOT_FOUND', 404 );
define( 'HTTP_STATUS_METHOD_NOT_ALLOWED', 405 );
define( 'HTTP_STATUS_NOT_ACCEPTABLE', 406 );
define( 'HTTP_STATUS_PROXY_AUTH_REQUIRED', 407 );
define( 'HTTP_STATUS_REQUEST_TIMEOUT', 408 );
define( 'HTTP_STATUS_CONFLICT', 409 );
define( 'HTTP_STATUS_GONE', 410 );
define( 'HTTP_STATUS_REQUEST_TOO_LARGE', 413 );
define( 'HTTP_STATUS_URI_TOO_LONG', 414 );
define( 'HTTP_STATUS_SERVER_ERROR', 500 );
define( 'HTTP_STATUS_NOT_IMPLEMENTED', 501 );
define( 'HTTP_STATUS_BAD_GATEWAY', 502 );
define( 'HTTP_STATUS_SERVICE_UNAVAILABLE', 503 );
define( 'HTTP_STATUS_VERSION_NOT_SUPPORTED', 505 );
基本常量定义~~跳过~
var $_headers;//数组,控制通用头域 ,比如Cache-Control、Connection、Date、Pragma、Upgrade、Via等
var $_debug;//调试出错信息
//初始化
function http_header() {
$this->_headers = Array();
$this->_debug = '';
} // End Of function http_header()
//得到 通用头域 信息
function get_header( $header_name ) {
$header_name = $this->_format_header_name( $header_name );
if (isset($this->_headers[$header_name]))
return $this->_headers[$header_name];
else
return null;
} // End of function get()
//设置 通用头域 信息
function set_header( $header_name, $value ) {
if ($value != '') {
$header_name = $this->_format_header_name( $header_name );
$this->_headers[$header_name] = $value;
}
} // End of function set()
//重设通用头域 信息
function reset() {
if ( count( $this->_headers ) > 0 ) $this->_headers = array();
$this->_debug .= "/n--------------- RESETED ---------------/n";
} // End of function clear()
//将通用头域 信息转化成合适的报文格式
function serialize_headers() {
$str = '';
foreach ( $this->_headers as $name=>$value) {
$str .= "$name: $value" . HTTP_CRLF;
}
return $str;
} // End of function serialize_headers()
//将通用头域 信息格式化~~
function _format_header_name( $header_name ) {
$formatted = str_replace( '-', ' ', strtolower( $header_name ) );
$formatted = ucwords( $formatted );
$formatted = str_replace( ' ', '-', $formatted );
return $formatted;
}
function add_debug_info( $data ) {
$this->_debug .= $data;
}
function get_debug_info() {
return $this->_debug;
}
} // End Of Class http_header
简单的就不注释了~
class http_response_header extends http_header {
var $cookies_headers;
function http_response_header() {
$this->cookies_headers = array();
http_header::http_header();
} // End of function http_response_header()
function deserialize_headers( $flat_headers ) {
$flat_headers = preg_replace( "/^" . HTTP_CRLF . "/", '', $flat_headers );
$tmp_headers = split( HTTP_CRLF, $flat_headers );
if (preg_match("'HTTP/(d.d)s+(d+).*'i", $tmp_headers[0], $matches )) {
$this->set_header( 'Protocol-Version', $matches[1] );
$this->set_header( 'Status', $matches[2] );
}
array_shift( $tmp_headers );
foreach( $tmp_headers as $index=>$value ) {
$pos = strpos( $value, ':' );
if ( $pos ) {
$key = substr( $value, 0, $pos );
$value = trim( substr( $value, $pos +1) );
if ( strtoupper($key) == 'SET-COOKIE' )
$this->cookies_headers[] = $value;
else
$this->set_header( $key, $value );
}
}
} // End of function deserialize_headers()
function reset() {
if ( count( $this->cookies_headers ) > 0 ) $this->cookies_headers = array();
http_header::reset();
}
}
class http_request_message extends http_header {
var $body;
function http_request_message() {
$this->body = '';
http_header::http_header();
} // End of function http_message()
function reset() {
$this->body = '';
http_header::reset();
}
}
/******************************************************************************************
* class http_response_message
******************************************************************************************/
class http_response_message extends http_response_header {
var $body;
var $cookies;
function http_response_message() {
$this->cookies = new http_cookie();
$this->body = '';
http_response_header::http_response_header();
} // End of function http_response_message()
function get_status() {
if ( $this->get_header( 'Status' ) != null )
return (integer)$this->get_header( 'Status' );
else
return -1;
}
function get_protocol_version() {
if ( $this->get_header( 'Protocol-Version' ) != null )
return $this->get_header( 'Protocol-Version' );
else
return HTTP_V10;
}
function get_content_type() {
$this->get_header( 'Content-Type' );
}
function get_body() {
return $this->body;
}
function reset() {
$this->body = '';
http_response_header::reset();
}
function parse_cookies( $host ) {
for ( $i = 0; $i < count( $this->cookies_headers ); $i++ )
$this->cookies->parse( $this->cookies_headers[$i], $host );
}
}
/******************************************************************************************
* class http_cookie
******************************************************************************************/
class http_cookie {
var $cookies;
function http_cookie() {
$this->cookies = array();
} // End of function http_cookies()
function _now() {
return strtotime( gmdate( "l, d-F-Y H:i:s", time() ) );
} // End of function _now()
function _timestamp( $date ) {
if ( $date == '' ) return $this->_now()+3600;
$time = strtotime( $date );
return ($time>0?$time:$this->_now()+3600);
} // End of function _timestamp()
function get( $current_domain, $current_path ) {
$cookie_str = '';
$now = $this->_now();
$new_cookies = array();
foreach( $this->cookies as $cookie_name => $cookie_data ) {
if ($cookie_data['expires'] > $now) {
$new_cookies[$cookie_name] = $cookie_data;
$domain = preg_quote( $cookie_data['domain'] );
$path = preg_quote( $cookie_data['path'] );
if ( preg_match( "'.*$domain$'i", $current_domain ) && preg_match( "'^$path.*'i", $current_path ) )
$cookie_str .= $cookie_name . '=' . $cookie_data['value'] . '; ';
}
}
$this->cookies = $new_cookies;
return $cookie_str;
} // End of function get()
function set( $name, $value, $domain, $path, $expires ) {
$this->cookies[$name] = array( 'value' => $value,
'domain' => $domain,
'path' => $path,
'expires' => $this->_timestamp( $expires )
);
} // End of function set()
function parse( $cookie_str, $host ) {
$cookie_str = str_replace( '; ', ';', $cookie_str ) . ';';
$data = split( ';', $cookie_str );
$value_str = $data[0];
$cookie_param = 'domain=';
$start = strpos( $cookie_str, $cookie_param );
if ( $start > 0 ) {
$domain = substr( $cookie_str, $start + strlen( $cookie_param ) );
$domain = substr( $domain, 0, strpos( $domain, ';' ) );
} else
$domain = $host;
$cookie_param = 'expires=';
$start = strpos( $cookie_str, $cookie_param );
if ( $start > 0 ) {
$expires = substr( $cookie_str, $start + strlen( $cookie_param ) );
$expires = substr( $expires, 0, strpos( $expires, ';' ) );
} else
$expires = '';
$cookie_param = 'path=';
$start = strpos( $cookie_str, $cookie_param );
if ( $start > 0 ) {
$path = substr( $cookie_str, $start + strlen( $cookie_param ) );
$path = substr( $path, 0, strpos( $path, ';' ) );
} else
$path = '/';
$sep_pos = strpos( $value_str, '=');
if ($sep_pos){
$name = substr( $value_str, 0, $sep_pos );
$value = substr( $value_str, $sep_pos+1 );
$this->set( $name, $value, $domain, $path, $expires );
}
} // End of function parse()
} // End of class http_cookie
这些比较简单就不一一注释了~
HTTP类及一些相关的函数
HTTP类及一些相关的函数
熟悉socket的应该容易看动的~由于我要忙着考研了(保研没保上),所以不能一一注释了~
不熟悉socket的自己看看手册吧~
var $_socket;
var $host;
var $port;
var $http_version;
var $user_agent;
var $errstr;
var $connected;
var $uri;
var $_proxy_host;
var $_proxy_port;
var $_proxy_login;
var $_proxy_pwd;
var $_use_proxy;
var $_auth_login;
var $_auth_pwd;
var $_response;
var $_request;
var $_keep_alive;
function http( $http_version = HTTP_V10, $keep_alive = false, $auth = false ) {
$this->http_version = $http_version;
$this->connected = false;
$this->user_agent = 'CosmoHttp/1.1 (compatible; MSIE 5.5; Linux)';
$this->host = '';
$this->port = 80;
$this->errstr = '';
$this->_keep_alive = $keep_alive;
$this->_proxy_host = '';
$this->_proxy_port = -1;
$this->_proxy_login = '';
$this->_proxy_pwd = '';
$this->_auth_login = '';
$this->_auth_pwd = '';
$this->_use_proxy = false;
$this->_response = new http_response_message();
$this->_request = new http_request_message();
// Basic Authentification added by Mate Jovic, 2002-18-06, jovic@matoma.de
if( is_array($auth) && count($auth) == 2 ){
$this->_auth_login = $auth[0];
$this->_auth_pwd = $auth[1];
}
} // End of Constuctor
function use_proxy( $host, $port, $proxy_login = null, $proxy_pwd = null ) {
// Proxy auth not yet supported
$this->http_version = HTTP_V10;
$this->_keep_alive = false;
$this->_proxy_host = $host;
$this->_proxy_port = $port;
$this->_proxy_login = $proxy_login;
$this->_proxy_pwd = $proxy_pwd;
$this->_use_proxy = true;
}
function set_request_header( $name, $value ) {
$this->_request->set_header( $name, $value );
}
function get_response_body() {
return $this->_response->body;
}
function get_response() {
return $this->_response;
}
function head( $uri ) {
$this->uri = $uri;
if ( ($this->_keep_alive && !$this->connected) || !$this->_keep_alive ) {
if ( !$this->_connect() ) {
$this->errstr = 'Could not connect to ' . $this->host;
return -1;
}
}
$http_cookie = $this->_response->cookies->get( $this->host, $this->_current_directory( $uri ) );
if ($this->_use_proxy) {
$this->_request->set_header( 'Host', $this->host . ':' . $this->port );
$this->_request->set_header( 'Proxy-Connection', ($this->_keep_alive?'Keep-Alive':'Close') );
if ( $this->_proxy_login != '' ) $this->_request->set_header( 'Proxy-Authorization', "Basic " . base64_encode( $this->_proxy_login . ":" . $this->_proxy_pwd ) );
$uri = 'http://' . $this->host . ':' . $this->port . $uri;
} else {
$this->_request->set_header( 'Host', $this->host );
$this->_request->set_header( 'Connection', ($this->_keep_alive?'Keep-Alive':'Close') );
}
if ( $this->_auth_login != '' ) $this->_request->set_header( 'Authorization', "Basic " . base64_encode( $this->_auth_login . ":" . $this->_auth_pwd ) );
$this->_request->set_header( 'User-Agent', $this->user_agent );
$this->_request->set_header( 'Accept', '*/*' );
$this->_request->set_header( 'Cookie', $http_cookie );
$cmd = "HEAD $uri HTTP/" . $this->http_version . HTTP_CRLF .
$this->_request->serialize_headers() .
HTTP_CRLF;
fwrite( $this->_socket, $cmd );
$this->_request->add_debug_info( $cmd );
$this->_get_response( false );
if ($this->_socket && !$this->_keep_alive) $this->disconnect();
if ( $this->_response->get_header( 'Connection' ) != null ) {
if ( $this->_keep_alive && strtolower( $this->_response->get_header( 'Connection' ) ) == 'close' ) {
$this->_keep_alive = false;
$this->disconnect();
}
}
if ( $this->_response->get_status() == HTTP_STATUS_USE_PROXY ) {
$location = $this->_parse_location( $this->_response->get_header( 'Location' ) );
$this->disconnect();
$this->use_proxy( $location['host'], $location['port'] );
$this->head( $this->uri );
}
return $this->_response->get_header( 'Status' );
} // End of function head()
function get( $uri, $follow_redirects = true, $referer = '' ) {
$this->uri = $uri;
if ( ($this->_keep_alive && !$this->connected) || !$this->_keep_alive ) {
if ( !$this->_connect() ) {
$this->errstr = 'Could not connect to ' . $this->host;
return -1;
}
}
if ($this->_use_proxy) {
$this->_request->set_header( 'Host', $this->host . ':' . $this->port );
$this->_request->set_header( 'Proxy-Connection', ($this->_keep_alive?'Keep-Alive':'Close') );
if ( $this->_proxy_login != '' ) $this->_request->set_header( 'Proxy-Authorization', "Basic " . base64_encode( $this->_proxy_login . ":" . $this->_proxy_pwd ) );
$uri = 'http://' . $this->host . ':' . $this->port . $uri;
} else {
$this->_request->set_header( 'Host', $this->host );
$this->_request->set_header( 'Connection', ($this->_keep_alive?'Keep-Alive':'Close') );
$this->_request->set_header( 'Pragma', 'no-cache' );
$this->_request->set_header( 'Cache-Control', 'no-cache' );
}
if ( $this->_auth_login != '' ) $this->_request->set_header( 'Authorization', "Basic " . base64_encode( $this->_auth_login . ":" . $this->_auth_pwd ) );
$http_cookie = $this->_response->cookies->get( $this->host, $this->_current_directory( $uri ) );
$this->_request->set_header( 'User-Agent', $this->user_agent );
$this->_request->set_header( 'Accept', '*/*' );
$this->_request->set_header( 'Referer', $referer );
$this->_request->set_header( 'Cookie', $http_cookie );
$cmd = "GET $uri HTTP/" . $this->http_version . HTTP_CRLF .
$this->_request->serialize_headers() .
HTTP_CRLF;
fwrite( $this->_socket, $cmd );
$this->_request->add_debug_info( $cmd );
$this->_get_response();
if ($this->_socket && !$this->_keep_alive) $this->disconnect();
if ( $this->_response->get_header( 'Connection' ) != null ) {
if ( $this->_keep_alive && strtolower( $this->_response->get_header( 'Connection' ) ) == 'close' ) {
$this->_keep_alive = false;
$this->disconnect();
}
}
if ( $follow_redirects && ($this->_response->get_status() == HTTP_STATUS_MOVED_PERMANENTLY || $this->_response->get_status() == HTTP_STATUS_FOUND || $this->_response->get_status() == HTTP_STATUS_SEE_OTHER ) ) {
if ( $this->_response->get_header( 'Location' ) != null ) {
$this->_redirect( $this->_response->get_header( 'Location' ) );
}
}
if ( $this->_response->get_status() == HTTP_STATUS_USE_PROXY ) {
$location = $this->_parse_location( $this->_response->get_header( 'Location' ) );
$this->disconnect();
$this->use_proxy( $location['host'], $location['port'] );
$this->get( $this->uri, $referer );
}
return $this->_response->get_status();
} // End of function get()
function multipart_post( $uri, &$form_fields, $form_files = null, $follow_redirects = true, $referer = '' ) {
$this->uri = $uri;
if ( ($this->_keep_alive && !$this->connected) || !$this->_keep_alive ) {
if ( !$this->_connect() ) {
$this->errstr = 'Could not connect to ' . $this->host;
return -1;
}
}
$boundary = uniqid('------------------');
$http_cookie = $this->_response->cookies->get( $this->host, $this->_current_directory( $uri ) );
$body = $this->_merge_multipart_form_data( $boundary, $form_fields, $form_files );
$this->_request->body = $body . HTTP_CRLF;
$content_length = strlen( $body );
if ($this->_use_proxy) {
$this->_request->set_header( 'Host', $this->host . ':' . $this->port );
$this->_request->set_header( 'Proxy-Connection', ($this->_keep_alive?'Keep-Alive':'Close') );
if ( $this->_proxy_login != '' ) $this->_request->set_header( 'Proxy-Authorization', "Basic " . base64_encode( $this->_proxy_login . ":" . $this->_proxy_pwd ) );
$uri = 'http://' . $this->host . ':' . $this->port . $uri;
} else {
$this->_request->set_header( 'Host', $this->host );
$this->_request->set_header( 'Connection', ($this->_keep_alive?'Keep-Alive':'Close') );
$this->_request->set_header( 'Pragma', 'no-cache' );
$this->_request->set_header( 'Cache-Control', 'no-cache' );
}
if ( $this->_auth_login != '' ) $this->_request->set_header( 'Authorization', "Basic " . base64_encode( $this->_auth_login . ":" . $this->_auth_pwd ) );
$this->_request->set_header( 'Accept', '*/*' );
$this->_request->set_header( 'Content-Type', 'multipart/form-data; boundary=' . $boundary );
$this->_request->set_header( 'User-Agent', $this->user_agent );
$this->_request->set_header( 'Content-Length', $content_length );
$this->_request->set_header( 'Cookie', $http_cookie );
$this->_request->set_header( 'Referer', $referer );
$req_header = "POST $uri HTTP/" . $this->http_version . HTTP_CRLF .
$this->_request->serialize_headers() .
HTTP_CRLF;
fwrite( $this->_socket, $req_header );
usleep(10);
fwrite( $this->_socket, $this->_request->body );
$this->_request->add_debug_info( $req_header );
$this->_get_response();
if ($this->_socket && !$this->_keep_alive) $this->disconnect();
if ( $this->_response->get_header( 'Connection' ) != null ) {
if ( $this->_keep_alive && strtolower( $this->_response->get_header( 'Connection' ) ) == 'close' ) {
$this->_keep_alive = false;
$this->disconnect();
}
}
if ( $follow_redirects && ($this->_response->get_status() == HTTP_STATUS_MOVED_PERMANENTLY || $this->_response->get_status() == HTTP_STATUS_FOUND || $this->_response->get_status() == HTTP_STATUS_SEE_OTHER ) ) {
if ( $this->_response->get_header( 'Location') != null ) {
$this->_redirect( $this->_response->get_header( 'Location') );
}
}
if ( $this->_response->get_status() == HTTP_STATUS_USE_PROXY ) {
$location = $this->_parse_location( $this->_response->get_header( 'Location') );
$this->disconnect();
$this->use_proxy( $location['host'], $location['port'] );
$this->multipart_post( $this->uri, $form_fields, $form_files, $referer );
}
return $this->_response->get_status();
} // End of function multipart_post()
function post( $uri, &$form_data, $follow_redirects = true, $referer = '' ) {
$this->uri = $uri;
if ( ($this->_keep_alive && !$this->connected) || !$this->_keep_alive ) {
if ( !$this->_connect() ) {
$this->errstr = 'Could not connect to ' . $this->host;
return -1;
}
}
$http_cookie = $this->_response->cookies->get( $this->host, $this->_current_directory( $uri ) );
$body = substr( $this->_merge_form_data( $form_data ), 1 );
$this->_request->body = $body . HTTP_CRLF . HTTP_CRLF;
$content_length = strlen( $body );
if ($this->_use_proxy) {
$this->_request->set_header( 'Host', $this->host . ':' . $this->port );
$this->_request->set_header( 'Proxy-Connection', ($this->_keep_alive?'Keep-Alive':'Close') );
if ( $this->_proxy_login != '' ) $this->_request->set_header( 'Proxy-Authorization', "Basic " . base64_encode( $this->_proxy_login . ":" . $this->_proxy_pwd ) );
$uri = 'http://' . $this->host . ':' . $this->port . $uri;
} else {
$this->_request->set_header( 'Host', $this->host );
$this->_request->set_header( 'Connection', ($this->_keep_alive?'Keep-Alive':'Close') );
$this->_request->set_header( 'Pragma', 'no-cache' );
$this->_request->set_header( 'Cache-Control', 'no-cache' );
}
if ( $this->_auth_login != '' ) $this->_request->set_header( 'Authorization', "Basic " . base64_encode( $this->_auth_login . ":" . $this->_auth_pwd ) );
$this->_request->set_header( 'Accept', '*/*' );
$this->_request->set_header( 'Content-Type', 'application/x-www-form-urlencoded' );
$this->_request->set_header( 'User-Agent', $this->user_agent );
$this->_request->set_header( 'Content-Length', $content_length );
$this->_request->set_header( 'Cookie', $http_cookie );
$this->_request->set_header( 'Referer', $referer );
$req_header = "POST $uri HTTP/" . $this->http_version . HTTP_CRLF .
$this->_request->serialize_headers() .
HTTP_CRLF;
fwrite( $this->_socket, $req_header );
usleep( 10 );
fwrite( $this->_socket, $this->_request->body );
$this->_request->add_debug_info( $req_header );
$this->_get_response();
if ($this->_socket && !$this->_keep_alive) $this->disconnect();
if ( $this->_response->get_header( 'Connection' ) != null ) {
if ( $this->_keep_alive && strtolower( $this->_response->get_header( 'Connection' ) ) == 'close' ) {
$this->_keep_alive = false;
$this->disconnect();
}
}
if ( $follow_redirects && ($this->_response->get_status() == HTTP_STATUS_MOVED_PERMANENTLY || $this->_response->get_status() == HTTP_STATUS_FOUND || $this->_response->get_status() == HTTP_STATUS_SEE_OTHER ) ) {
if ( $this->_response->get_header( 'Location' ) != null ) {
$this->_redirect( $this->_response->get_header( 'Location' ) );
}
}
if ( $this->_response->get_status() == HTTP_STATUS_USE_PROXY ) {
$location = $this->_parse_location( $this->_response->get_header( 'Location' ) );
$this->disconnect();
$this->use_proxy( $location['host'], $location['port'] );
$this->post( $this->uri, $form_data, $referer );
}
return $this->_response->get_status();
} // End of function post()
function post_xml( $uri, $xml_data, $follow_redirects = true, $referer = '' ) {
$this->uri = $uri;
if ( ($this->_keep_alive && !$this->connected) || !$this->_keep_alive ) {
if ( !$this->_connect() ) {
$this->errstr = 'Could not connect to ' . $this->host;
return -1;
}
}
$http_cookie = $this->_response->cookies->get( $this->host, $this->_current_directory( $uri ) );
$body = $xml_data;
$this->_request->body = $body . HTTP_CRLF . HTTP_CRLF;
$content_length = strlen( $body );
if ($this->_use_proxy) {
$this->_request->set_header( 'Host', $this->host . ':' . $this->port );
$this->_request->set_header( 'Proxy-Connection', ($this->_keep_alive?'Keep-Alive':'Close') );
if ( $this->_proxy_login != '' ) $this->_request->set_header( 'Proxy-Authorization', "Basic " . base64_encode( $this->_proxy_login . ":" . $this->_proxy_pwd ) );
$uri = 'http://' . $this->host . ':' . $this->port . $uri;
} else {
$this->_request->set_header( 'Host', $this->host );
$this->_request->set_header( 'Connection', ($this->_keep_alive?'Keep-Alive':'Close') );
$this->_request->set_header( 'Pragma', 'no-cache' );
$this->_request->set_header( 'Cache-Control', 'no-cache' );
}
if ( $this->_auth_login != '' ) $this->_request->set_header( 'Authorization', "Basic " . base64_encode( $this->_auth_login . ":" . $this->_auth_pwd ) );
$this->_request->set_header( 'Accept', '*/*' );
$this->_request->set_header( 'Content-Type', 'text/xml; charset=utf-8' );
$this->_request->set_header( 'User-Agent', $this->user_agent );
$this->_request->set_header( 'Content-Length', $content_length );
$this->_request->set_header( 'Cookie', $http_cookie );
$this->_request->set_header( 'Referer', $referer );
$req_header = "POST $uri HTTP/" . $this->http_version . HTTP_CRLF .
$this->_request->serialize_headers() .
HTTP_CRLF;
fwrite( $this->_socket, $req_header );
usleep( 10 );
fwrite( $this->_socket, $this->_request->body );
$this->_request->add_debug_info( $req_header );
$this->_get_response();
if ($this->_socket && !$this->_keep_alive) $this->disconnect();
if ( $this->_response->get_header( 'Connection' ) != null ) {
if ( $this->_keep_alive && strtolower( $this->_response->get_header( 'Connection' ) ) == 'close' ) {
$this->_keep_alive = false;
$this->disconnect();
}
}
if ( $follow_redirects && ($this->_response->get_status() == HTTP_STATUS_MOVED_PERMANENTLY || $this->_response->get_status() == HTTP_STATUS_FOUND || $this->_response->get_status() == HTTP_STATUS_SEE_OTHER ) ) {
if ( $this->_response->get_header( 'Location' ) != null ) {
$this->_redirect( $this->_response->get_header( 'Location' ) );
}
}
if ( $this->_response->get_status() == HTTP_STATUS_USE_PROXY ) {
$location = $this->_parse_location( $this->_response->get_header( 'Location' ) );
$this->disconnect();
$this->use_proxy( $location['host'], $location['port'] );
$this->post( $this->uri, $form_data, $referer );
}
return $this->_response->get_status();
} // End of function post_xml()
function disconnect() {
if ($this->_socket && $this->connected) {
fclose($this->_socket);
$this->connected = false;
}
} // End of function disconnect()
/********************************************************************************
* Private functions
********************************************************************************/
function _connect( ) {
if ( $this->host == '' ) user_error( 'Class HTTP->_connect() : host property not set !' , E_ERROR );
if (!$this->_use_proxy)
$this->_socket = fsockopen( $this->host, $this->port, $errno, $errstr, 10 );
else
$this->_socket = fsockopen( $this->_proxy_host, $this->_proxy_port, $errno, $errstr, 10 );
$this->errstr = $errstr;
$this->connected = ($this->_socket == true);
return $this->connected;
} // End of function connect()
function _merge_multipart_form_data( $boundary, &$form_fields, &$form_files ) {
$boundary = '--' . $boundary;
$multipart_body = '';
foreach ( $form_fields as $name => $data) {
$multipart_body .= $boundary . HTTP_CRLF;
$multipart_body .= 'Content-Disposition: form-data; name="' . $name . '"' . HTTP_CRLF;
$multipart_body .= HTTP_CRLF;
$multipart_body .= $data . HTTP_CRLF;
}
if ( isset($form_files) ) {
foreach ( $form_files as $data) {
$multipart_body .= $boundary . HTTP_CRLF;
$multipart_body .= 'Content-Disposition: form-data; name="' . $data['name'] . '"; filename="' . $data['filename'] . '"' . HTTP_CRLF;
if ($data['content-type']!='')
$multipart_body .= 'Content-Type: ' . $data['content-type'] . HTTP_CRLF;
else
$multipart_body .= 'Content-Type: application/octet-stream' . HTTP_CRLF;
$multipart_body .= HTTP_CRLF;
$multipart_body .= $data['data'] . HTTP_CRLF;
}
}
$multipart_body .= $boundary . '--' . HTTP_CRLF;
return $multipart_body;
} // End of function _merge_multipart_form_data()
function _merge_form_data( &$param_array, $param_name = '' ) {
$params = '';
$format = ($param_name !=''?'&'.$param_name.'[%s]=%s':'&%s=%s');
foreach ( $param_array as $key=>$value ) {
if ( !is_array( $value ) )
$params .= sprintf( $format, $key, urlencode( $value ) );
else
$params .= $this->_merge_form_data( $param_array[$key], $key );
}
return $params;
} // End of function _merge_form_data()
function _current_directory( $uri ) {
$tmp = split( '/', $uri );
array_pop($tmp);
$current_dir = implode( '/', $tmp ) . '/';
return ($current_dir!=''?$current_dir:'/');
} // End of function _current_directory()
function _get_response( $get_body = true ) {
$this->_response->reset();
$this->_request->reset();
$header = '';
$body = '';
$continue = true;
while ($continue) {
$header = '';
// Read the Response Headers
while ( (($line = fgets( $this->_socket, 4096 )) != HTTP_CRLF || $header == '') && !feof( $this->_socket ) ) {
if ($line != HTTP_CRLF) $header .= $line;
}
$this->_response->deserialize_headers( $header );
$this->_response->parse_cookies( $this->host );
$this->_response->add_debug_info( $header );
$continue = ($this->_response->get_status() == HTTP_STATUS_CONTINUE);
if ($continue) fwrite( $this->_socket, HTTP_CRLF );
}
if ( !$get_body ) return;
// Read the Response Body
if ( strtolower( $this->_response->get_header( 'Transfer-Encoding' ) ) != 'chunked' && !$this->_keep_alive ) {
while ( !feof( $this->_socket ) ) {
$body .= fread( $this->_socket, 4096 );
}
} else {
if ( $this->_response->get_header( 'Content-Length' ) != null ) {
$content_length = (integer)$this->_response->get_header( 'Content-Length' );
$body = fread( $this->_socket, $content_length );
} else {
if ( $this->_response->get_header( 'Transfer-Encoding' ) != null ) {
if ( strtolower( $this->_response->get_header( 'Transfer-Encoding' ) ) == 'chunked' ) {
$chunk_size = (integer)hexdec(fgets( $this->_socket, 4096 ) );
while($chunk_size > 0) {
$body .= fread( $this->_socket, $chunk_size );
fread( $this->_socket, strlen(HTTP_CRLF) );
$chunk_size = (integer)hexdec(fgets( $this->_socket, 4096 ) );
}
// TODO : Read trailing http headers
}
}
}
}
$this->_response->body = $body;
} // End of function _get_response()
function _parse_location( $redirect_uri ) {
$parsed_url = parse_url( $redirect_uri );
$scheme = (isset($parsed_url['scheme'])?$parsed_url['scheme']:'');
$port = (isset($parsed_url['port'])?$parsed_url['port']:$this->port);
$host = (isset($parsed_url['host'])?$parsed_url['host']:$this->host);
$request_file = (isset($parsed_url['path'])?$parsed_url['path']:'');
$query_string = (isset($parsed_url['query'])?$parsed_url['query']:'');
if ( substr( $request_file, 0, 1 ) != '/' )
$request_file = $this->_current_directory( $this->uri ) . $request_file;
return array( 'scheme' => $scheme,
'port' => $port,
'host' => $host,
'request_file' => $request_file,
'query_string' => $query_string
);
} // End of function _parse_location()
function _redirect( $uri ) {
$location = $this->_parse_location( $uri );
if ( $location['host'] != $this->host || $location['port'] != $this->port ) {
$this->host = $location['host'];
$this->port = $location['port'];
if ( !$this->_use_proxy) $this->disconnect();
}
usleep( 100 );
$this->get( $location['request_file'] . '?' . $location['query_string'] );
} // End of function _redirect()
} // End of class http
示例
处理HTTP GET
POST的
/*********************************************************************
* Demonstrates the use of the get() method
*********************************************************************/
require_once( 'http.inc' );
header( 'Content-Type: text/xml' );
// Grab a RDF file from phpdeveloper.org and display it
$http_client = new http( HTTP_V11, false);
$http_client->host = 'www.phpdeveloper.org';
if ( $http_client->get( '/phpdev.rdf' ) == HTTP_STATUS_OK)
print( $http_client->get_response_body() );
else
print( 'Server returned ' . $http_client->status );
unset( $http_client );
?>
require_once( 'http.inc' );
header( 'Content-Type: text/plain' );
$form = array(
'value' => 1,
'date' => '05/20/02',
'date_fmt' => 'us',
'result' => 1,
'lang' => 'eng',
'exch' => 'USD',
'Currency' => 'EUR',
'format' => 'HTML',
'script' => '../convert/fxdaily',
'dest' => 'Get Table'
);
$http_client = new http( HTTP_V11, true );
$http_client->host = 'www.oanda.com';
$status = $http_client->post( '/convert/fxdaily', $form, 'http://www.oanda.com/convert/fxdaily' );
if ( $status == HTTP_STATUS_OK ) {
print( $http_client->get_response_body() );
} else {
print( "An error occured while requesting your file !/n" );
print_r( $http_client );
}
$http_client->disconnect();
unset( $http_client );
?>
multipart post 仅仅是个用法的例子,具体如何建议还是看下类的结构
require_once( 'http.inc' );
$fields = array( 'user' => 'GuinuX',
'password' => 'mypass',
'lang' => 'US'
);
$files = array();
$files[] = array( 'name' => 'myfile1',
'content-type' => 'text/plain',
'filename' => 'test1.txt',
'data' => 'Hello from File 1 !!!'
);
$files[] = array( 'name' => 'myfile2',
'content-type' => 'text/plain',
'filename' => 'test2.txt',
'data' => "bla bla bla/nbla bla"
);
$http_client = new http( HTTP_V11, false );
$http_client->host = 'www.myhost.com';
if ($http_client->multipart_post( '/upload.pl', $fields, $files ) == HTTP_STATUS_OK )
print($http_client->get_response_body());
else
print('Server returned status code : ' . $http_client->status);
unset( $http_client );
?>
proxy
/*********************************************************************
* Demonstrates the use of requests via proxy
*********************************************************************/
header('Content-Type: text/plain');
require_once( 'http.inc' );
$http_client = new http( HTTP_V11, false );
$http_client->host = 'www.yahoo.com';
$http_client->use_proxy( 'ns.crs.org.ni', 3128 );
if ($http_client->get( '/' ) == HTTP_STATUS_OK)
print_r( $http_client );
else
print('Server returned ' . $http_client->status );
unset( $http_client );
?>