| Uutiset | Koodikirjasto | Wiki | Keskustelut | FAQ | Info |
http1.1 mk IIIamp_god 30.07.07 02:28 HTTP 1.1 asiakas, ylläpitää muodostetut yhteydet serveriin. :)
[code] class http11 { ## Initial variables ## private $Connections = array(); private $ConnTimeOut = 10; private $ErrorLog = array(); private $DebugMSG = FALSE; ## Socket timeout set/get ## function TimeOut($seconds = FALSE) { if(!$seconds) { return $this->ConnTimeOut; } if(is_numeric($seconds)) { $this->ConnTimeOut = $seconds; return TRUE; } else { return FALSE; } } ## Debug set/get ## function Debug($value = NULL) { if($value == NULL) { return $this->DebugMSG; } if($value == TRUE) { $this->DebugMSG = TRUE; return TRUE; } if($value == FALSE) { $this->DebugMSG = FALSE; return TRUE; } } ## Connection handling ## private function Connect($server, $port) { if(!empty($this->Connections["$server:$port"])) { return($this->Connections["$server:$port"]); } $this->Connections["$server:$port"] = @fsockopen($server, $port, $errno, $errstr, $this->ConnTimeOut); if(!$this->Connections["$server:$port"]) { $this->ErrorLog[] = time() . " : Connection failed to $server:$port. $errno/$errstr"; return FALSE; } return $this->Connections["$server:$port"]; } ## HEAD Fetching ## private function GetHead($connection) { $buf = ""; $continue = TRUE; while($continue) { if(!$connection) { $continue = FALSE; return FALSE; } ## Connection failed? if(feof($connection)) { $continue = FALSE; return FALSE; } ## Unexpected EOF? if(substr($buf, -4) == "\r\n\r\n") { $continue = FALSE; break; } ## Expected \r\n\r\n $buf .= fread($connection, 1); } $buf = "Status: " . trim($buf); $buf = explode("\r\n", $buf); $result = array(); foreach($buf as $row) { $row = explode(": ", $row); $result["$row[0]"] = $row[1]; } return $result; } ## Chunked decryption ## private function ReadChunked($connection) { $buf = ""; $mainbuf = ""; $chunklen = 1; if($this->DebugMSG) { print("Chunks:\n"); } while($chunklen > 0) { ############################## ## Finding the chunk lenght ## $temp = ""; $buf = ""; while(substr($buf, -2) != "\r\n" || strlen($temp) == 0) { $char = fread($connection, 1); $buf .= $char; if($char != "\r" && $char != "\n") { $temp .= $char; } } $chunklen = hexdec($temp); if($this->DebugMSG) { print(" Chunklen=$chunklen, Reads="); } ##/Finding the chink lenght ## ############################## $buf2 = ""; if($this->DebugMSG) print("["); while(strlen($buf2) < $chunklen) { $buf2 .= fread($connection, $chunklen - strlen($buf2)); if($this->DebugMSG) print("."); } if($this->DebugMSG) print("]\n"); $mainbuf .= $buf2; } if($this->DebugMSG) { print("Chunks done\n"); } ##/Reading the CHUNKED encoding ## ################################## return $mainbuf; } ## DATA Fetching ## private function GetData($connection, $head) { if($this->DebugMSG) print("----Data download----\n"); $mainbuf = ""; $chunked = strpos($head["Transfer-Encoding"], "chunked"); if($chunked === false) { ##################### ## Normal Download ## $continue = TRUE; if($this->DebugMSG) print(" Downloading normally...\n"); while($continue) { if(!$connection) { $continue = FALSE; return FALSE; break; } ## Connection failed? if(feof($connection)) { $continue = FALSE; break; } ## EOF? if(!empty($head['Content-Length'])) { if(strlen($mainbuf) == $head['Content-Length']) { $continue = FALSE; break; } ## Lenght archieved } $new = fread($connection, 2048); $mainbuf .= $new; if($this->DebugMSG) print(" " . number_format(strlen($new)) . " bytes downloaded (" . number_format(strlen($mainbuf)) . " bytes total)\n"); } if($this->DebugMSG) print(" Complete\n"); ##/Normal Download ## ##################### } else { ###################### ## Chunked transfer ## $mainbuf = $this->ReadChunked($connection); ##/Chunked transfer ## ###################### } ########################## ## GZipped transmission ## if($head['Content-Encoding'] == "gzip") { if($this->DebugMSG) { print(" GZipped transmission, decoding..."); } $mainbuf = gzinflate(substr($mainbuf, 10)); if($this->DebugMSG) { if($mainbuf === false) { print(" Failed.\n"); } else { print(" Success.\n"); } } } ##/GZipped transmission ## ########################## if($this->DebugMSG) print("\n"); return $mainbuf; } ## Generate http/1.1 request ## private function urlDefaults($url) { ################## ## URL Handling ## $url = parse_url($url); if(empty($url['port'])) { $url['port'] = 80; } if(empty($url['query'])) { $url['query'] = ""; } if(!empty($url['query'])) { $url['query'] = "?" . $url['query']; } if(empty($url['path'])) { $url['path'] = "/"; } ##/URL Handling ## ################## return $url; } private function genRequest($url, $method = "GET") { ##################### ## Generating HEAD ## $url = $this->urlDefaults($url); $head = array("$method ${url['path']}${url['query']} HTTP/1.1", "Host: ${url['host']}", "Accept: */*", "Accept-Encoding: gzip"); if($this->DebugMSG) { print("----REQUEST----\n"); print_r($head); print("\n"); } ##/Generating HEAD ## ##################### return $head; } ########################### ## GET http/1.1 function ## function GET($url) { $head = $this->genRequest($url); $url = $this->urlDefaults($url); #################################### ## Connecting and writing the req ## $sock = $this->Connect($url['host'], $url['port']); if(!$sock) { return FALSE; } foreach($head as $row) { fwrite($sock, "$row\r\n"); } fwrite($sock, "\r\n"); ##/Connecting and writing the req ## #################################### ############################## ## Getting the responseHead ## $responseHead = $this->GetHead($sock); if(!$responseHead) { return FALSE; } if($this->DebugMSG) { print("----RESPONSE----\n"); print_r($responseHead); print("\n"); } ##/Getting the responseHead ## ############################## ########################## ## Downloading the data ## $data = $this->GetData($sock, $responseHead); return $data; ##/Downloading the data ## ########################## } ##/GET http/1.1 function ## ########################### ############### ## HTTP HEAD ## function HEAD($url) { $head = $this->genRequest($url, "HEAD"); $url = $this->urlDefaults($url); #################################### ## Connecting and writing the req ## $sock = $this->Connect($url['host'], $url['port']); if(!$sock) { return FALSE; } foreach($head as $row) { fwrite($sock, "$row\r\n"); } fwrite($sock, "\r\n"); ##/Connecting and writing the req ## #################################### ############################## ## Getting the responseHead ## $responseHead = $this->GetHead($sock); if(!$responseHead) { return FALSE; } return $responseHead; } ##/HTTP HEAD ## ############### } [/code] ## Todo ## - yhteyden katkaiseminen "fiksusti" - Chunked koodauksen purku voisi olla siistinpikin - POST metodi - Proxy - referrerit sun muut. ## Käyttäminen ## $httpClient = new http11; $httpClient->Debug(TRUE); $headinfo = $httpClient->HEAD("http://localhost/"); $data = $httpClient->GET("http://localhost"); print("---- Header ----\n"); print_r($headinfo); print("\n"); print("----Final data----\n$data"); Tommonen. Tuli kirjoitettua http11 asiakas ihan puhtaalta pöydältä lukuunottamatta chunked koodauksen purkua. Tarkoitettu lähinnä usean tiedoston lataamiseen samalta serveriltä ilman että katkaistaan yhteyttä jokavälissä. Ehdotuksia? amp_god 02:30 30.7.07 Tulostaa esim seuraavaa: (debug päällä) $ php http11_v3.php X-Powered-By: PHP/5.2.1 Content-type: text/html ----REQUEST---- Array ( [0] => GET / HTTP/1.1 [1] => Host: localhost [2] => Accept: */* [3] => Accept-Encoding: gzip, * ) ----RESPONSE---- Array ( [Status] => HTTP/1.1 200 OK [Transfer-Encoding] => chunked [X-Powered-By] => PHP/5.2.1 [Set-Cookie] => PHPSESSID=b80006e458012abe322b20b9252de092; path=/ [Expires] => Thu, 19 Nov 1981 08:52:00 GMT [Cache-Control] => no-store, no-cache, must-revalidate, post-check=0, pre-check=0 [Pragma] => no-cache [Content-type] => text/html [Date] => Sun, 29 Jul 2007 23:30:14 GMT [Server] => lighttpd/1.4.13 ) ----Data download---- Chunks: Chunklen=1087, Reads=[.] Chunklen=159, Reads=[.] Chunklen=0, Reads=[] Chunks done ----Final data---- [[HTML Koodia]] amp_god 19:13 30.7.07 Chunked koodauksen luku siirretty omaan funktioonsa, gzipin purku lisätty. Entropia 17:23 1.8.07 Montako HTTP-clienttiä täällä kuhassa oikein pitää olla? editoitu: 22:57 1.8.07 amp_god 22:18 1.8.07 Muut (minun tekemät) http asiakasohjelmat poistettu. Näkeepähän ainakin että kehitystä tapahtuu ;) ------------- Scriptiä päivitetty. - Debug muuttujan määrääminen / palauttaminen Debug funktiolla. - Yhdistämisen aikakatkaisun määrääminen / lukeminen TimeOut funktiolla. - Muuttujat määrätty yksityisiksi - Funktiot määrätty yksityisiksi - HEAD kysely - Lisää sisäisiä funktioita tsuriga 12:58 3.8.07 Ittehän kirjottaisin luokan isolla ja funkkarit pienellä alkukirjaimella, kuten PEARin ohjeissa ehdotellaan. Kivat kommentit ja pätkäkin varmaan toimii kuin junan vessa. netteri 18:16 9.8.07 Hmm, voisin vaikkapas poistaa oman ja nakata plussaa... editoitu: 01:01 6.11.07 tsuriga 17:58 5.11.07 Tuohon requestiin olis kiva lisätä omia headereitä ja tässä vois tietysti käyttää vaikkapa Zendin koodausohjeita niin sais selkeämmäks. |
![]() Haku
|