home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 June / ENTER.ISO / files / xampp-win32-1.4.5-installer.exe / xampp / Socket.php < prev    next >
Encoding:
PHP Script  |  2004-03-24  |  12.4 KB  |  430 lines

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