Your Ad Here

Posted By

hanguofeng on 10/06/08


Tagged

http


Versions (?)

HTTPClient


 / Published in: PHP
 

  1. <?php
  2. class HttpClient
  3. {
  4. // Request vars
  5. var $host;
  6. var $port;
  7. var $path;
  8. var $method;
  9. var $postdata = '';
  10. var $cookies = array();
  11. var $referer;
  12. var $accept = 'text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,image/jpeg,image/gif,*/*';
  13. var $accept_encoding = 'gzip';
  14. var $accept_language = 'en-us';
  15. var $user_agent = '';
  16. // Options
  17. var $timeout = 20;
  18. var $use_gzip = true;
  19. var $persist_cookies = true; // If true, received cookies are placed in the $this->cookies array ready for the next request
  20. // Note: This currently ignores the cookie path (and time) completely. Time is not important,
  21. // but path could possibly lead to security problems.
  22. var $persist_referers = true; // For each request, sends path of last request as referer
  23. var $debug = false;
  24. var $handle_redirects = true; // Auaomtically redirect if Location or URI header is found
  25. var $max_redirects = 5;
  26. var $headers_only = false; // If true, stops receiving once headers have been read.
  27. // Basic authorization variables
  28. var $username;
  29. var $password;
  30. // Response vars
  31. var $status;
  32. var $headers = array();
  33. var $content = '';
  34. var $errormsg;
  35. // Tracker variables
  36. var $redirect_count = 0;
  37. var $cookie_host = '';
  38. function HttpClient($host, $port = 80)
  39. {
  40. $this->host = $host;
  41. $this->port = $port;
  42. }
  43. function get($path, $data = false)
  44. {
  45. $this->path = $path;
  46. $this->method = 'GET';
  47. if ($data)
  48. {
  49. $this->path .= '?' . $this->buildQueryString($data);
  50. }
  51. return $this->doRequest();
  52. }
  53. function post($path, $data)
  54. {
  55. $this->path = $path;
  56. $this->method = 'POST';
  57. $this->postdata = $this->buildQueryString($data);
  58. return $this->doRequest();
  59. }
  60. function buildQueryString($data)
  61. {
  62. $querystring = '';
  63. if (is_array($data))
  64. {
  65. // Change data in to postable data
  66. foreach ($data as $key => $val)
  67. {
  68. if (is_array($val))
  69. {
  70. foreach ($val as $val2)
  71. {
  72. $querystring .= urlencode($key) . '=' . urlencode($val2) . '&';
  73. }
  74. } else
  75. {
  76. $querystring .= urlencode($key) . '=' . urlencode($val) . '&';
  77. }
  78. }
  79. $querystring = substr($querystring, 0, -1); // Eliminate unnecessary &
  80. } else
  81. {
  82. $querystring = $data;
  83. }
  84. return $querystring;
  85. }
  86. function doRequest()
  87. {
  88. // Performs the actual HTTP request, returning true or false depending on outcome
  89. if (!$fp = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout))
  90. {
  91. // Set error message
  92. switch ($errno)
  93. {
  94. case - 3:
  95. $this->errormsg = 'Socket creation failed (-3)';
  96. case - 4:
  97. $this->errormsg = 'DNS lookup failure (-4)';
  98. case - 5:
  99. $this->errormsg = 'Connection refused or timed out (-5)';
  100. default:
  101. $this->errormsg = 'Connection failed (' . $errno . ')';
  102. $this->errormsg .= ' ' . $errstr;
  103. $this->debug($this->errormsg);
  104. }
  105. return false;
  106. }
  107. socket_set_timeout($fp, $this->timeout);
  108. $request = $this->buildRequest();
  109. $this->debug('Request', $request);
  110. fwrite($fp, $request);
  111. // Reset all the variables that should not persist between requests
  112. $this->headers = array();
  113. $this->content = '';
  114. $this->errormsg = '';
  115. // Set a couple of flags
  116. $inHeaders = true;
  117. $atStart = true;
  118. // Now start reading back the response
  119. while (!feof($fp))
  120. {
  121. $line = fgets($fp, 4096);
  122. if ($atStart)
  123. {
  124. // Deal with first line of returned data
  125. $atStart = false;
  126. if (!preg_match('/HTTP\/(\\d\\.\\d)\\s*(\\d+)\\s*(.*)/', $line, $m))
  127. {
  128. $this->errormsg = "Status code line invalid: " . htmlentities($line);
  129. $this->debug($this->errormsg);
  130. return false;
  131. }
  132. $http_version = $m[1]; // not used
  133. $this->status = $m[2];
  134. $status_string = $m[3]; // not used
  135. $this->debug(trim($line));
  136. continue;
  137. }
  138. if ($inHeaders)
  139. {
  140. if (trim($line) == '')
  141. {
  142. $inHeaders = false;
  143. $this->debug('Received Headers', $this->headers);
  144. if ($this->headers_only)
  145. {
  146. break; // Skip the rest of the input
  147. }
  148. continue;
  149. }
  150. if (!preg_match('/([^:]+):\\s*(.*)/', $line, $m))
  151. {
  152. // Skip to the next header
  153. continue;
  154. }
  155. $key = strtolower(trim($m[1]));
  156. $val = trim($m[2]);
  157. // Deal with the possibility of multiple headers of same name
  158. if (isset($this->headers[$key]))
  159. {
  160. if (is_array($this->headers[$key]))
  161. {
  162. $this->headers[$key][] = $val;
  163. } else
  164. {
  165. $this->headers[$key] = array($this->headers[$key], $val);
  166. }
  167. } else
  168. {
  169. $this->headers[$key] = $val;
  170. }
  171. continue;
  172. }
  173. // We're not in the headers, so append the line to the contents
  174. $this->content .= $line;
  175. }
  176. fclose($fp);
  177. // If data is compressed, uncompress it
  178. if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] ==
  179. 'gzip')
  180. {
  181. $this->debug('Content is gzip encoded, unzipping it');
  182. $this->content = substr($this->content, 10); // See http://www.php.net/manual/en/function.gzencode.php
  183. $this->content = gzinflate($this->content);
  184. }
  185. // If $persist_cookies, deal with any cookies
  186. //if ($this->persist_cookies && isset($this->headers['set-cookie']) && $this->host == $this->cookie_host) {
  187. if ($this->persist_cookies && isset($this->headers['set-cookie']))
  188. {
  189. $cookies = $this->headers['set-cookie'];
  190. if (!is_array($cookies))
  191. {
  192. $cookies = array($cookies);
  193. }
  194. foreach ($cookies as $cookie)
  195. {
  196. if (preg_match('/([^=]+)=([^;]+);/', $cookie, $m))
  197. {
  198. $this->cookies[$m[1]] = $m[2];
  199. }
  200. }
  201. // Record domain of cookies for security reasons
  202. //$this->cookie_host = $this->host;
  203. }
  204. // If $persist_referers, set the referer ready for the next request
  205. if ($this->persist_referers)
  206. {
  207. $this->debug('Persisting referer: ' . $this->getRequestURL());
  208. $this->referer = $this->getRequestURL();
  209. }
  210. // Finally, if handle_redirects and a redirect is sent, do that
  211. /*if ($this->handle_redirects) {
  212.   if (++$this->redirect_count >= $this->max_redirects) {
  213.   $this->errormsg = 'Number of redirects exceeded maximum ('.$this->max_redirects.')';
  214.   $this->debug($this->errormsg);
  215.   $this->redirect_count = 0;
  216.   return false;
  217.   }
  218.   $location = isset($this->headers['location']) ? $this->headers['location'] : '';
  219.   $uri = isset($this->headers['uri']) ? $this->headers['uri'] : '';
  220.   if ($location || $uri) {
  221.   $url = parse_url($location.$uri);
  222.   // This will FAIL if redirect is to a different site
  223.   return $this->get($url['path']);
  224.   }
  225.   }*/
  226. return true;
  227. }
  228. function buildRequest()
  229. {
  230. $headers = array();
  231. $headers[] = "{$this->method} {$this->path} HTTP/1.0"; // Using 1.1 leads to all manner of problems, such as "chunked" encoding
  232. $headers[] = "Host: {$this->host}";
  233. $headers[] = "User-Agent: {$this->user_agent}";
  234. $headers[] = "Accept: {$this->accept}";
  235. if ($this->use_gzip)
  236. {
  237. $headers[] = "Accept-encoding: {$this->accept_encoding}";
  238. }
  239. $headers[] = "Accept-language: {$this->accept_language}";
  240. if ($this->referer)
  241. {
  242. $headers[] = "Referer: {$this->referer}";
  243. }
  244. // Cookies
  245. if ($this->cookies)
  246. {
  247. $cookie = 'Cookie: ';
  248. foreach ($this->cookies as $key => $value)
  249. {
  250. $cookie .= "$key=$value; ";
  251. }
  252. $headers[] = $cookie;
  253. }
  254. // Basic authentication
  255. if ($this->username && $this->password)
  256. {
  257. $headers[] = 'Authorization: BASIC ' . base64_encode($this->username . ':' . $this->
  258. password);
  259. }
  260. // If this is a POST, set the content type and length
  261. if ($this->postdata)
  262. {
  263. $headers[] = 'Content-Type: application/x-www-form-urlencoded';
  264. $headers[] = 'Content-Length: ' . strlen($this->postdata);
  265. }
  266. $request = implode("
  267. ", $headers) . "
  268.  
  269. " . $this->postdata;
  270. return $request;
  271. }
  272. function getStatus()
  273. {
  274. return $this->status;
  275. }
  276. function getContent()
  277. {
  278. return $this->content;
  279. }
  280. function getHeaders()
  281. {
  282. return $this->headers;
  283. }
  284. function getHeader($header)
  285. {
  286. $header = strtolower($header);
  287. if (isset($this->headers[$header]))
  288. {
  289. return $this->headers[$header];
  290. } else
  291. {
  292. return false;
  293. }
  294. }
  295. function getError()
  296. {
  297. return $this->errormsg;
  298. }
  299. function getCookies()
  300. {
  301. return $this->cookies;
  302. }
  303. function getRequestURL()
  304. {
  305. $url = 'http://' . $this->host;
  306. if ($this->port != 80)
  307. {
  308. $url .= ':' . $this->port;
  309. }
  310. $url .= $this->path;
  311. return $url;
  312. }
  313. // Setter methods
  314. function setUserAgent($string)
  315. {
  316. $this->user_agent = $string;
  317. }
  318. function setAuthorization($username, $password)
  319. {
  320. $this->username = $username;
  321. $this->password = $password;
  322. }
  323. function setCookies($array)
  324. {
  325. $this->cookies = $array;
  326. }
  327. // Option setting methods
  328. function useGzip($boolean)
  329. {
  330. $this->use_gzip = $boolean;
  331. }
  332. function setPersistCookies($boolean)
  333. {
  334. $this->persist_cookies = $boolean;
  335. }
  336. function setPersistReferers($boolean)
  337. {
  338. $this->persist_referers = $boolean;
  339. }
  340. function setHandleRedirects($boolean)
  341. {
  342. $this->handle_redirects = $boolean;
  343. }
  344. function setMaxRedirects($num)
  345. {
  346. $this->max_redirects = $num;
  347. }
  348. function setHeadersOnly($boolean)
  349. {
  350. $this->headers_only = $boolean;
  351. }
  352. function setDebug($boolean)
  353. {
  354. $this->debug = $boolean;
  355. }
  356. // "Quick" static methods
  357. function quickGet($url)
  358. {
  359. $bits = parse_url($url);
  360. $host = $bits['host'];
  361. $port = isset($bits['port']) ? $bits['port'] : 80;
  362. $path = isset($bits['path']) ? $bits['path'] : '/';
  363. if (isset($bits['query']))
  364. {
  365. $path .= '?' . $bits['query'];
  366. }
  367. $client = new HttpClient($host, $port);
  368. if (!$client->get($path))
  369. {
  370. return false;
  371. } else
  372. {
  373. return $client->getContent();
  374. }
  375. }
  376. function quickPost($url, $data)
  377. {
  378. $bits = parse_url($url);
  379. $host = $bits['host'];
  380. $port = isset($bits['port']) ? $bits['port'] : 80;
  381. $path = isset($bits['path']) ? $bits['path'] : '/';
  382. $client = new HttpClient($host, $port);
  383. if (!$client->post($path, $data))
  384. {
  385. return false;
  386. } else
  387. {
  388. return $client->getContent();
  389. }
  390. }
  391. function debug($msg, $object = false)
  392. {
  393. if ($this->debug)
  394. {
  395. print '<div style="border: 1px solid red; padding: 0.5em; margin: 0.5em;"><strong>HttpClient Debug:</strong> ' .
  396. $msg;
  397. if ($object)
  398. {
  399. print_r($object);
  400. print '<pre>' . $content . '</pre>';
  401. }
  402. print '</div>';
  403. }
  404. }
  405. }
  406. ?>

Report this snippet  

You need to login to post a comment.