Location: PHPKode > scripts > XS PHP Library > xs-php-library/inc/smtp.inc.php
<?php
//
// +--------------------------------------------------------------------------+
// |                                                                          |
// |                   XS PHP Library  Generic Classes Library                |
// |                                                                          |
// |                   Copyright (c) 2001-2002 XSPHPLib Group.                |
// |                                                                          |
// +--------------------------------------------------------------------------+
// |                                                                          |
// | Distributed under the terms of the GNU Lesser General Public License as  |
// | published by the Free Software Foundation version 2.1                    |
// | See the GNU Lesser General Public License for more details. You should   |
// | have received a copy of the GNU Lesser General Public License along with |
// | this package; if not, write to the Free Software Foundation, Inc.,       |
// | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.                 |
// |                                                                          |
// +--------------------------------------------------------------------------+
// |                                                                          |
// | Authors: Robert Bala <hide@address.com>                                   |
// |          Hans Zaunere <hide@address.com>                                   |
// |                                                                          |
// +--------------------------------------------------------------------------+
//
// $Id: smtp.inc.php,v 1.2 2003/01/25 23:25:02 rbala Exp $

/**
 * SMTP access class.
 *
 * SMTP class is a wrapper to the SMTP protocol, as specified by RFC 821.
 * All mandatory SMTP commands are available, as are a few optional SMTP
 * commands. It can be used to construct SMTP based web mail program, seding
 * new mail from the web, or even to authenticate secured areas of the web site.
 *
 * @author Robert Bala <hide@address.com>
 * @author Hans Zaunere <hide@address.com>
 * @access public
 * @package net
 * @version $Id: smtp.inc.php,v 1.2 2003/01/25 23:25:02 rbala Exp $
 */
class SMTP extends Object {

	/**
	 * IP address or host name.
     * @access private
	 * @var string
	 */
    var $_host;

	/**
	 * TCP port number.
     * @access private
	 * @var int
	 */
    var $_port;
    
	/**
     * Stores detected features of the SMTP server.
     * @access private
     * @var array
     */
    var $_esmtp;

	/**
	 * The banner returned by the SMTP server.
     * @access private
	 * @var int
	 */
    var $_banner;
    
	/**
	 * The last response status returned by the SMTP server.
     * @access private
	 * @var int
	 */
    var $_status;
    
	/**
     * The socket resource being used to connect to the SMTP server.
     * @access private
     * @var resource
     */
    var $_socket;

    /**
     * SMTP class constructor.
     *
     * Creates the new instance of SMTP class and sets up basic properties.
     *
     * @access public
     * @param string $host IP address or host name, defaults to "".
     * @param int $port TCP port number, defaults to 25.
     * @return void
     */
    function SMTP($host='', $port=25) {
        Object::Object();
        $this->_host = $host;
        $this->_port = $port;
        $this->_esmtp = array();
        $this->_banner = '';
        $this->_status = '';
        $this->_socket = null;
    }

    /**
     * Gets the IP address or host name.
     *
     * Returns IP address or host name.
     *
     * @access public
     * @return string
     */
    function getHost() {
        return $this->_host;
    }

    /**
     * Gets the TCP port number.
     *
     * Returns TCP port number.
     *
     * @access public
     * @return int
     */
    function getPort() {
        return $this->_port;
    }
    
    /**
     * Gets the banner returned by the SMTP server.
     *
     * If called when the connection is already established, it returns the
     * banner returned by the SMTP server otherwise it returns empty string.
     *
     * @access public
     * @return string
     */
    function getBanner() {
        return $this->_banner;
    }
    
    /**
     * Gets the last response message returned by the POP3 server.
     *
     * If called when the connection is already established, it returns the
     * last response smessage returned by the POP3 server otherwise it returns
     * empty string.
     *
     * @access public
     * @return string
     */
    function getStatus() {
        return $this->_status;
    }

    /**
     * Sets the IP address or host name.
     *
     * Returns True on success or a error object if the connection is
     * already established.
     *
     * @access public
     * @return mixed
     */
    function setHost($host) {
        if (!$this->isOpened()) {
            $this->_host = $host;
        } else {
            return new Error('sethost(): SMTP connection already established.');
        }
        return true;
    }

    /**
     * Sets the TCP port number.
     *
     * Returns True on success or a error object if the connection is
     * already established.
     *
     * @access public
     * @return mixed
     */
    function setPort($port) {
        if (!$this->isOpened()) {
            $this->_port = $port;
        } else {
            return new Error('setport(): SMTP connection already established.');
        }
        return true;
    }

    /**
     * Attempt to open connection to the SMTP server.
     *
     * If called when the connection is already established, it returns error
     * object otherwise it returns true on success or a error object with an
     * error message on any kind of failure.
     *
     * @access public
     * @return mixed
     */
    function open() {
        if (!$this->isOpened()) {
            $socket = new Socket($this->_host, $this->_port, 1, 512);
            if (object_isError($socket)) {
                return new Error('open(): SMTP unable to open socket.');
            }
            if (object_isError($socket->open())) {
                return new Error('open(): SMTP unable to open socket.');
            }
            $this->_status = $socket->readLine();
            if (smtp_extractCode($this->_status) != '220') {
		        return new Error('open(): SMTP server not 220 ready.');
            }
            $this->_banner = smtp_extractInfo($this->_status);
            if (object_isError($socket->writeLine('EHLO ' . $this->_host))) {
		        return new Error('open(): SMTP write to socket failed.');
            }
            $this->_status = $socket->readLine();
            if (smtp_extractCode($this->_status) == '250') {
                do {
                    if ($reply = $socket->readLine()) {
                        if (strpos($reply, '-')) {
                            $token = strtok($reply, '-');
                        } else {
                            $token = strtok($reply, ' ');
                        }
                        $reply = substr($reply, strlen($token) + 1, strlen($reply) - strlen($token) - 1);
                        $token = strtok($reply, ' ');
                        $reply = substr($reply, strlen($token) + 1, strlen($reply) - strlen($token) - 2);
                        $this->_esmtp[$token] = $reply;
                    }
                    $status = $socket->status();
                } while ($status['unread_bytes'] > 0);
            } else {
                if (object_isError($socket->writeLine('HELO ' . $this->_host))) {
		            return new Error('open(): SMTP write to socket failed.');
                }
                $this->_status = $socket->readLine();
                if (smtp_extractCode($this->_status) != '250') {
		            return new Error('open(): SMTP HELO not accepted.');
                }
            }
            $this->_socket =& $socket;
        } else {
            return new Error('open(): SMTP socket connection already established.');
        }
        return true;
    }
    
    /**
     * Attempt to close connection from the SMTP server.
     *
     * If called when the connection is not established, it returns error
     * object otherwise it returns true on success or a error object with an
     * error message on any kind of failure.
     *
     * @access public
     * @return mixed
     */
    function close() {
        if ($this->isOpened()) {
            if (object_isError($this->_socket->writeLine('QUIT'))) {
                return new Error('close(): SMTP write to socket failed');
            }
            $this->_status = $this->_socket->readLine();
            if (smtp_extractCode($this->_status) != '221') {
		        return new Error('close(): SMTP 221 Bye not received.');
            }
            if (object_isError($this->_socket->close())) {
                return new Error('close(): SMTP unable to close socket.');
            }
            $this->_esmtp = array();
        } else {
            return new Error('close(): SMTP socket connection not established.');
        }
        return true;
    }
    
    /**
     * Send the EHLO command and obtain a list of available ESMTP extensions.
     *
     * If called when the connection is not established, it returns error
     * object otherwise it returns true on success or a error object with an
     * error message on any kind of failure.
     *
     * @access public
     * @param string $domain the domain name to say we are.
     * @return mixed
     */
	function ehlo($domain) {
        if ($this->isOpened()) {
            $this->_esmtp[] = array();
            if (object_isError($this->_socket->writeLine('EHLO ' . $domain))) {
		        return new Error('ehlo(): SMTP write to socket failed.');
            }
            $this->_status = $this->_socket->readLine();
            if (smtp_extractCode($this->_status) != '250') {
		        return new Error('ehlo(): SMTP 250 OK not received.');
            }
            do {
                if ($reply = $this->_socket->readLine()) {
                    if (strpos($reply, '-')) {
                        $token = strtok($reply, '-');
                    } else {
                        $token = strtok($reply, ' ');
                    }
                    $reply = substr($reply, strlen($token) + 1, strlen($reply) - strlen($token) - 1);
                    $token = strtok($reply, ' ');
                    $reply = substr($reply, strlen($token) + 1, strlen($reply) - strlen($token) - 2);
                    $this->_esmtp[$token] = $reply;
                }
                $status = $this->_socket->status();
            } while ($status['unread_bytes'] > 0);
        } else {
            return new Error('ehlo(): SMTP socket connection not established.');
        }
		return true;
	}
 
    /**
     * Send the HELO command.
     *
     * If called when the connection is not established, it returns error
     * object otherwise it returns true on success or a error object with an
     * error message on any kind of failure.
     *
     * @access public
     * @param string $domain the domain name to say we are.
     * @return mixed
     */
	function helo($domain) {
        if ($this->isOpened()) {
            if (object_isError($this->_socket->writeLine('HELO ' . $domain))) {
                return new Error('helo(): SMTP write to socket failed.');
            }
            $this->_status = $this->_socket->readLine();
            if (smtp_extractCode($this->_status) != '250') {
		        return new Error('helo(): SMTP 250 OK not received.');
            }
        } else {
            return new Error('helo(): SMTP socket connection not established.');
        }
		return true;
	}
 
    /**
     * Send the VRFY command.
     *
     * If called when the connection is not established, it returns error
     * object otherwise it returns true on success or a error object with an
     * error message on any kind of failure.
     *
     * @access public
     * @param string $string the string to verify.
     * @return mixed
     */
	function vrfy($string) {
        if ($this->isOpened()) {
            if (object_isError($this->_socket->writeLine('VRFY ' . $string))) {
                return new Error('vrfy(): SMTP write to socket failed.');
            }
            $this->_status = $this->_socket->readLine();
            if (smtp_extractCode($this->_status) != '250') {
		        return new Error('vrfy(): SMTP 250 OK not received.');
            }
        } else {
            return new Error('vrfy(): SMTP socket connection not established.');
        }
		return true;
	}
 
	function expn($string) {
        if ($this->isOpened()) {
            if (object_isError($this->_socket->writeLine('EXPN ' . $string))) {
                return new Error('expn(): SMTP write to socket failed.');
            }
            $this->_status = $this->_socket->readLine();
            if (smtp_extractCode($this->_status) != '250') {
		        return new Error('expn(): SMTP 250 OK not received.');
            }
        } else {
            return new Error('expn(): SMTP socket connection not established.');
        }
		return true;
	}
 
    /**
     * Attempt to do SMTP authentication.
     *
     * Attempt to do user authentication if this feature is supported by SMTP
     * server. If called when the connection is not established, it returns
     * error object otherwise it returns true on success or a error object
     * with an error message on any kind of failure.
     *
     * @access public
     * @param string $user the username to login.
     * @param string $pass the password to login.
     * @return mixed
     */
	function auth($user, $pass) {
		if (isset($this->_esmtp['AUTH'])) {
            if (object_isError($this->_socket->writeLine('AUTH LOGIN'))) {
                return new Error('auth(): SMTP write to socket failed');
            }
            $this->_status = $this->_socket->readLine();
            if (smtp_extractCode($this->_status) != '334') {
		        return new Error('auth(): SMTP AUTH LOGIN not recognize.');
            }
            if (object_isError($this->_socket->write(base64_encode($user) . "\n"))) {
                return new Error('auth(): SMTP write to socket failed');
            }
            $this->_status = $this->_socket->readLine();
            if (smtp_extractCode($this->_status) != '334') {
		        return new Error('auth(): SMTP 334 not received.');
            }
            if (object_isError($this->_socket->write(base64_encode($pass) . "\n"))) {
                return new Error('auth(): SMTP write to socket failed');
            }
            $this->_status = $this->_socket->readLine();
            if (smtp_extractCode($this->_status) != '235') {
		        return new Error('auth(): SMTP 235 not received.');
            }
        } else {
            return new Error('auth(): SMTP auth not supported.');
        }
		return true;
	}

    /**
     * Send the RSET command.
     *
     * If called when the connection is not established, it returns error
     * object otherwise it returns true on success or a error object with an
     * error message on any kind of failure.
     *
     * @access public
     * @return mixed
     */
	function rset() {
        if ($this->isOpened()) {
            if (object_isError($this->_socket->writeLine('RSET'))) {
                return new Error('rset(): SMTP write to socket failed.');
            }
            $this->_status = $this->_socket->readLine();
            if (smtp_extractCode($this->_status) != '250') {
		        return new Error('rset(): SMTP 250 OK not received.');
            }
        } else {
            return new Error('rset(): SMTP socket connection not established.');
        }
		return true;
	}
 
    /**
     * Send the NOOP command.
     *
     * If called when the connection is not established, it returns error
     * object otherwise it returns true on success or a error object with an
     * error message on any kind of failure.
     *
     * @access public
     * @return mixed
     */
	function noop() {
        if ($this->isOpened()) {
            if (object_isError($this->_socket->writeLine('NOOP'))) {
                return new Error('noop(): SMTP write to socket failed.');
            }
            $this->_status = $this->_socket->readLine();
            if (smtp_extractCode($this->_status) != '250') {
		        return new Error('noop(): SMTP 250 OK not received.');
            }
        } else {
            return new Error('noop(): SMTP socket connection not established.');
        }
		return true;
	}

    /**
     * Send the MAIL FROM command.
     *
     * If called when the connection is not established, it returns error
     * object otherwise it returns true on success or a error object with an
     * error message on any kind of failure.
     *
     * @access public
     * @param string $addr the sender (reverse path) to set.
     * @return mixed
     */
	function mail($addr) {
        if ($this->isOpened()) {
            if (object_isError($this->_socket->writeLine('MAIL FROM:' .  smtp_extractAddr($addr)))) {
                return new Error('mail(): SMTP write to socket failed.');
            }
            $this->_status = $this->_socket->readLine();
            if (smtp_extractCode($this->_status) != '250') {
		        return new Error('mail(): SMTP 250 OK not received.');
            }
        } else {
            return new Error('mail(): SMTP socket connection not established.');
        }
		return true;
	}
 
    /**
     * Send the SEND FROM command.
     *
     * If called when the connection is not established, it returns error
     * object otherwise it returns true on success or a error object with an
     * error message on any kind of failure.
     *
     * @access public
     * @param string $addr the sender (reverse path) to send.
     * @return mixed
     */
	function send($addr) {
        if ($this->isOpened()) {
            if (object_isError($this->_socket->writeLine('SEND FROM:' .  smtp_extractAddr($addr)))) {
                return new Error('send(): SMTP write to socket failed.');
            }
            $this->_status = $this->_socket->readLine();
            if (smtp_extractCode($this->_status) != '250') {
		        return new Error('send(): SMTP 250 OK not received.');
            }
        } else {
            return new Error('send(): SMTP socket connection not established.');
        }
		return true;
	}
 
    /**
     * Send the SOML FROM command.
     *
     * If called when the connection is not established, it returns error
     * object otherwise it returns true on success or a error object with an
     * error message on any kind of failure.
     *
     * @access public
     * @param string $addr the reverse path to send.
     * @return mixed
     */
	function soml($addr) {
        if ($this->isOpened()) {
            if (object_isError($this->_socket->writeLine('SOML FROM:' .  smtp_extractAddr($addr)))) {
                return new Error('soml(): SMTP write to socket failed.');
            }
            $this->_status = $this->_socket->readLine();
            if (smtp_extractCode($this->_status) != '250') {
		        return new Error('soml(): SMTP 250 OK not received.');
            }
        } else {
            return new Error('soml(): SMTP socket connection not established.');
        }
		return true;
	}
 
    /**
     * Send the SAML FROM command.
     *
     * If called when the connection is not established, it returns error
     * object otherwise it returns true on success or a error object with an
     * error message on any kind of failure.
     *
     * @access public
     * @param string $addr the reverse path to send.
     * @return mixed
     */
	function saml($addr) {
        if ($this->isOpened()) {
            if (object_isError($this->_socket->writeLine('SAML FROM:' .  smtp_extractAddr($addr)))) {
                return new Error('saml(): SMTP write to socket failed.');
            }
            $this->_status = $this->_socket->readLine();
            if (smtp_extractCode($this->_status) != '250') {
		        return new Error('saml(): SMTP 250 OK not received.');
            }
        } else {
            return new Error('saml(): SMTP socket connection not established.');
        }
		return true;
	}
 
    /**
     * Send the RCPT TO command.
     *
     * If called when the connection is not established, it returns error
     * object otherwise it returns true on success or a error object with an
     * error message on any kind of failure.
     *
     * @access public
     * @param string $addr recipient (forward path) to add.
     * @return mixed
     */
	function rcpt($addr) {
        if ($this->isOpened()) {
            if (object_isError($this->_socket->writeLine('RCPT TO:' .  smtp_extractAddr($addr)))) {
                return new Error('rcpt(): SMTP write to socket failed.');
            }
            $this->_status = $this->_socket->readLine();
            if (smtp_extractCode($this->_status) != '250') {
		        return new Error('rcpt(): SMTP 250 OK not received.');
            }
        } else {
            return new Error('rcpt(): SMTP socket connection not established.');
        }
		return true;
    }
    
    /**
     * Send the DATA command.
     *
     * If called when the connection is not established, it returns error
     * object otherwise it returns true on success or a error object with an
     * error message on any kind of failure.
     *
     * @access public
     * @param string $data the message body to send.
     * @return mixed
     */
	function data($data) {
        if ($this->isOpened()) {
            if (object_isError($this->_socket->writeLine('DATA'))) {
                return new Error('data(): SMTP write to socket failed.');
            }
            $this->_status = $this->_socket->readLine();
            if (smtp_extractCode($this->_status) != '354') {
		        return new Error('data(): SMTP 354 not received.');
            }
		    $data = preg_replace("/\n\n/", "\n\r\n", $data);
		    $data = preg_replace("/^(\..*)/", ".\\1", $data);
    		$data = preg_replace("/([^\r]{1})\n/", "\\1\r\n", $data);
            if (object_isError($this->_socket->writeLine($data . "\r\n."))) {
                return new Error('data(): SMTP write to socket failed.');
            }
            $this->_status = $this->_socket->readLine();
            if (smtp_extractCode($this->_status) != '250') {
		        return new Error('data(): SMTP 250 OK not received.');
            }
        } else {
            return new Error('data(): SMTP socket connection not established.');
        }
		return true;
	}
 
    /**
     * Finds whether the socket connection is opened.
     *
     * Returns true if the connection is established, false otherwise.
     *
     * @access public
     * @return boolean
     */
    function isOpened() {
        return (isset($this->_socket) && $this->_socket->isOpened());
    }

}

/**
 * Extracts response code returned from SMTP server.
 *
 * Returns response code returned from SMTP server on success, Null
 * otherwise.
 *
 * @author Hans Zaunere <hide@address.com>
 * @access private
 * @param string $string the response returned from SMTP server.
 * @return mixed
 */

function smtp_extractCode( $string ) {
    if( is_numeric(substr($string,0,3)) )
        return (int) substr($string,0,3);
    return NULL;
}

/**
 * Extracts response message returned from SMTP server.
 *
 * Returns response message returned from SMTP server on success, empty string
 * otherwise.
 *
 * @author Robert Bala <hide@address.com>
 * @access private
 * @param string $string the response returned from SMTP server.
 * @return string
 */
function smtp_extractInfo($string) {
    $indent = smtp_extractCode($string);
    if ($indent == $string) {
        return '';
    }
    return substr($string, strlen($indent) + 1, strlen($string) - strlen($indent) - 1);
}

/**
 * Extracts email address.
 *
 * Returns valid email address from the string on success, empty string
 * otherwise.
 *
 * @author Robert Bala <hide@address.com>
 * @access public
 * @param string $string the string from which email is extracted.
 * @return string
 */
function smtp_extractAddr($string) {
    if (preg_match("/([^<)\s]+@\S+\.[^>(\s]+)/", $string, $match)) {
        return  '<' . $match[0] . '>';
    }
    return '';
}

?>
Return current item: XS PHP Library