<?php /************************************************************ * 描述:HTTP操做類 * 做者:heiyeluren * 建立:2009/12/13 04:43 * 修改:2009/12/16 10:30 實現基本HTTP各類接口操做支持 ************************************************************/ /** * HTTP功能工廠方法類 * 調用示例代碼: * try { * $http = Http::factory('http://www.baidu.com', Http::TYPE_SOCK ); * echo $http->get(); * $http = Http::factory('http://127.0.0.1/test/i.php', Http::TYPE_SOCK ); * echo $http->post('', array('user'=>'咱們', 'nick'=>'ASSADF@#!32812989+-239%ASDF'), '', array('aa'=>'bb', 'cc'=>'dd')); * } catch (Exception $e) { * echo $e->getMessage(); * } */ class Http{ /** * @var 使用 CURL */ const TYPE_CURL = 1; /** * @var 使用 Socket */ const TYPE_SOCK = 2; /** * @var 使用 Stream */ const TYPE_STREAM = 3; /** * 保證對象不被clone */ private function __clone(){ } /** * 構造函數 */ private function __construct(){ } /** * HTTP工廠操做方法 * @param string $url 須要訪問的URL * @param int $type 須要使用的HTTP類 * @return object */ public static function factory($url = '' , $type = self::TYPE_SOCK){ if ($type == '') { $type = self::TYPE_SOCK; } switch ($type) { case self::TYPE_CURL : if (!function_exists('curl_init')) { throw new Exception(__CLASS__ . " PHP CURL extension not install"); } $obj = Http_Curl::getInstance($url); break; case self::TYPE_SOCK : if (!function_exists('fsockopen')) { throw new Exception(__CLASS__ . " PHP function fsockopen() not support"); } $obj = Http_Sock::getInstance($url); break; case self::TYPE_STREAM : if (!function_exists('stream_context_create')) { throw new Exception(__CLASS__ . " PHP Stream extension not install"); } $obj = Http_Stream::getInstance($url); break; default: throw new Exception("http access type $type not support"); } return $obj; } /** * 生成一個供Cookie或HTTP GET Query的字符串 * @param array $data 須要生產的數據數組,必須是 Name => Value 結構 * @param string $sep 兩個變量值之間分割的字符,缺省是 & * @return string 返回生成好的Cookie查詢字符串 */ public static function makeQuery($data , $sep = '&'){ $encoded = ''; while (list($k , $v) = each($data)) { $encoded .= ($encoded ? "$sep" : ""); $encoded .= rawurlencode($k) . "=" . rawurlencode($v); } return $encoded; } } /** * 使用CURL 做爲核心操做的HTTP訪問類 * @desc CURL 以穩定、高效、移植性強做爲很重要的HTTP協議訪問客戶端,必須在PHP中安裝 CURL 擴展才能使用本功能 */ class Http_Curl{ /** * @var object 對象單例 */ static $_instance = NULL; /** * @var string 須要發送的cookie信息 */ private $cookies = ''; /** * @var array 須要發送的頭信息 */ private $header = array(); /** * @var string 須要訪問的URL地址 */ private $uri = ''; /** * @var array 須要發送的數據 */ private $vars = array(); /** * 構造函數 * @param string $configFile 配置文件路徑 */ private function __construct($url){ $this->uri = $url; } /** * 保證對象不被clone */ private function __clone(){ } /** * 獲取對象惟一實例 * @param string $configFile 配置文件路徑 * @return object 返回本對象實例 */ public static function getInstance($url = ''){ if (!(self::$_instance instanceof self)) { self::$_instance = new self($url); } return self::$_instance; } /** * 設置須要發送的HTTP頭信息 * @param array /string 須要設置的頭信息,能夠是一個 相似 array('Host: example.com', 'Accept-Language: zh-cn') 的頭信息數組 * 或單一的一條相似於 'Host: example.com' 頭信息字符串 * @return void */ public function setHeader($header){ if (emptyempty($header)) { return; } if (is_array($header)) { foreach ($header as $k => $v) { $this->header[] = is_numeric($k) ? trim($v) : (trim($k) . ": " . trim($v)); } } elseif (is_string($header)) { $this->header[] = $header; } } /** * 設置Cookie頭信息 * 注意:本函數只能調用一次,下次調用會覆蓋上一次的設置 * @param string /array 須要設置的Cookie信息,一個相似於 'name1=value1&name2=value2' 的Cookie字符串信息, * 或者是一個 array('name1'=>'value1', 'name2'=>'value2') 的一維數組 * @return void */ public function setCookie($cookie){ if (emptyempty($cookie)) { return; } if (is_array($cookie)) { $this->cookies = Http::makeQuery($cookie , ';'); } elseif (is_string($cookie)) { $this->cookies = $cookie; } } /** * 設置要發送的數據信息 * 注意:本函數只能調用一次,下次調用會覆蓋上一次的設置 * @param array 設置須要發送的數據信息,一個相似於 array('name1'=>'value1', 'name2'=>'value2') 的一維數組 * @return void */ public function setVar($vars){ if (emptyempty($vars)) { return; } if (is_array($vars)) { $this->vars = $vars; } } /** * 設置要請求的URL地址 * @param string $url 須要設置的URL地址 * @return void */ public function setUrl($url){ if ($url != '') { $this->uri = $url; } } /** * 發送HTTP GET請求 * @param string $url 若是初始化對象的時候沒有設置或者要設置不一樣的訪問URL,能夠傳本參數 * @param array $vars 須要單獨返送的GET變量 * @param array /string 須要設置的頭信息,能夠是一個 相似 array('Host: example.com', 'Accept-Language: zh-cn') 的頭信息數組 * 或單一的一條相似於 'Host: example.com' 頭信息字符串 * @param string /array 須要設置的Cookie信息,一個相似於 'name1=value1&name2=value2' 的Cookie字符串信息, * 或者是一個 array('name1'=>'value1', 'name2'=>'value2') 的一維數組 * @param int $timeout 鏈接對方服務器訪問超時時間,單位爲秒 * @param array $options 當前操做類一些特殊的屬性設置 * @return unknown */ public function get($url = '' , $vars = array() , $header = array() , $cookie = '' , $timeout = 5 , $options = array()){ $this->setUrl($url); $this->setHeader($header); $this->setCookie($cookie); $this->setVar($vars); return $this->send('GET' , $timeout); } /** * 發送HTTP POST請求 * @param string $url 若是初始化對象的時候沒有設置或者要設置不一樣的訪問URL,能夠傳本參數 * @param array $vars 須要單獨返送的GET變量 * @param array /string 須要設置的頭信息,能夠是一個 相似 array('Host: example.com', 'Accept-Language: zh-cn') 的頭信息數組 * 或單一的一條相似於 'Host: example.com' 頭信息字符串 * @param string /array 須要設置的Cookie信息,一個相似於 'name1=value1&name2=value2' 的Cookie字符串信息, * 或者是一個 array('name1'=>'value1', 'name2'=>'value2') 的一維數組 * @param int $timeout 鏈接對方服務器訪問超時時間,單位爲秒 * @param array $options 當前操做類一些特殊的屬性設置 * @return unknown */ public function post($url = '' , $vars = array() , $header = array() , $cookie = '' , $timeout = 5 , $options = array()){ $this->setUrl($url); $this->setHeader($header); $this->setCookie($cookie); $this->setVar($vars); return $this->send('POST' , $timeout); } /** * 發送HTTP請求核心函數 * @param string $method 使用GET仍是POST方式訪問 * @param array $vars 須要另外附加發送的GET/POST數據 * @param int $timeout 鏈接對方服務器訪問超時時間,單位爲秒 * @param array $options 當前操做類一些特殊的屬性設置 * @return string 返回服務器端讀取的返回數據 */ public function send($method = 'GET' , $timeout = 5 , $options = array()){ //處理參數是否爲空 if ($this->uri == '') { throw new Exception(__CLASS__ . ": Access url is empty"); } //初始化CURL $ch = curl_init(); curl_setopt($ch , CURLOPT_HEADER , 0); curl_setopt($ch , CURLOPT_FOLLOWLOCATION , 1); curl_setopt($ch , CURLOPT_RETURNTRANSFER , 1); curl_setopt($ch , CURLOPT_TIMEOUT , $timeout); //設置特殊屬性 if (!emptyempty($options)) { curl_setopt_array($ch , $options); } //處理GET請求參數 if ($method == 'GET' && !emptyempty($this->vars)) { $query = Http::makeQuery($this->vars); $parse = parse_url($this->uri); $sep = isset($parse['query']) ? '&' : '?'; $this->uri .= $sep . $query; } //處理POST請求數據 if ($method == 'POST') { curl_setopt($ch , CURLOPT_POST , 1); curl_setopt($ch , CURLOPT_POSTFIELDS , $this->vars); } //設置cookie信息 if (!emptyempty($this->cookies)) { curl_setopt($ch , CURLOPT_COOKIE , $this->cookies); } //設置HTTP缺省頭 if (emptyempty($this->header)) { $this->header = array('User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1)' , //'Accept-Language: zh-cn', //'Cache-Control: no-cache', ); } curl_setopt($ch , CURLOPT_HTTPHEADER , $this->header); //發送請求讀取輸數據 curl_setopt($ch , CURLOPT_URL , $this->uri); $data = curl_exec($ch); if (($err = curl_error($ch))) { curl_close($ch); throw new Exception(__CLASS__ . " error: " . $err); } curl_close($ch); return $data; } } /** * 使用 Socket操做(fsockopen) 做爲核心操做的HTTP訪問接口 * @desc Network/fsockopen 是PHP內置的一個Sokcet網絡訪問接口,必須安裝/打開 fsockopen 函數本類才能工做, * 同時確保其餘相關網絡環境和配置是正確的 */ class Http_Sock{ /** * @var object 對象單例 */ static $_instance = NULL; /** * @var string 須要發送的cookie信息 */ private $cookies = ''; /** * @var array 須要發送的頭信息 */ private $header = array(); /** * @var string 須要訪問的URL地址 */ private $uri = ''; /** * @var array 須要發送的數據 */ private $vars = array(); /** * 構造函數 * @param string $configFile 配置文件路徑 */ private function __construct($url){ $this->uri = $url; } /** * 保證對象不被clone */ private function __clone(){ } /** * 獲取對象惟一實例 * @param string $configFile 配置文件路徑 * @return object 返回本對象實例 */ public static function getInstance($url = ''){ if (!(self::$_instance instanceof self)) { self::$_instance = new self($url); } return self::$_instance; } /** * 設置須要發送的HTTP頭信息 * @param array /string 須要設置的頭信息,能夠是一個 相似 array('Host: example.com', 'Accept-Language: zh-cn') 的頭信息數組 * 或單一的一條相似於 'Host: example.com' 頭信息字符串 * @return void */ public function setHeader($header){ if (emptyempty($header)) { return; } if (is_array($header)) { foreach ($header as $k => $v) { $this->header[] = is_numeric($k) ? trim($v) : (trim($k) . ": " . trim($v)); } } elseif (is_string($header)) { $this->header[] = $header; } } /** * 設置Cookie頭信息 * 注意:本函數只能調用一次,下次調用會覆蓋上一次的設置 * @param string /array 須要設置的Cookie信息,一個相似於 'name1=value1&name2=value2' 的Cookie字符串信息, * 或者是一個 array('name1'=>'value1', 'name2'=>'value2') 的一維數組 * @return void */ public function setCookie($cookie){ if (emptyempty($cookie)) { return; } if (is_array($cookie)) { $this->cookies = Http::makeQuery($cookie , ';'); } elseif (is_string($cookie)) { $this->cookies = $cookie; } } /** * 設置要發送的數據信息 * 注意:本函數只能調用一次,下次調用會覆蓋上一次的設置 * @param array 設置須要發送的數據信息,一個相似於 array('name1'=>'value1', 'name2'=>'value2') 的一維數組 * @return void */ public function setVar($vars){ if (emptyempty($vars)) { return; } if (is_array($vars)) { $this->vars = $vars; } } /** * 設置要請求的URL地址 * @param string $url 須要設置的URL地址 * @return void */ public function setUrl($url){ if ($url != '') { $this->uri = $url; } } /** * 發送HTTP GET請求 * @param string $url 若是初始化對象的時候沒有設置或者要設置不一樣的訪問URL,能夠傳本參數 * @param array $vars 須要單獨返送的GET變量 * @param array /string 須要設置的頭信息,能夠是一個 相似 array('Host: example.com', 'Accept-Language: zh-cn') 的頭信息數組 * 或單一的一條相似於 'Host: example.com' 頭信息字符串 * @param string /array 須要設置的Cookie信息,一個相似於 'name1=value1&name2=value2' 的Cookie字符串信息, * 或者是一個 array('name1'=>'value1', 'name2'=>'value2') 的一維數組 * @param int $timeout 鏈接對方服務器訪問超時時間,單位爲秒 * @param array $options 當前操做類一些特殊的屬性設置 * @return unknown */ public function get($url = '' , $vars = array() , $header = array() , $cookie = '' , $timeout = 5 , $options = array()){ $this->setUrl($url); $this->setHeader($header); $this->setCookie($cookie); $this->setVar($vars); return $this->send('GET' , $timeout); } /** * 發送HTTP POST請求 * @param string $url 若是初始化對象的時候沒有設置或者要設置不一樣的訪問URL,能夠傳本參數 * @param array $vars 須要單獨返送的GET變量 * @param array /string 須要設置的頭信息,能夠是一個 相似 array('Host: example.com', 'Accept-Language: zh-cn') 的頭信息數組 * 或單一的一條相似於 'Host: example.com' 頭信息字符串 * @param string /array 須要設置的Cookie信息,一個相似於 'name1=value1&name2=value2' 的Cookie字符串信息, * 或者是一個 array('name1'=>'value1', 'name2'=>'value2') 的一維數組 * @param int $timeout 鏈接對方服務器訪問超時時間,單位爲秒 * @param array $options 當前操做類一些特殊的屬性設置 * @return unknown */ public function post($url = '' , $vars = array() , $header = array() , $cookie = '' , $timeout = 5 , $options = array()){ $this->setUrl($url); $this->setHeader($header); $this->setCookie($cookie); $this->setVar($vars); return $this->send('POST' , $timeout); } /** * 發送HTTP請求核心函數 * @param string $method 使用GET仍是POST方式訪問 * @param array $vars 須要另外附加發送的GET/POST數據 * @param int $timeout 鏈接對方服務器訪問超時時間,單位爲秒 * @param array $options 當前操做類一些特殊的屬性設置 * @return string 返回服務器端讀取的返回數據 */ public function send($method = 'GET' , $timeout = 5 , $options = array()){ //處理參數是否爲空 if ($this->uri == '') { throw new Exception(__CLASS__ . ": Access url is empty"); } //處理GET請求參數 if ($method == 'GET' && !emptyempty($this->vars)) { $query = Http::makeQuery($this->vars); $parse = parse_url($this->uri); $sep = isset($parse['query']) && ($parse['query'] != '') ? '&' : '?'; $this->uri .= $sep . $query; } //處理POST請求數據 $data = ''; if ($method == 'POST' && !emptyempty($this->vars)) { $data = Http::makeQuery($this->vars); $this->setHeader('Content-Type: application/x-www-form-urlencoded'); $this->setHeader('Content-Length: ' . strlen($data)); } //解析URL地址 $url = parse_url($this->uri); $host = $url['host']; $port = isset($url['port']) && ($url['port'] != '') ? $url['port'] : 80; $path = isset($url['path']) && ($url['path'] != '') ? $url['path'] : '/'; $path .= isset($url['query']) ? "?" . $url['query'] : ''; //組織HTTP請求頭信息 array_unshift(&$this->header , $method . " " . $path . " HTTP/1.1"); $this->setHeader('User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1)'); if (!preg_match("/^[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}$/" , $host)) { $this->setHeader("Host: " . $host); } if ($this->cookies != '') { $this->setHeader("Cookie: " . $this->cookies); } $this->setHeader("Connection: Close"); //'Accept-Language: zh-cn', //'Cache-Control: no-cache', //構造請求信息 $header = ''; foreach ($this->header as $h) { $header .= $h . "\r\n"; } $header .= "\r\n"; if ($method == 'POST' && $data != '') { $header .= $data . "\r\n"; } //鏈接服務器發送請求數據 $ip = gethostbyname($host); if (!($fp = fsockopen($ip , $port , &$errno , &$errstr , $timeout))) { throw new Exception(__CLASS__ . ": Can't connect $host:$port, errno:$errno,message:$errstr"); } fputs($fp , $header); $lineSize = 1024; //處理301,302跳轉頁面訪問 $line = fgets($fp , $lineSize); $first = preg_split("/\s/" , trim($line)); if (isset($first[1]) && in_array($first[1] , array('301' , '302'))) { while (!feof($fp)) { $line = fgets($fp , $lineSize); $second = preg_split("/\s/" , trim($line)); if (ucfirst(trim($second[0])) == 'Location:' && $second[1] != '') { $this->header = array(); return $this->get(trim($second[1])); } } } //正常讀取返回數據 $buf = ''; $inheader = 1; while (!feof($fp)) { if ($inheader && ($line == "\n" || $line == "\r\n")) { $inheader = 0; } $line = fgets($fp , $lineSize); if ($inheader == 0) { $buf .= $line; } } fclose($fp); return $buf; } } /** * 使用文件流操做函數爲核心操做的HTTP訪問接口 * @desc stream_* 和 fopen/file_get_contents 是PHP內置的一個流和文件操做接口,必須打開 fsockopen 函數本類才能工做, * 同時確保其餘相關網絡環境和配置是正確的,包括 allow_url_fopen 等設置 */ class Http_Stream{ /** * @var object 對象單例 */ static $_instance = NULL; /** * @var string 須要發送的cookie信息 */ private $cookies = ''; /** * @var array 須要發送的頭信息 */ private $header = array(); /** * @var string 須要訪問的URL地址 */ private $uri = ''; /** * @var array 須要發送的數據 */ private $vars = array(); /** * 構造函數 * @param string $configFile 配置文件路徑 */ private function __construct($url){ $this->uri = $url; } /** * 保證對象不被clone */ private function __clone(){ } /** * 獲取對象惟一實例 * @param string $configFile 配置文件路徑 * @return object 返回本對象實例 */ public static function getInstance($url = ''){ if (!(self::$_instance instanceof self)) { self::$_instance = new self($url); } return self::$_instance; } /** * 設置須要發送的HTTP頭信息 * @param array /string 須要設置的頭信息,能夠是一個 相似 array('Host: example.com', 'Accept-Language: zh-cn') 的頭信息數組 * 或單一的一條相似於 'Host: example.com' 頭信息字符串 * @return void */ public function setHeader($header){ if (emptyempty($header)) { return; } if (is_array($header)) { foreach ($header as $k => $v) { $this->header[] = is_numeric($k) ? trim($v) : (trim($k) . ": " . trim($v)); } } elseif (is_string($header)) { $this->header[] = $header; } } /** * 設置Cookie頭信息 * 注意:本函數只能調用一次,下次調用會覆蓋上一次的設置 * @param string /array 須要設置的Cookie信息,一個相似於 'name1=value1&name2=value2' 的Cookie字符串信息, * 或者是一個 array('name1'=>'value1', 'name2'=>'value2') 的一維數組 * @return void */ public function setCookie($cookie){ if (emptyempty($cookie)) { return; } if (is_array($cookie)) { $this->cookies = Http::makeQuery($cookie , ';'); } elseif (is_string($cookie)) { $this->cookies = $cookie; } } /** * 設置要發送的數據信息 * 注意:本函數只能調用一次,下次調用會覆蓋上一次的設置 * @param array 設置須要發送的數據信息,一個相似於 array('name1'=>'value1', 'name2'=>'value2') 的一維數組 * @return void */ public function setVar($vars){ if (emptyempty($vars)) { return; } if (is_array($vars)) { $this->vars = $vars; } } /** * 設置要請求的URL地址 * @param string $url 須要設置的URL地址 * @return void */ public function setUrl($url){ if ($url != '') { $this->uri = $url; } } /** * 發送HTTP GET請求 * @param string $url 若是初始化對象的時候沒有設置或者要設置不一樣的訪問URL,能夠傳本參數 * @param array $vars 須要單獨返送的GET變量 * @param array /string 須要設置的頭信息,能夠是一個 相似 array('Host: example.com', 'Accept-Language: zh-cn') 的頭信息數組 * 或單一的一條相似於 'Host: example.com' 頭信息字符串 * @param string /array 須要設置的Cookie信息,一個相似於 'name1=value1&name2=value2' 的Cookie字符串信息, * 或者是一個 array('name1'=>'value1', 'name2'=>'value2') 的一維數組 * @param int $timeout 鏈接對方服務器訪問超時時間,單位爲秒 * @param array $options 當前操做類一些特殊的屬性設置 * @return unknown */ public function get($url = '' , $vars = array() , $header = array() , $cookie = '' , $timeout = 5 , $options = array()){ $this->setUrl($url); $this->setHeader($header); $this->setCookie($cookie); $this->setVar($vars); return $this->send('GET' , $timeout); } /** * 發送HTTP POST請求 * @param string $url 若是初始化對象的時候沒有設置或者要設置不一樣的訪問URL,能夠傳本參數 * @param array $vars 須要單獨返送的GET變量 * @param array /string 須要設置的頭信息,能夠是一個 相似 array('Host: example.com', 'Accept-Language: zh-cn') 的頭信息數組 * 或單一的一條相似於 'Host: example.com' 頭信息字符串 * @param string /array 須要設置的Cookie信息,一個相似於 'name1=value1&name2=value2' 的Cookie字符串信息, * 或者是一個 array('name1'=>'value1', 'name2'=>'value2') 的一維數組 * @param int $timeout 鏈接對方服務器訪問超時時間,單位爲秒 * @param array $options 當前操做類一些特殊的屬性設置 * @return unknown */ public function post($url = '' , $vars = array() , $header = array() , $cookie = '' , $timeout = 5 , $options = array()){ $this->setUrl($url); $this->setHeader($header); $this->setCookie($cookie); $this->setVar($vars); return $this->send('POST' , $timeout); } /** * 發送HTTP請求核心函數 * @param string $method 使用GET仍是POST方式訪問 * @param array $vars 須要另外附加發送的GET/POST數據 * @param int $timeout 鏈接對方服務器訪問超時時間,單位爲秒 * @param array $options 當前操做類一些特殊的屬性設置 * @return string 返回服務器端讀取的返回數據 */ public function send($method = 'GET' , $timeout = 5 , $options = array()){ //處理參數是否爲空 if ($this->uri == '') { throw new Exception(__CLASS__ . ": Access url is empty"); } $parse = parse_url($this->uri); $host = $parse['host']; //處理GET請求參數 if ($method == 'GET' && !emptyempty($this->vars)) { $query = Http::makeQuery($this->vars); $sep = isset($parse['query']) && ($parse['query'] != '') ? '&' : '?'; $this->uri .= $sep . $query; } //處理POST請求數據 $data = ''; if ($method == 'POST' && !emptyempty($this->vars)) { $data = Http::makeQuery($this->vars); } //設置缺省頭 $this->setHeader('User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1)'); if (!preg_match("/^[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}$/" , $host)) { $this->setHeader("Host: " . $host); } if ($this->cookies != '') { $this->setHeader("Cookie: " . $this->cookies); } $this->setHeader("Connection: Close"); //'Accept-Language: zh-cn', //'Cache-Control: no-cache', //構造頭信息 $opts = array('http' => array('method' => $method , 'timeout' => $timeout ,)); if ($data != '') { $opts['http']['content'] = $data; } $opts['http']['header'] = ''; foreach ($this->header as $h) { $opts['http']['header'] .= $h . "\r\n"; } //print_r($opts);exit; //讀取擴展設置選項 if (!emptyempty($options)) { isset($options['proxy']) ? $opts['http']['proxy'] = $options['proxy'] : ''; isset($options['max_redirects']) ? $opts['http']['max_redirects'] = $options['max_redirects'] : ''; isset($options['request_fulluri']) ? $opts['http']['request_fulluri'] = $options['request_fulluri'] : ''; } //發送數據返回 $context = stream_context_create($opts); if (($buf = file_get_contents($this->uri , null , $context)) === false) { throw new Exception(__CLASS__ . ": file_get_contents(" . $this->uri . ") fail"); } return $buf; } }