Posted By

shaunjanssens on 11/05/09


Tagged

api DirectAdmin httpsocket


Versions (?)

Who likes this?

2 people have marked this snippet as a favorite

shaunjanssens
Juntalis


DirectAdmin API httpsocket.php


 / Published in: PHP
 

Socket communication class for DirectAdmin

  1. <?php
  2.  
  3. /**
  4.  * Socket communication class.
  5.  *
  6.  * Originally designed for use with DirectAdmin's API, this class will fill any HTTP socket need.
  7.  *
  8.  * Very, very basic usage:
  9.  * $Socket = new HTTPSocket;
  10.  * echo $Socket->get('http://user:[email protected]/somedir/some.file?query=string&this=that');
  11.  *
  12.  * @author Phi1 'l0rdphi1' Stier <[email protected]>
  13.  * @package HTTPSocket
  14.  * @version 2.6
  15.  */
  16. class HTTPSocket {
  17.  
  18. var $version = '2.6';
  19.  
  20. /* all vars are private except $error, $query_cache, and $doFollowLocationHeader */
  21.  
  22. var $method = 'GET';
  23.  
  24. var $remote_host;
  25. var $remote_port;
  26. var $remote_uname;
  27. var $remote_passwd;
  28.  
  29. var $result;
  30. var $result_header;
  31. var $result_body;
  32. var $result_status_code;
  33.  
  34. var $lastTransferSpeed;
  35.  
  36. var $bind_host;
  37.  
  38. var $error = array();
  39. var $warn = array();
  40. var $query_cache = array();
  41.  
  42. var $doFollowLocationHeader = TRUE;
  43. var $redirectURL;
  44.  
  45. var $extra_headers = array();
  46.  
  47. /**
  48.   * Create server "connection".
  49.   *
  50.   */
  51. function connect($host, $port = '' )
  52. {
  53. if (!is_numeric($port))
  54. {
  55. $port = 80;
  56. }
  57.  
  58. $this->remote_host = $host;
  59. $this->remote_port = $port;
  60. }
  61.  
  62. function bind( $ip = '' )
  63. {
  64. if ( $ip == '' )
  65. {
  66. $ip = $_SERVER['SERVER_ADDR'];
  67. }
  68.  
  69. $this->bind_host = $ip;
  70. }
  71.  
  72. /**
  73.   * Change the method being used to communicate.
  74.   *
  75.   * @param string|null request method. supports GET, POST, and HEAD. default is GET
  76.   */
  77. function set_method( $method = 'GET' )
  78. {
  79. $this->method = strtoupper($method);
  80. }
  81.  
  82. /**
  83.   * Specify a username and password.
  84.   *
  85.   * @param string|null username. defualt is null
  86.   * @param string|null password. defualt is null
  87.   */
  88. function set_login( $uname = '', $passwd = '' )
  89. {
  90. if ( strlen($uname) > 0 )
  91. {
  92. $this->remote_uname = $uname;
  93. }
  94.  
  95. if ( strlen($passwd) > 0 )
  96. {
  97. $this->remote_passwd = $passwd;
  98. }
  99.  
  100. }
  101.  
  102. /**
  103.   * Query the server
  104.   *
  105.   * @param string containing properly formatted server API. See DA API docs and examples. Http:// URLs O.K. too.
  106.   * @param string|array query to pass to url
  107.   * @param int if connection KB/s drops below value here, will drop connection
  108.   */
  109. function query( $request, $content = '', $doSpeedCheck = 0 )
  110. {
  111. $this->error = $this->warn = array();
  112. $this->result_status_code = NULL;
  113.  
  114. // is our request a http:// ... ?
  115. if (preg_match('!^http://!i',$request))
  116. {
  117. $location = parse_url($request);
  118. $this->connect($location['host'],$location['port']);
  119. $this->set_login($location['user'],$location['pass']);
  120.  
  121. $request = $location['path'];
  122. $content = $location['query'];
  123.  
  124. if ( strlen($request) < 1 )
  125. {
  126. $request = '/';
  127. }
  128.  
  129. }
  130.  
  131. $array_headers = array(
  132. 'User-Agent' => "HTTPSocket/$this->version",
  133. 'Host' => ( $this->remote_port == 80 ? $this->remote_host : "$this->remote_host:$this->remote_port" ),
  134. 'Accept' => '*/*',
  135. 'Connection' => 'Close' );
  136.  
  137. foreach ( $this->extra_headers as $key => $value )
  138. {
  139. $array_headers[$key] = $value;
  140. }
  141.  
  142. $this->result = $this->result_header = $this->result_body = '';
  143.  
  144. // was content sent as an array? if so, turn it into a string
  145. if (is_array($content))
  146. {
  147. $pairs = array();
  148.  
  149. foreach ( $content as $key => $value )
  150. {
  151. $pairs[] = "$key=".urlencode($value);
  152. }
  153.  
  154. $content = join('&',$pairs);
  155. unset($pairs);
  156. }
  157.  
  158. $OK = TRUE;
  159.  
  160. // instance connection
  161. if ($this->bind_host)
  162. {
  163. $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  164. socket_bind($socket,$this->bind_host);
  165.  
  166. if (!@socket_connect($socket,$this->remote_host,$this->remote_port))
  167. {
  168. $OK = FALSE;
  169. }
  170.  
  171. }
  172. else
  173. {
  174. $socket = @fsockopen( $this->remote_host, $this->remote_port, $sock_errno, $sock_errstr, 10 );
  175. }
  176.  
  177. if ( !$socket || !$OK )
  178. {
  179. $this->error[] = "Can't create socket connection to $this->remote_host:$this->remote_port.";
  180. return 0;
  181. }
  182.  
  183. // if we have a username and password, add the header
  184. if ( isset($this->remote_uname) && isset($this->remote_passwd) )
  185. {
  186. $array_headers['Authorization'] = 'Basic '.base64_encode("$this->remote_uname:$this->remote_passwd");
  187. }
  188.  
  189. // for DA skins: if $this->remote_passwd is NULL, try to use the login key system
  190. if ( isset($this->remote_uname) && $this->remote_passwd == NULL )
  191. {
  192. $array_headers['Cookie'] = "session={$_SERVER['SESSION_ID']}; key={$_SERVER['SESSION_KEY']}";
  193. }
  194.  
  195. // if method is POST, add content length & type headers
  196. if ( $this->method == 'POST' )
  197. {
  198. $array_headers['Content-type'] = 'application/x-www-form-urlencoded';
  199. $array_headers['Content-length'] = strlen($content);
  200. }
  201. // else method is GET or HEAD. we don't support anything else right now.
  202. else
  203. {
  204. if ($content)
  205. {
  206. $request .= "?$content";
  207. }
  208. }
  209.  
  210. // prepare query
  211. $query = "$this->method $request HTTP/1.0
  212. ";
  213. foreach ( $array_headers as $key => $value )
  214. {
  215. $query .= "$key: $value
  216. ";
  217. }
  218. $query .= "
  219. ";
  220.  
  221. // if POST we need to append our content
  222. if ( $this->method == 'POST' && $content )
  223. {
  224. $query .= "$content
  225.  
  226. ";
  227. }
  228.  
  229. // query connection
  230. if ($this->bind_host)
  231. {
  232. socket_write($socket,$query);
  233.  
  234. // now load results
  235. while ( $out = socket_read($socket,2048) )
  236. {
  237. $this->result .= $out;
  238. }
  239. }
  240. else
  241. {
  242. fwrite( $socket, $query, strlen($query) );
  243.  
  244. // now load results
  245. $this->lastTransferSpeed = 0;
  246. $status = socket_get_status($socket);
  247. $startTime = time();
  248. $length = 0;
  249. $prevSecond = 0;
  250. while ( !feof($socket) && !$status['timed_out'] )
  251. {
  252. $chunk = fgets($socket,1024);
  253. $length += strlen($chunk);
  254. $this->result .= $chunk;
  255.  
  256. $elapsedTime = time() - $startTime;
  257.  
  258. if ( $elapsedTime > 0 )
  259. {
  260. $this->lastTransferSpeed = ($length/1024)/$elapsedTime;
  261. }
  262.  
  263. if ( $doSpeedCheck > 0 && $elapsedTime > 5 && $this->lastTransferSpeed < $doSpeedCheck )
  264. {
  265. $this->warn[] = "kB/s for last 5 seconds is below 50 kB/s (~".( ($length/1024)/$elapsedTime )."), dropping connection...";
  266. $this->result_status_code = 503;
  267. break;
  268. }
  269.  
  270. }
  271.  
  272. if ( $this->lastTransferSpeed == 0 )
  273. {
  274. $this->lastTransferSpeed = $length/1024;
  275. }
  276.  
  277. }
  278.  
  279. list($this->result_header,$this->result_body) = split("
  280.  
  281. ",$this->result,2);
  282.  
  283. if ($this->bind_host)
  284. {
  285. socket_close($socket);
  286. }
  287. else
  288. {
  289. fclose($socket);
  290. }
  291.  
  292. $this->query_cache[] = $query;
  293.  
  294.  
  295. $headers = $this->fetch_header();
  296.  
  297. // what return status did we get?
  298. if (!$this->result_status_code)
  299. {
  300. preg_match("#HTTP/1\.. (\d+)#",$headers[0],$matches);
  301. $this->result_status_code = $matches[1];
  302. }
  303.  
  304. // did we get the full file?
  305. if ( !empty($headers['content-length']) && $headers['content-length'] != strlen($this->result_body) )
  306. {
  307. $this->result_status_code = 206;
  308. }
  309.  
  310. // now, if we're being passed a location header, should we follow it?
  311. if ($this->doFollowLocationHeader)
  312. {
  313. if ($headers['location'])
  314. {
  315. $this->redirectURL = $headers['location'];
  316. $this->query($headers['location']);
  317. }
  318. }
  319.  
  320. }
  321.  
  322. function getTransferSpeed()
  323. {
  324. return $this->lastTransferSpeed;
  325. }
  326.  
  327. /**
  328.   * The quick way to get a URL's content :)
  329.   *
  330.   * @param string URL
  331.   * @param boolean return as array? (like PHP's file() command)
  332.   * @return string result body
  333.   */
  334. function get($location, $asArray = FALSE )
  335. {
  336. $this->query($location);
  337.  
  338. if ( $this->get_status_code() == 200 )
  339. {
  340. if ($asArray)
  341. {
  342. return split("\n",$this->fetch_body());
  343. }
  344.  
  345. return $this->fetch_body();
  346. }
  347.  
  348. return FALSE;
  349. }
  350.  
  351. /**
  352.   * Returns the last status code.
  353.   * 200 = OK;
  354.   * 403 = FORBIDDEN;
  355.   * etc.
  356.   *
  357.   * @return int status code
  358.   */
  359. function get_status_code()
  360. {
  361. return $this->result_status_code;
  362. }
  363.  
  364. /**
  365.   * Adds a header, sent with the next query.
  366.   *
  367.   * @param string header name
  368.   * @param string header value
  369.   */
  370. function add_header($key,$value)
  371. {
  372. $this->extra_headers[$key] = $value;
  373. }
  374.  
  375. /**
  376.   * Clears any extra headers.
  377.   *
  378.   */
  379. function clear_headers()
  380. {
  381. $this->extra_headers = array();
  382. }
  383.  
  384. /**
  385.   * Return the result of a query.
  386.   *
  387.   * @return string result
  388.   */
  389. function fetch_result()
  390. {
  391. return $this->result;
  392. }
  393.  
  394. /**
  395.   * Return the header of result (stuff before body).
  396.   *
  397.   * @param string (optional) header to return
  398.   * @return array result header
  399.   */
  400. function fetch_header( $header = '' )
  401. {
  402. $array_headers = split("
  403. ",$this->result_header);
  404.  
  405. $array_return = array( 0 => $array_headers[0] );
  406. unset($array_headers[0]);
  407.  
  408. foreach ( $array_headers as $pair )
  409. {
  410. list($key,$value) = split(": ",$pair,2);
  411. $array_return[strtolower($key)] = $value;
  412. }
  413.  
  414. if ( $header != '' )
  415. {
  416. return $array_return[strtolower($header)];
  417. }
  418.  
  419. return $array_return;
  420. }
  421.  
  422. /**
  423.   * Return the body of result (stuff after header).
  424.   *
  425.   * @return string result body
  426.   */
  427. function fetch_body()
  428. {
  429. return $this->result_body;
  430. }
  431.  
  432. /**
  433.   * Return parsed body in array format.
  434.   *
  435.   * @return array result parsed
  436.   */
  437. function fetch_parsed_body()
  438. {
  439. parse_str($this->result_body,$x);
  440. return $x;
  441. }
  442.  
  443. }
  444.  
  445. ?>

Report this snippet  

You need to login to post a comment.