Automatically exported from code.google.com/p/planningalerts
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Socket.php 16 KiB

18 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  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: Socket.php,v 1.28 2006/12/13 21:32:03 cweiske Exp $
  21. require_once 'PEAR.php';
  22. define('NET_SOCKET_READ', 1);
  23. define('NET_SOCKET_WRITE', 2);
  24. define('NET_SOCKET_ERROR', 4);
  25. /**
  26. * Generalized Socket class.
  27. *
  28. * @version 1.1
  29. * @author Stig Bakken <ssb@php.net>
  30. * @author Chuck Hagenbuch <chuck@horde.org>
  31. */
  32. class Net_Socket extends PEAR {
  33. /**
  34. * Socket file pointer.
  35. * @var resource $fp
  36. */
  37. var $fp = null;
  38. /**
  39. * Whether the socket is blocking. Defaults to true.
  40. * @var boolean $blocking
  41. */
  42. var $blocking = true;
  43. /**
  44. * Whether the socket is persistent. Defaults to false.
  45. * @var boolean $persistent
  46. */
  47. var $persistent = false;
  48. /**
  49. * The IP address to connect to.
  50. * @var string $addr
  51. */
  52. var $addr = '';
  53. /**
  54. * The port number to connect to.
  55. * @var integer $port
  56. */
  57. var $port = 0;
  58. /**
  59. * Number of seconds to wait on socket connections before assuming
  60. * there's no more data. Defaults to no timeout.
  61. * @var integer $timeout
  62. */
  63. var $timeout = false;
  64. /**
  65. * Number of bytes to read at a time in readLine() and
  66. * readAll(). Defaults to 2048.
  67. * @var integer $lineLength
  68. */
  69. var $lineLength = 2048;
  70. /**
  71. * Connect to the specified port. If called when the socket is
  72. * already connected, it disconnects and connects again.
  73. *
  74. * @param string $addr IP address or host name.
  75. * @param integer $port TCP port number.
  76. * @param boolean $persistent (optional) Whether the connection is
  77. * persistent (kept open between requests
  78. * by the web server).
  79. * @param integer $timeout (optional) How long to wait for data.
  80. * @param array $options See options for stream_context_create.
  81. *
  82. * @access public
  83. *
  84. * @return boolean | PEAR_Error True on success or a PEAR_Error on failure.
  85. */
  86. function connect($addr, $port = 0, $persistent = null, $timeout = null, $options = null)
  87. {
  88. if (is_resource($this->fp)) {
  89. @fclose($this->fp);
  90. $this->fp = null;
  91. }
  92. if (!$addr) {
  93. return $this->raiseError('$addr cannot be empty');
  94. } elseif (strspn($addr, '.0123456789') == strlen($addr) ||
  95. strstr($addr, '/') !== false) {
  96. $this->addr = $addr;
  97. } else {
  98. $this->addr = @gethostbyname($addr);
  99. }
  100. $this->port = $port % 65536;
  101. if ($persistent !== null) {
  102. $this->persistent = $persistent;
  103. }
  104. if ($timeout !== null) {
  105. $this->timeout = $timeout;
  106. }
  107. $openfunc = $this->persistent ? 'pfsockopen' : 'fsockopen';
  108. $errno = 0;
  109. $errstr = '';
  110. if ($options && function_exists('stream_context_create')) {
  111. if ($this->timeout) {
  112. $timeout = $this->timeout;
  113. } else {
  114. $timeout = 0;
  115. }
  116. $context = stream_context_create($options);
  117. $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $timeout, $context);
  118. } else {
  119. if ($this->timeout) {
  120. $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $this->timeout);
  121. } else {
  122. $fp = @$openfunc($this->addr, $this->port, $errno, $errstr);
  123. }
  124. }
  125. if (!$fp) {
  126. return $this->raiseError($errstr, $errno);
  127. }
  128. $this->fp = $fp;
  129. return $this->setBlocking($this->blocking);
  130. }
  131. /**
  132. * Disconnects from the peer, closes the socket.
  133. *
  134. * @access public
  135. * @return mixed true on success or an error object otherwise
  136. */
  137. function disconnect()
  138. {
  139. if (!is_resource($this->fp)) {
  140. return $this->raiseError('not connected');
  141. }
  142. @fclose($this->fp);
  143. $this->fp = null;
  144. return true;
  145. }
  146. /**
  147. * Find out if the socket is in blocking mode.
  148. *
  149. * @access public
  150. * @return boolean The current blocking mode.
  151. */
  152. function isBlocking()
  153. {
  154. return $this->blocking;
  155. }
  156. /**
  157. * Sets whether the socket connection should be blocking or
  158. * not. A read call to a non-blocking socket will return immediately
  159. * if there is no data available, whereas it will block until there
  160. * is data for blocking sockets.
  161. *
  162. * @param boolean $mode True for blocking sockets, false for nonblocking.
  163. * @access public
  164. * @return mixed true on success or an error object otherwise
  165. */
  166. function setBlocking($mode)
  167. {
  168. if (!is_resource($this->fp)) {
  169. return $this->raiseError('not connected');
  170. }
  171. $this->blocking = $mode;
  172. socket_set_blocking($this->fp, $this->blocking);
  173. return true;
  174. }
  175. /**
  176. * Sets the timeout value on socket descriptor,
  177. * expressed in the sum of seconds and microseconds
  178. *
  179. * @param integer $seconds Seconds.
  180. * @param integer $microseconds Microseconds.
  181. * @access public
  182. * @return mixed true on success or an error object otherwise
  183. */
  184. function setTimeout($seconds, $microseconds)
  185. {
  186. if (!is_resource($this->fp)) {
  187. return $this->raiseError('not connected');
  188. }
  189. return socket_set_timeout($this->fp, $seconds, $microseconds);
  190. }
  191. /**
  192. * Sets the file buffering size on the stream.
  193. * See php's stream_set_write_buffer for more information.
  194. *
  195. * @param integer $size Write buffer size.
  196. * @access public
  197. * @return mixed on success or an PEAR_Error object otherwise
  198. */
  199. function setWriteBuffer($size)
  200. {
  201. if (!is_resource($this->fp)) {
  202. return $this->raiseError('not connected');
  203. }
  204. $returned = stream_set_write_buffer($this->fp, $code);
  205. if ($returned == 0) {
  206. return true;
  207. }
  208. return $this->raiseError('Cannot set write buffer.');
  209. }
  210. /**
  211. * Returns information about an existing socket resource.
  212. * Currently returns four entries in the result array:
  213. *
  214. * <p>
  215. * timed_out (bool) - The socket timed out waiting for data<br>
  216. * blocked (bool) - The socket was blocked<br>
  217. * eof (bool) - Indicates EOF event<br>
  218. * unread_bytes (int) - Number of bytes left in the socket buffer<br>
  219. * </p>
  220. *
  221. * @access public
  222. * @return mixed Array containing information about existing socket resource or an error object otherwise
  223. */
  224. function getStatus()
  225. {
  226. if (!is_resource($this->fp)) {
  227. return $this->raiseError('not connected');
  228. }
  229. return socket_get_status($this->fp);
  230. }
  231. /**
  232. * Get a specified line of data
  233. *
  234. * @access public
  235. * @return $size bytes of data from the socket, or a PEAR_Error if
  236. * not connected.
  237. */
  238. function gets($size)
  239. {
  240. if (!is_resource($this->fp)) {
  241. return $this->raiseError('not connected');
  242. }
  243. return @fgets($this->fp, $size);
  244. }
  245. /**
  246. * Read a specified amount of data. This is guaranteed to return,
  247. * and has the added benefit of getting everything in one fread()
  248. * chunk; if you know the size of the data you're getting
  249. * beforehand, this is definitely the way to go.
  250. *
  251. * @param integer $size The number of bytes to read from the socket.
  252. * @access public
  253. * @return $size bytes of data from the socket, or a PEAR_Error if
  254. * not connected.
  255. */
  256. function read($size)
  257. {
  258. if (!is_resource($this->fp)) {
  259. return $this->raiseError('not connected');
  260. }
  261. return @fread($this->fp, $size);
  262. }
  263. /**
  264. * Write a specified amount of data.
  265. *
  266. * @param string $data Data to write.
  267. * @param integer $blocksize Amount of data to write at once.
  268. * NULL means all at once.
  269. *
  270. * @access public
  271. * @return mixed true on success or an error object otherwise
  272. */
  273. function write($data, $blocksize = null)
  274. {
  275. if (!is_resource($this->fp)) {
  276. return $this->raiseError('not connected');
  277. }
  278. if (is_null($blocksize) && !OS_WINDOWS) {
  279. return fwrite($this->fp, $data);
  280. } else {
  281. if (is_null($blocksize)) {
  282. $blocksize = 1024;
  283. }
  284. $pos = 0;
  285. $size = strlen($data);
  286. while ($pos < $size) {
  287. $written = @fwrite($this->fp, substr($data, $pos, $blocksize));
  288. if ($written === false) {
  289. return false;
  290. }
  291. $pos += $written;
  292. }
  293. return $pos;
  294. }
  295. }
  296. /**
  297. * Write a line of data to the socket, followed by a trailing "\r\n".
  298. *
  299. * @access public
  300. * @return mixed fputs result, or an error
  301. */
  302. function writeLine($data)
  303. {
  304. if (!is_resource($this->fp)) {
  305. return $this->raiseError('not connected');
  306. }
  307. return fwrite($this->fp, $data . "\r\n");
  308. }
  309. /**
  310. * Tests for end-of-file on a socket descriptor.
  311. *
  312. * Also returns true if the socket is disconnected.
  313. *
  314. * @access public
  315. * @return bool
  316. */
  317. function eof()
  318. {
  319. return (!is_resource($this->fp) || feof($this->fp));
  320. }
  321. /**
  322. * Reads a byte of data
  323. *
  324. * @access public
  325. * @return 1 byte of data from the socket, or a PEAR_Error if
  326. * not connected.
  327. */
  328. function readByte()
  329. {
  330. if (!is_resource($this->fp)) {
  331. return $this->raiseError('not connected');
  332. }
  333. return ord(@fread($this->fp, 1));
  334. }
  335. /**
  336. * Reads a word of data
  337. *
  338. * @access public
  339. * @return 1 word of data from the socket, or a PEAR_Error if
  340. * not connected.
  341. */
  342. function readWord()
  343. {
  344. if (!is_resource($this->fp)) {
  345. return $this->raiseError('not connected');
  346. }
  347. $buf = @fread($this->fp, 2);
  348. return (ord($buf[0]) + (ord($buf[1]) << 8));
  349. }
  350. /**
  351. * Reads an int of data
  352. *
  353. * @access public
  354. * @return integer 1 int of data from the socket, or a PEAR_Error if
  355. * not connected.
  356. */
  357. function readInt()
  358. {
  359. if (!is_resource($this->fp)) {
  360. return $this->raiseError('not connected');
  361. }
  362. $buf = @fread($this->fp, 4);
  363. return (ord($buf[0]) + (ord($buf[1]) << 8) +
  364. (ord($buf[2]) << 16) + (ord($buf[3]) << 24));
  365. }
  366. /**
  367. * Reads a zero-terminated string of data
  368. *
  369. * @access public
  370. * @return string, or a PEAR_Error if
  371. * not connected.
  372. */
  373. function readString()
  374. {
  375. if (!is_resource($this->fp)) {
  376. return $this->raiseError('not connected');
  377. }
  378. $string = '';
  379. while (($char = @fread($this->fp, 1)) != "\x00") {
  380. $string .= $char;
  381. }
  382. return $string;
  383. }
  384. /**
  385. * Reads an IP Address and returns it in a dot formated string
  386. *
  387. * @access public
  388. * @return Dot formated string, or a PEAR_Error if
  389. * not connected.
  390. */
  391. function readIPAddress()
  392. {
  393. if (!is_resource($this->fp)) {
  394. return $this->raiseError('not connected');
  395. }
  396. $buf = @fread($this->fp, 4);
  397. return sprintf("%s.%s.%s.%s", ord($buf[0]), ord($buf[1]),
  398. ord($buf[2]), ord($buf[3]));
  399. }
  400. /**
  401. * Read until either the end of the socket or a newline, whichever
  402. * comes first. Strips the trailing newline from the returned data.
  403. *
  404. * @access public
  405. * @return All available data up to a newline, without that
  406. * newline, or until the end of the socket, or a PEAR_Error if
  407. * not connected.
  408. */
  409. function readLine()
  410. {
  411. if (!is_resource($this->fp)) {
  412. return $this->raiseError('not connected');
  413. }
  414. ob_start();
  415. $line = '';
  416. $timeout = time() + $this->timeout;
  417. while (!feof($this->fp) && (!$this->timeout || time() < $timeout)) {
  418. $line .= fgets($this->fp, $this->lineLength);
  419. if (substr($line, -1) == "\n") {
  420. ob_end_clean();
  421. return rtrim($line, "\r\n");
  422. }
  423. }
  424. ob_end_clean();
  425. return $line;
  426. }
  427. /**
  428. * Read until the socket closes, or until there is no more data in
  429. * the inner PHP buffer. If the inner buffer is empty, in blocking
  430. * mode we wait for at least 1 byte of data. Therefore, in
  431. * blocking mode, if there is no data at all to be read, this
  432. * function will never exit (unless the socket is closed on the
  433. * remote end).
  434. *
  435. * @access public
  436. *
  437. * @return string All data until the socket closes, or a PEAR_Error if
  438. * not connected.
  439. */
  440. function readAll()
  441. {
  442. if (!is_resource($this->fp)) {
  443. return $this->raiseError('not connected');
  444. }
  445. $data = '';
  446. while (!feof($this->fp)) {
  447. $data .= @fread($this->fp, $this->lineLength);
  448. }
  449. return $data;
  450. }
  451. /**
  452. * Runs the equivalent of the select() system call on the socket
  453. * with a timeout specified by tv_sec and tv_usec.
  454. *
  455. * @param integer $state Which of read/write/error to check for.
  456. * @param integer $tv_sec Number of seconds for timeout.
  457. * @param integer $tv_usec Number of microseconds for timeout.
  458. *
  459. * @access public
  460. * @return False if select fails, integer describing which of read/write/error
  461. * are ready, or PEAR_Error if not connected.
  462. */
  463. function select($state, $tv_sec, $tv_usec = 0)
  464. {
  465. if (!is_resource($this->fp)) {
  466. return $this->raiseError('not connected');
  467. }
  468. $read = null;
  469. $write = null;
  470. $except = null;
  471. if ($state & NET_SOCKET_READ) {
  472. $read[] = $this->fp;
  473. }
  474. if ($state & NET_SOCKET_WRITE) {
  475. $write[] = $this->fp;
  476. }
  477. if ($state & NET_SOCKET_ERROR) {
  478. $except[] = $this->fp;
  479. }
  480. if (false === ($sr = stream_select($read, $write, $except, $tv_sec, $tv_usec))) {
  481. return false;
  482. }
  483. $result = 0;
  484. if (count($read)) {
  485. $result |= NET_SOCKET_READ;
  486. }
  487. if (count($write)) {
  488. $result |= NET_SOCKET_WRITE;
  489. }
  490. if (count($except)) {
  491. $result |= NET_SOCKET_ERROR;
  492. }
  493. return $result;
  494. }
  495. }