OSDN Git Service

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