| Uutiset | Koodikirjasto | Wiki | Keskustelut | FAQ | Info |
HTTP1.1 Clientamp_god 22.07.08 20:50 HTTP 1.1 Asiakas joka (tulee) osaamaan HTTP GET/HEAD/POST -funktiot ja tietenkin HTTP1.1:en vaatima Chunked -koodauksen
<?php class http11 { private $socket = FALSE; private $proxyHost = FALSE; private $proxyPort = FALSE; private $errorString = FALSE; private $warningString = FALSE; private $currentSocket = FALSE; private $cookies = FALSE; function readUntil($mark) { if(!$this->currentSocket) { return FALSE; } $buf = ''; $markLen = strlen($mark) * -1; while(substr($buf, $markLen) != $mark) { if(feof($this->currentSocket)) break; $buf .= fread($this->currentSocket, 1); } return $buf; } function readLenght($lenght) { $buf = ""; while(strlen($buf) < $lenght) { if(feof($this->currentSocket)) break; $buf .= fread($this->currentSocket, $lenght - strlen($buf)); print("."); } return $buf; } function setProxy($proxyHost) { $proxyHost = parse_url($proxyHost); if(empty($proxyHost['host'])) { return FALSE; } if(empty($proxyHost['port'])) { return FALSE; } $this->proxyHost = $proxyHost['host']; $this->proxyPort = $proxyHost['port']; return TRUE; } function connect($url) { $url = parse_url($url); if(empty($url['port'])) { $url['port'] = 80; } $errNo = FALSE; $errStr = FALSE; if(!empty($this->proxyHost)) { $connect = @fsockopen($this->proxyHost, $this->proxyPort, $errNo, $errStr); if(!$connect) { $this->errorString[] = "Connection failure, $errStr ($errNo)"; return FALSE; } $this->socket[$url['host']] = $connect; $this->currentSocket = $connect; return TRUE; } $connect = @fsockopen($url['host'], $url['port'], $errNo, $errStr); if(!$connect) { $this->errorString[] = "Connection failure, $errStr ($errNo)"; return FALSE; } $this->socket[$url['host']] = $connect; $this->currentSocket = $connect; return TRUE; } function genRequest($method, $url, $postArray = FALSE) { $parsedUrl = parse_url($url); $request = array(); if(empty($parsedUrl['path'])) { $parsedUrl['path'] = "/"; } if(empty($parsedUrl['query'])) { $path = $parsedUrl['path']; } else { $path = $parsedUrl['path'] . "?" . $parsedUrl['query']; } if(!empty($this->cookies[$parsedUrl['host']])) { $cookies = ""; foreach($this->cookies[$parsedUrl['host']] as $cookie) { $cookies .= "Cookie: $cookie\r\n"; } } else { $cookies = FALSE; } if(!$this->proxyHost) { switch($method) { case 'GET': $request[] = "GET $path HTTP/1.1\r\n"; $request[] = "Host: " . $parsedUrl['host'] . "\r\n"; $request[] = "Accept-Encoding: compress, gzip\r\n"; if($cookies) { $request[] = "$cookies"; } $request[] = "Connection: close\r\n"; $request[] = "\r\n"; break; case 'HEAD': $request[] = "HEAD $path HTTP/1.1\r\n"; $request[] = "Host: " . $parsedUrl['host'] . "\r\n"; if($cookies) { $request[] = "$cookies"; } $request[] = "Connection: close\r\n"; $request[] = "\r\n"; break; case 'POST': $postString = ""; $last = ""; foreach($postArray AS $name => $content) { $postString .= "$name=$content&"; $last = $name; } $request[] = "POST $path HTTP/1.1\r\n"; $request[] = "Host: " . $parsedUrl['host'] . "\r\n"; $request[] = "Accept-Encoding: gzip\r\n"; $request[] = "Content-Lenght: " . strlen($postString) . "\r\n"; if($cookies) { $request[] = "$cookies"; } $request[] = "Connection: close\r\n"; $request[] = "\r\n"; $request[] = $postString; break; } } if($this->proxyHost) { switch($method) { case 'GET': $request[] = "GET $url HTTP/1.1\r\n"; $request[] = "Host: " . $parsedUrl['host'] . "\r\n"; $request[] = "Accept-Encoding: gzip\r\n"; if($cookies) { $request[] = "$cookies"; } $request[] = "Connection: close\r\n"; $request[] = "\r\n"; break; case 'HEAD': $request[] = "HEAD $url HTTP/1.1\r\n"; $request[] = "Host: " . $parsedUrl['host'] . "\r\n"; if($cookies) { $request[] = "$cookies"; } $request[] = "Connection: close\r\n"; $request[] = "\r\n"; break; case 'POST': $postString = ""; foreach($postArray AS $name => $content) { $postString .= "$name=$content&"; } $postString = substr($postString, 0, -1); $request[] = "POST $url HTTP/1.1\r\n"; $request[] = "Host: " . $parsedUrl['host'] . "\r\n"; $request[] = "Accept-Encoding: gzip\r\n"; $request[] = "Content-Lenght: " . strlen($postString) . "\r\n"; if($cookies) { $request[] = "$cookies"; } $request[] = "Connection: close\r\n"; $request[] = "\r\n"; $request[] = $postString; break; } } return $request; } function readChunked() { $mainBuf = ""; $chunkLen = 1; while($chunkLen > 0) { $temp = substr($this->readUntil("\r\n"), 0, -2); if($temp == '') { $temp = substr($this->readUntil("\r\n"), 0, -2); } $chunkLen = hexdec($temp); print("\nChunklen=$chunkLen"); if($chunkLen > 0) { $mainBuf .= $this->readLenght($chunkLen); } } return $mainBuf; } function sendRequest($request) { if(!is_array($request)) { $this->errorString[] = "Generated request is not an array"; return FALSE; } foreach($request as $req) { fwrite($this->currentSocket, $req); } return TRUE; } function readHeader() { $buf = $this->readUntil("\r\n\r\n"); if(strlen($buf) == 0) { $this->errorString[] = "No header."; return FALSE; } $result = array(); $count = 0; $buf = explode("\r\n", $buf); foreach($buf AS $line) { if($count == 0) { $result['Status'] = $line; } else { $lineSplit = explode(": ", $line); if(!empty($result[$lineSplit[0]])) { if(is_array($result[$lineSplit[0]])) { $result[$lineSplit[0]][] = $lineSplit[1]; } else { $result[$lineSplit[0]] = array($result[$lineSplit[0]], $lineSplit[1]); } } else { $result[$lineSplit[0]] = $lineSplit[1]; } } $count++; } return $result; } function readResponse($header) { if($header['Transfer-Encoding'] == 'chunked') { $buf = $this->readChunked(); } else { $buf = ''; while(!feof($this->currentSocket)) { $buf .= fread($this->currentSocket, 1024); } } if(!empty($header['Content-Length'])) { if(strlen($buf) != $header['Content-Length']) { $this->warningString[] = "Received data lenght doesnt match header...\n"; } } if($header['Content-Encoding'] == 'gzip') { $buf = gzinflate(substr($buf, 10)); } return $buf; } function saveCookies($header, $url) { if(empty($header) || empty($url)) { return FALSE; } if(!is_array($header['Set-Cookie'])) { return FALSE; } $url = parse_url($url); $cookies = array(); foreach($header['Set-Cookie'] as $cookie) { $cookie = explode('; ', $cookie); $cookies[] = $cookie[0]; } $this->cookies[$url['host']] = $cookies; return TRUE; } function GET($url) { $url_parsed = parse_url($url); $request = $this->genRequest('GET', $url); print("Generated request:\n"); print_r($request); print("Connecting..."); if(!$this->connect($url)) { return FALSE; } print("\nSending the request..."); $reqSend = $this->sendRequest($request); print("\nReading the response header..."); $header = $this->readHeader(); if(!$header) { $this->errorString[] = "Header retrieval failure."; return FALSE; } print("\nHeader received:\n"); print_r($header); $this->saveCookies($header, $url); print("Reading the rest..."); if(!empty($header['Location'])) { return $this->GET("http://" . $url_parsed['host'] . $url_parsed['path'] . $header['Location']); } $theData = $this->readResponse($header); if(!$theData) { $this->errorString[] = "Error retrieving the data..."; return FALSE; } print("\n\nThe data:\n$theData<EOF>"); } function Errors() { return $this->errorString; } function Warnings() { return $this->warningString; } function Cookies() { return $this->cookies; } } ## ToDo ## - HEAD - POST ## Done ## - Keksien tallennus - gzip - Proxy - GET - Chunked purku # Esimerkki # $client = new http11(); print($client->GET("http://www.google.fi/")); # Esimerkki 2 # $client = new http11(); $client->setProxy("http://localhost:3128/"); print($client->GET("http://www.google.fi/")); Akiro 20:53 22.7.08 Miten tämä eroaa tuosta edellisestäsi: http://mureakuha.com/koodikirjasto/1022 Ja miksi se keskeneräisenä pitää esitellä? amp_god 20:58 22.7.08 Akiro kirjoitti: Miten tämä eroaa tuosta edellisestäsi: http://mureakuha.com/koodikirjasto/1022 Ja miksi se keskeneräisenä pitää esitellä? Suurin muutos on tuo POST -funkkari. Toinen etu on 100% alusta lähtien kirjoitettu. :) Keskeneräisenä "julkaisemisen" syy: Kirjoittelen tätä työn ohessa ja joudun käyttämään muutamaa eri konetta + kotikoneella vielä erikseen. Akiro 21:13 22.7.08 Ok, aiheutti vain ihmettelyä tuolla ircin puolella. Pätevän oloinen koodipätkähän tämä muuten on. PS. On niitä muitakin tapoja säilöä tekstiä/koodia netissä ;-) |
![]() Haku
|