PageRenderTime 42ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/mrbs/tags/mrbs-post-MDB-merge/web/Net/Socket.php

https://github.com/jessfishenden/mrbs-mcr
PHP | 456 lines | 196 code | 33 blank | 227 comment | 39 complexity | 54f7c3146a49ea5e1a1138a325878834 MD5 | raw file
  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4 |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 The PHP Group |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.0 of the PHP license, |
  9. // | that is bundled with this package in the file LICENSE, and is |
  10. // | available at through the world-wide-web at |
  11. // | http://www.php.net/license/2_02.txt. |
  12. // | If you did not receive a copy of the PHP license and are unable to |
  13. // | obtain it through the world-wide-web, please send a note to |
  14. // | license@php.net so we can mail you a copy immediately. |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Stig Bakken <ssb@php.net> |
  17. // | Chuck Hagenbuch <chuck@horde.org> |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id$
  21. //
  22. require_once 'PEAR.php';
  23. /**
  24. * Generalized Socket class. More docs to be written.
  25. *
  26. * @version 1.0
  27. * @author Stig Bakken <ssb@php.net>
  28. * @author Chuck Hagenbuch <chuck@horde.org>
  29. */
  30. class Net_Socket extends PEAR {
  31. // {{{ properties
  32. /** Socket file pointer. */
  33. var $fp = null;
  34. /** Whether the socket is blocking. */
  35. var $blocking = true;
  36. /** Whether the socket is persistent. */
  37. var $persistent = false;
  38. /** The IP address to connect to. */
  39. var $addr = '';
  40. /** The port number to connect to. */
  41. var $port = 0;
  42. /** Number of seconds to wait on socket connections before
  43. assuming there's no more data. */
  44. var $timeout = false;
  45. /** Number of bytes to read at a time in readLine() and
  46. readAll(). */
  47. var $lineLength = 2048;
  48. // }}}
  49. // {{{ constructor
  50. /**
  51. * Constructs a new Net_Socket object.
  52. *
  53. * @access public
  54. */
  55. function Net_Socket()
  56. {
  57. $this->PEAR();
  58. }
  59. // }}}
  60. // {{{ connect()
  61. /**
  62. * Connect to the specified port. If called when the socket is
  63. * already connected, it disconnects and connects again.
  64. *
  65. * @param $addr string IP address or host name
  66. * @param $port int TCP port number
  67. * @param $persistent bool (optional) whether the connection is
  68. * persistent (kept open between requests by the web server)
  69. * @param $timeout int (optional) how long to wait for data
  70. * @param $options array see options for stream_context_create
  71. * @access public
  72. * @return mixed true on success or error object
  73. */
  74. function connect($addr, $port, $persistent = null, $timeout = null, $options = null)
  75. {
  76. if (is_resource($this->fp)) {
  77. @fclose($this->fp);
  78. $this->fp = null;
  79. }
  80. if (strspn($addr, '.0123456789') == strlen($addr)) {
  81. $this->addr = $addr;
  82. } else {
  83. $this->addr = gethostbyname($addr);
  84. }
  85. $this->port = $port % 65536;
  86. if ($persistent !== null) {
  87. $this->persistent = $persistent;
  88. }
  89. if ($timeout !== null) {
  90. $this->timeout = $timeout;
  91. }
  92. $openfunc = $this->persistent ? 'pfsockopen' : 'fsockopen';
  93. $errno = 0;
  94. $errstr = '';
  95. if ($options && function_exists('stream_context_create')) {
  96. if ($this->timeout) {
  97. $timeout = $this->timeout;
  98. } else {
  99. $timeout = 0;
  100. }
  101. $context = stream_context_create($options);
  102. $fp = $openfunc($this->addr, $this->port, $errno, $errstr, $timeout, $context);
  103. } else {
  104. if ($this->timeout) {
  105. $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $this->timeout);
  106. } else {
  107. $fp = @$openfunc($this->addr, $this->port, $errno, $errstr);
  108. }
  109. }
  110. if (!$fp) {
  111. return $this->raiseError($errstr, $errno);
  112. }
  113. $this->fp = $fp;
  114. return $this->setBlocking($this->blocking);
  115. }
  116. // }}}
  117. // {{{ disconnect()
  118. /**
  119. * Disconnects from the peer, closes the socket.
  120. *
  121. * @access public
  122. * @return mixed true on success or an error object otherwise
  123. */
  124. function disconnect()
  125. {
  126. if (is_resource($this->fp)) {
  127. fclose($this->fp);
  128. $this->fp = null;
  129. return true;
  130. }
  131. return $this->raiseError("not connected");
  132. }
  133. // }}}
  134. // {{{ isBlocking()
  135. /**
  136. * Find out if the socket is in blocking mode.
  137. *
  138. * @access public
  139. * @return bool the current blocking mode.
  140. */
  141. function isBlocking()
  142. {
  143. return $this->blocking;
  144. }
  145. // }}}
  146. // {{{ setBlocking()
  147. /**
  148. * Sets whether the socket connection should be blocking or
  149. * not. A read call to a non-blocking socket will return immediately
  150. * if there is no data available, whereas it will block until there
  151. * is data for blocking sockets.
  152. *
  153. * @param $mode bool true for blocking sockets, false for nonblocking
  154. * @access public
  155. * @return mixed true on success or an error object otherwise
  156. */
  157. function setBlocking($mode)
  158. {
  159. if (is_resource($this->fp)) {
  160. $this->blocking = $mode;
  161. socket_set_blocking($this->fp, $this->blocking);
  162. return true;
  163. }
  164. return $this->raiseError("not connected");
  165. }
  166. // }}}
  167. // {{{ setTimeout()
  168. /**
  169. * Sets the timeout value on socket descriptor,
  170. * expressed in the sum of seconds and microseconds
  171. *
  172. * @param $seconds int seconds
  173. * @param $microseconds int microseconds
  174. * @access public
  175. * @return mixed true on success or an error object otherwise
  176. */
  177. function setTimeout($seconds, $microseconds)
  178. {
  179. if (is_resource($this->fp)) {
  180. socket_set_timeout($this->fp, $seconds, $microseconds);
  181. return true;
  182. }
  183. return $this->raiseError("not connected");
  184. }
  185. // }}}
  186. // {{{ getStatus()
  187. /**
  188. * Returns information about an existing socket resource.
  189. * Currently returns four entries in the result array:
  190. *
  191. * <p>
  192. * timed_out (bool) - The socket timed out waiting for data<br>
  193. * blocked (bool) - The socket was blocked<br>
  194. * eof (bool) - Indicates EOF event<br>
  195. * unread_bytes (int) - Number of bytes left in the socket buffer<br>
  196. * </p>
  197. *
  198. * @access public
  199. * @return mixed Array containing information about existing socket resource or an error object otherwise
  200. */
  201. function getStatus()
  202. {
  203. if (is_resource($this->fp)) {
  204. return socket_get_status($this->fp);
  205. }
  206. return $this->raiseError("not connected");
  207. }
  208. // }}}
  209. // {{{ gets()
  210. /**
  211. * Get a specified line of data
  212. *
  213. * @access public
  214. * @return $size bytes of data from the socket, or a PEAR_Error if
  215. * not connected.
  216. */
  217. function gets($size)
  218. {
  219. if (is_resource($this->fp)) {
  220. return fgets($this->fp, $size);
  221. }
  222. return $this->raiseError("not connected");
  223. }
  224. // }}}
  225. // {{{ read()
  226. /**
  227. * Read a specified amount of data. This is guaranteed to return,
  228. * and has the added benefit of getting everything in one fread()
  229. * chunk; if you know the size of the data you're getting
  230. * beforehand, this is definitely the way to go.
  231. *
  232. * @param $size The number of bytes to read from the socket.
  233. * @access public
  234. * @return $size bytes of data from the socket, or a PEAR_Error if
  235. * not connected.
  236. */
  237. function read($size)
  238. {
  239. if (is_resource($this->fp)) {
  240. return fread($this->fp, $size);
  241. }
  242. return $this->raiseError("not connected");
  243. }
  244. // }}}
  245. // {{{ write()
  246. /**
  247. * Write a specified amount of data.
  248. *
  249. * @access public
  250. * @return mixed true on success or an error object otherwise
  251. */
  252. function write($data)
  253. {
  254. if (is_resource($this->fp)) {
  255. return fwrite($this->fp, $data);
  256. }
  257. return $this->raiseError("not connected");
  258. }
  259. // }}}
  260. // {{{ writeLine()
  261. /**
  262. * Write a line of data to the socket, followed by a trailing "\r\n".
  263. *
  264. * @access public
  265. * @return mixed fputs result, or an error
  266. */
  267. function writeLine ($data)
  268. {
  269. if (is_resource($this->fp)) {
  270. return $this->write($data . "\r\n");
  271. }
  272. return $this->raiseError("not connected");
  273. }
  274. // }}}
  275. // {{{ eof()
  276. /**
  277. * Tests for end-of-file on a socket descriptor
  278. *
  279. * @access public
  280. * @return bool
  281. */
  282. function eof()
  283. {
  284. return (is_resource($this->fp) && feof($this->fp));
  285. }
  286. // }}}
  287. // {{{ readByte()
  288. /**
  289. * Reads a byte of data
  290. *
  291. * @access public
  292. * @return 1 byte of data from the socket, or a PEAR_Error if
  293. * not connected.
  294. */
  295. function readByte()
  296. {
  297. if (is_resource($this->fp)) {
  298. return ord($this->read(1));
  299. }
  300. return $this->raiseError("not connected");
  301. }
  302. // }}}
  303. // {{{ readWord()
  304. /**
  305. * Reads a word of data
  306. *
  307. * @access public
  308. * @return 1 word of data from the socket, or a PEAR_Error if
  309. * not connected.
  310. */
  311. function readWord()
  312. {
  313. if (is_resource($this->fp)) {
  314. $buf = $this->read(2);
  315. return (ord($buf[0]) + (ord($buf[1]) << 8));
  316. }
  317. return $this->raiseError("not connected");
  318. }
  319. // }}}
  320. // {{{ readInt()
  321. /**
  322. * Reads an int of data
  323. *
  324. * @access public
  325. * @return 1 int of data from the socket, or a PEAR_Error if
  326. * not connected.
  327. */
  328. function readInt()
  329. {
  330. if (is_resource($this->fp)) {
  331. $buf = $this->read(4);
  332. return (ord($buf[0]) + (ord($buf[1]) << 8) +
  333. (ord($buf[2]) << 16) + (ord($buf[3]) << 24));
  334. }
  335. return $this->raiseError("not connected");
  336. }
  337. // }}}
  338. // {{{ readString()
  339. /**
  340. * Reads a zeroterminated string of data
  341. *
  342. * @access public
  343. * @return string, or a PEAR_Error if
  344. * not connected.
  345. */
  346. function readString()
  347. {
  348. if (is_resource($this->fp)) {
  349. $string = '';
  350. while (($char = $this->read(1)) != "\x00") {
  351. $string .= $char;
  352. }
  353. return $string;
  354. }
  355. return $this->raiseError("not connected");
  356. }
  357. // }}}
  358. // {{{ readIPAddress()
  359. /**
  360. * Reads an IP Address and returns it in a dot formated string
  361. *
  362. * @access public
  363. * @return Dot formated string, or a PEAR_Error if
  364. * not connected.
  365. */
  366. function readIPAddress()
  367. {
  368. if (is_resource($this->fp)) {
  369. $buf = $this->read(4);
  370. return sprintf("%s.%s.%s.%s", ord($buf[0]), ord($buf[1]),
  371. ord($buf[2]), ord($buf[3]));
  372. }
  373. return $this->raiseError("not connected");
  374. }
  375. // }}}
  376. // {{{ readLine()
  377. /**
  378. * Read until either the end of the socket or a newline, whichever
  379. * comes first. Strips the trailing newline from the returned data.
  380. *
  381. * @access public
  382. * @return All available data up to a newline, without that
  383. * newline, or until the end of the socket, or a PEAR_Error if
  384. * not connected.
  385. */
  386. function readLine()
  387. {
  388. if (is_resource($this->fp)) {
  389. $line = '';
  390. $timeout = time() + $this->timeout;
  391. while (!$this->eof() && (!$this->timeout || time() < $timeout)) {
  392. $line .= $this->gets($this->lineLength);
  393. if (substr($line, -2) == "\r\n" ||
  394. substr($line, -1) == "\n") {
  395. return rtrim($line, "\r\n");
  396. }
  397. }
  398. return $line;
  399. }
  400. return $this->raiseError("not connected");
  401. }
  402. // }}}
  403. // {{{ readAll()
  404. /**
  405. * Read until the socket closes. THIS FUNCTION WILL NOT EXIT if the
  406. * socket is in blocking mode until the socket closes.
  407. *
  408. * @access public
  409. * @return All data until the socket closes, or a PEAR_Error if
  410. * not connected.
  411. */
  412. function readAll()
  413. {
  414. if (is_resource($this->fp)) {
  415. $data = '';
  416. while (!$this->eof())
  417. $data .= $this->read($this->lineLength);
  418. return $data;
  419. }
  420. return $this->raiseError("not connected");
  421. }
  422. // }}}
  423. }