OSDN Git Service

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