gusucode.com > 同城苏州黄页系统php源码程序 > lib/http.class.php

    <?
$events = array(
	# 'EVENT_NO_FUNC_INVOKE',					// 无事件函数
												// 此事件以在 base.class.php 中声明
	
	// 登陆
	'EVENT_BEFORE_LOGIN',						// 登陆以前
	'EVENT_LOGIN_SUCCEED',						// 登陆成功
	'EVENT_LOGIN_FAILED',						// 登陆失败
);
register_event($events);
?>

<?php
/**************************************************************************************************
* Class: Advanced HTTP Client
***************************************************************************************************
* Version       : 1.1
* Released      : 06-20-2002
* Last Modified : 06-10-2003
* Author        : GuinuX <guinux@cosmoplazza.com>
*
***************************************************************************************************
* Changes 
***************************************************************************************************
* 2003-06-10 : GuinuX 
*   - Fixed a bug with multiple gets and basic auth
*   - Added support for Basic proxy Authentification 
* 2003-05-25: By Michael Mauch <michael.mauch@gmx.de>
*   - Fixed two occurences of the former "status" member which is now deprecated
* 2002-09-23: GuinuX
*   - Fixed a bug to the post method with some HTTP servers
*   - Thanx to l0rd jenci <lord_jenci@bigfoot.com> for reporting this bug.
* 2002-09-07: Dirk Fokken <fokken@cross-consulting.com>
*   - Deleted trailing characters at the end of the file, right after the php closing tag, in order 
*     to fix a bug with binary requests.
* 2002-20-06: GuinuX, Major changes
*   - Turned to a more OOP style => added class http_header, http_response_header, 
*       http_request_message, http_response_message.
*       The members : status, body, response_headers, cookies, _request_headers of the http class 
*       are Deprecated.
* 2002-19-06: GuinuX, fixed some bugs in the http::_get_response() method
* 2002-18-06: By Mate Jovic <jovic@matoma.de>
*   - Added support for Basic Authentification 
*       usage: $http_client = new http( HTTP_V11, false, Array('user','pass') );
*
***************************************************************************************************
* Description:  
***************************************************************************************************
*   A HTTP client class
*   Supports : 
*           - GET, HEAD and POST methods 
*           - Http cookies 
*           - multipart/form-data AND application/x-www-form-urlencoded
*           - Chunked Transfer-Encoding 
*           - HTTP 1.0 and 1.1 protocols 
*           - Keep-Alive Connections 
*           - Proxy
*           - Basic WWW-Authentification and Proxy-Authentification 
*
***************************************************************************************************
* TODO :
***************************************************************************************************
*           - Read trailing headers for Chunked Transfer-Encoding 
***************************************************************************************************
* usage
***************************************************************************************************
* See example scripts.
*
***************************************************************************************************
* License
***************************************************************************************************
* GNU Lesser General Public License (LGPL)
* http://www.opensource.org/licenses/lgpl-license.html
*
* For any suggestions or bug report please contact me : guinux@cosmoplazza.com
***************************************************************************************************/
/***************************************************************************************************

***************************************************************************************************/
    if ( !defined('HTTP_CRLF') ) define( 'HTTP_CRLF', chr(13) . chr(10));
    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 );


/******************************************************************************************
* class http_header
******************************************************************************************/
    class http_header extends base {
        var $_headers;
        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
******************************************************************************************/
    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();
        }

    } // End of class http_response_header


/******************************************************************************************
* class http_request_message
******************************************************************************************/
    class http_request_message extends http_header {
    	
    	var $stream;
        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 $stream;
    	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 preg_replace( "/^(\r\n){2}/", '', $this->body ) ;
        }
        
        function reset() {
            $this->body = '';
            http_response_header::reset();
        }

        function parse_cookies( $host ) {
        	//pp($this->cookies_headers);
            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*24*365;
            $time = strtotime( $date );
            return ($time>0?$time:$this->_now()+3600*24*365);
        } // 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']  );
                    /*pp(' ; ',$domain,$current_domain,$path,$current_path);
                    pp(':','domain',preg_match( "'.*$domain$'i", $current_domain ));
                    pp(':','path',preg_match( "'^$path.*'i", $current_path ));*/
                    if ( preg_match( "'.*$domain$'i", $current_domain ) && preg_match( "'^$path.*'i", $current_path ) )
                    {
                    	if( !empty($cookie_str) )
                    		$cookie_str.= '; ';
                        $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   
    
/******************************************************************************************
* class http
******************************************************************************************/
    class http extends base {
        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;   
		var $referer;
		var $waiting_response = true ;

        function http( $http_version = HTTP_V10, $keep_alive = false, $auth = false ) {
            $this->http_version = $http_version;
            $this->connected    = false;
            $this->user_agent   = 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; Maxthon; .NET CLR 1.1.4322; Alexa Toolbar)';
            $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 _send_request($cmd)
        {
        	if( !is_array($cmd) )
        		fwrite( $this->_socket, $cmd );
        	else
        	{
	        	fwrite( $this->_socket, $cmd['header'] );
	            usleep( 10 );
	            fwrite( $this->_socket, $cmd['body'] );
	            $cmd = implode( '', $cmd );
        	}
        	
        	$this->_debug_log($cmd,'lastSendData.log');        	
        	$this->_request->stream = $cmd;
        }

        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 );
            
            
            if( function_exists('OnBeforeRequest') )
            	OnBeforeRequest( $this,'HEAD',$uri );
            $cmd =  "HEAD $uri HTTP/" . $this->http_version . HTTP_CRLF . 
                    $this->_request->serialize_headers() .
                    HTTP_CRLF;
            $this->_send_request($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', (!empty($referer))? $referer: $this->referer );
            $this->_request->set_header( 'Cookie', $http_cookie );
            
            if( function_exists('OnBeforeRequest') )
            	OnBeforeRequest( $this,'GET',$uri );
            $cmd =  "GET $uri HTTP/" . $this->http_version . HTTP_CRLF . 
                    $this->_request->serialize_headers() .
                    HTTP_CRLF;

            $this->_send_request($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 );
            }

            $this->referer = "http://{$this->host}{$uri}";
            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;

            $this->_send_request(array('header'=>$req_header,'body'=>$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 = '',$encoded=false ) {
            $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, '', $encoded ), 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 );
                            
            
            if( function_exists('OnBeforeRequest') )
            	OnBeforeRequest( $this,'POST',$uri );
            $req_header = "POST $uri HTTP/" . $this->http_version . HTTP_CRLF . 
                        $this->_request->serialize_headers() .
                        HTTP_CRLF;

            $this->_send_request(array('header'=>$req_header,'body'=>$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 );
			
            
            if( function_exists('OnBeforeRequest') )
            	OnBeforeRequest( $this,'POST',$uri );
            $req_header = "POST $uri HTTP/" . $this->http_version . HTTP_CRLF . 
                        $this->_request->serialize_headers() .
                        HTTP_CRLF;

            $this->_send_request(array('header'=>$req_header,'body'=>$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()

        function fullPath($url)
        {
			if( preg_match("|^/|",$url) )
				return "http://{$this->host}{$url}";
			elseif( preg_match("|^http://|i",$thePost['url']) )
				return $url;
			else
				return $this->_current_directory($this->listTemplet).$url;
        }

        /********************************************************************************
         * 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, 15 );
            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 = '', $encoded=false ) {
            $params = '';
            $format = ($param_name !=''?'&'.$param_name.'[%s]=%s':'&%s=%s');
            foreach ( $param_array as $key=>$value ) {
                if ( !is_array( $value ) )
                    $params .= sprintf( $format, $key, $encoded?$value:urlencode( $value ) );
                else
                    $params .= $this->_merge_form_data( $param_array[$key],  $key,  $encoded );
            }
            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;

            // 异步任务,不等待回应内容, 直接返回,断开连接
            if( !$this->waiting_response )
            	return ;

            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->_debug_log($header,'lastRecvHead.log');
                $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' );
                    if( $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 ) ); 
                            pp($chunk_size);
                            while($chunk_size > 0) {
                                $body .= fread( $this->_socket, $chunk_size ); 
                                fread( $this->_socket, strlen(HTTP_CRLF) ); 
                                $chunk_size = (integer)hexdec(fgets( $this->_socket, 4096 ) ); 
                                pp($chunk_size);
                            }*/
                            
                            do {
							    $data = fread( $this->_socket, 8192 );
							    if ( strlen($data) == 0 )
							        break;
							    $body.= $data;
							} while(true);
                            // TODO : Read trailing http headers
                        }
                    } 
                }
            }
            $this->_response->body = $body;
            $this->_debug_log($body,'lastRecvBody.log');
            
            $this->_response->stream = $header . HTTP_CRLF . $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()
        
        function _debug_log($str,$file,$show=false)
        {
        	if($show)
        		print $str;

        	if( !file_exists('./debug/') )
        	{
        		// echo 'no debug/';
        		return false;
        	}

        	return file_put_contents("./debug/{$this->host}.{$file}",$str);
        }

    } // End of class http
    
?>

<?
###############################
#
# loginHTTP
#
# 提供两种方式的网站登陆
# alee 2006.2,22
# alee201@163.com
#
###############################


define('LOGINWAY_NOHAVE',0);					// 不需要登陆
define('LOGINWAY_SUBMIT',1);					// 输入用户名,密码登陆
define('LOGINWAY_SAVECOOKIE',2);				// 保存Cookie 登陆

class loginHTTP extends http
{
	# 登陆
	var $login_way			 = LOGINWAY_NOHAVE;	// 登陆方式
	
	// 输入用户名,密码登陆 -- --

	/**
	 * 多个帐号列表
	 *
	 * 例如:
	 * array(  array('ID'=>'ID 1','password'=>'******'),
	 * 		   array('ID'=>'ID 2','password'=>'******'),
	 * 		   array('ID'=>'ID 3','password'=>'******')	);
	 * 
	 * @var array
	 */
	var $users				 = array();			// 用户名、密码  
	var $userInputName		 = '';				// 填写用户名的表单名
	var $passwordInputName	 = '';				// 填写密码的表单名
	var $logingSubmitData	 = array();			// 其他需要提交的固定参数
	var $logingSubmitUri	 = '';				// 登陆提交地址
	var $logingRefererUrl	 = '';				// 登陆填写页面
	var $loginSucceed ;
	
	
	// 保存Cookie 登陆 -- --

	var $loginCookie		 = '';

	// 
	var $hideInputs			 = array();			// 用于在提交post 前,下载一些网页上的隐藏表单值


##############################################################

	function _getRandUser()
	{
		if( empty($this->users) )
			return array();

		shuffle( $this->users ); shuffle( $this->users ); shuffle( $this->users );
		return $this->users[0] ;
	}
	
	function _getUri( $url )
	{
		if( preg_match( "|^http://|",$url ) )
			return str_replace("http://{$this->host}",'',$url);
		return $url;
	}

##############################################################

	function advancedHTTP( $http_version = HTTP_V10, $keep_alive = false, $auth = false )
	{
		$this->http( $http_version, $keep_alive, $auth );

		// 登陆
		// if( $this->login_way != LOGINWAY_NOHAVE )
		// 		$this->login();
	}
	

	function get_hideinput_value( $when )
	{
		$data = array();
		
		if( empty($this->hideInputs[$when]) )
			return $data ;

		foreach( $this->hideInputs[$when] as $thispage)
		{
			// 打开网页
			if( !$this->get( $thispage['uri'], isset($thispage['follow'])?$thispage['follow']:true, isset($thispage['referer'])?$thispage['referer']:'referer' ) )
				continue ;

			// 寻找需要摘取的 隐藏表单值
			foreach($thispage['inputs'] as $name)
			{
				// 发现指定表单
				if( preg_match( "|<input[^>\"']+name=['\"]?{$name}['\"]?[^>\"']*>|isU", $this->_response->body, $result ) )
				{
					// 获取 表单值
					if( preg_match( "|<input[^>\"']+value=['\"]?([^'\"\s])['\"]?[^>\"']*>|isU", $result[0], $re ) )
						$data[$name] = $re[1];
				}
			}
		}
		
		return $data;
	}	
	
	/**
	 * 设置对象的配置参数
	 *
	 * @param array $configs
	 */
	function setMyConfigs( $configs )
	{
		foreach ($configs as $key=>$value)
			$this->$key = $value;
	}
	
	function login()
	{

		switch ( $this->login_way )
		{
			case LOGINWAY_SAVECOOKIE:
				$re = true ;
				break;

			case LOGINWAY_SUBMIT:						// 提交登陆
				
				// 固定提交的数据
				$formdata = $this->logingSubmitData ;
				// 用户名密码

				list( $formdata [$this->userInputName], $formdata [$this->passwordInputName] )
							= array_values( $this->_getRandUser() );
				// 获得 登陆页面的隐藏表单
				$formdata+= $this->get_hideinput_value( EVENT_BEFORE_LOGIN );
				
				// 触发事件
				$this->_touch_user_event( EVENT_BEFORE_LOGIN );
				
				$this->post( $this->logingSubmitUri, $formdata, false, $this->logingRefererUrl, true );
				$re = $this->loginSucceed->check( $this->_response->stream );

				break;

			default :
				$re = true;
				break;
		}
		
		if( $re )
			$this->_touch_user_event( EVENT_LOGIN_SUCCEED );
		else
			$this->_touch_user_event( EVENT_LOGIN_FAILED );
		
		return $re;
			
	}

}
?>