pop3.php

来自「PHP 知识管理系统(基于树结构的知识管理系统), 英文原版的PHP源码。」· PHP 代码 · 共 1,227 行 · 第 1/3 页

PHP
1,227
字号
<?php
// +-----------------------------------------------------------------------+
// | Copyright (c) 2002, Richard Heyes                                     |
// | All rights reserved.                                                  |
// |                                                                       |
// | Redistribution and use in source and binary forms, with or without    |
// | modification, are permitted provided that the following conditions    |
// | are met:                                                              |
// |                                                                       |
// | o Redistributions of source code must retain the above copyright      |
// |   notice, this list of conditions and the following disclaimer.       |
// | o Redistributions in binary form must reproduce the above copyright   |
// |   notice, this list of conditions and the following disclaimer in the |
// |   documentation and/or other materials provided with the distribution.|
// | o The names of the authors may not be used to endorse or promote      |
// |   products derived from this software without specific prior written  |
// |   permission.                                                         |
// |                                                                       |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  |
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      |
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   |
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  |
// |                                                                       |
// +-----------------------------------------------------------------------+
// | Author: Richard Heyes <richard@phpguru.org>                           |
// | Co-Author: Damian Fernandez Sosa <damlists@cnba.uba.ar>               |
// +-----------------------------------------------------------------------+
//
// $Id: POP3.php 6819 2007-06-20 13:09:21Z kevin_fourie $

require_once('Net/Socket.php');



/**
*  +----------------------------- IMPORTANT ------------------------------+
*  | Usage of this class compared to native php extensions such as IMAP   |
*  | is slow and may be feature deficient. If available you are STRONGLY  |
*  | recommended to use the php extensions.                               |
*  +----------------------------------------------------------------------+
*
* POP3 Access Class
*
* For usage see the example script
*/

define('NET_POP3_STATE_DISCONNECTED',  1, true);
define('NET_POP3_STATE_AUTHORISATION', 2, true);
define('NET_POP3_STATE_TRANSACTION',   4, true);

class Net_POP3 {

    /*
    * Some basic information about the mail drop
    * garnered from the STAT command
    *
    * @var array
    */
    var $_maildrop;

    /*
    * Used for APOP to store the timestamp
    *
    * @var string
    */
    var $_timestamp;

    /*
    * Timeout that is passed to the socket object
    *
    * @var integer
    */
    var $_timeout;

    /*
    * Socket object
    *
    * @var object
    */
    var $_socket;

    /*
    * Current state of the connection. Used with the
    * constants defined above.
    *
    * @var integer
    */
    var $_state;

    /*
    * Hostname to connect to
    *
    * @var string
    */
    var $_host;

    /*
    * Port to connect to
    *
    * @var integer
    */
    var $_port;

    /**
    * To allow class debuging
    * @var boolean
    */
    var $_debug = false;


    /**
    * The auth methods this class support
    * @var array
    */
    //var $supportedAuthMethods=array('DIGEST-MD5', 'CRAM-MD5', 'APOP' , 'PLAIN' , 'LOGIN', 'USER');
    //Disabling DIGEST-MD5 for now
    var $supportedAuthMethods=array( 'CRAM-MD5', 'APOP' , 'PLAIN' , 'LOGIN', 'USER');
    //var $supportedAuthMethods=array( 'CRAM-MD5', 'PLAIN' , 'LOGIN');
    //var $supportedAuthMethods=array( 'PLAIN' , 'LOGIN');


    /**
    * The auth methods this class support
    * @var array
    */
    var $supportedSASLAuthMethods=array('DIGEST-MD5', 'CRAM-MD5');


    /**
    * The capability response
    * @var array
    */
    var $_capability;

   /*
    * Constructor. Sets up the object variables, and instantiates
    * the socket object.
    *
    */


    function Net_POP3()
    {
        $this->_timestamp =  ''; // Used for APOP
        $this->_maildrop  =  array();
        $this->_timeout   =  3;
        $this->_state     =  NET_POP3_STATE_DISCONNECTED;
        $this->_socket    =& new Net_Socket();
        /*
        * Include the Auth_SASL package.  If the package is not available,
        * we disable the authentication methods that depend upon it.
        */
        if ((@include_once 'Auth/SASL.php') == false) {
            if($this->_debug){
                echo "AUTH_SASL NOT PRESENT!\n";
            }
            foreach($this->supportedSASLAuthMethods as $SASLMethod){
                $pos = array_search( $SASLMethod, $this->supportedAuthMethods );
                if($this->_debug){
                    echo "DISABLING METHOD $SASLMethod\n";
                }
                unset($this->supportedAuthMethods[$pos]);
            }
        }



    }


    /**
    * Handles the errors the class can find
    * on the server
    *
    * @access private
    * @return PEAR_Error
    */

    function _raiseError($msg, $code =-1)
    {
    include_once 'PEAR.php';
    return PEAR::raiseError($msg, $code);
    }


    
    /*
    * Connects to the given host on the given port.
    * Also looks for the timestamp in the greeting
    * needed for APOP authentication
    *
    * @param  string $host Hostname/IP address to connect to
    * @param  string $port Port to use to connect to on host
    * @return bool  Success/Failure
    */
    function connect($host = 'localhost', $port = 110)
    {
        $this->_host = $host;
        $this->_port = $port;

        $result = $this->_socket->connect($host, $port, false, $this->_timeout);
        if ($result === true) {
            $data = $this->_recvLn();

            if( $this->_checkResponse($data) ){
            // if the response begins with '+OK' ...
//            if (@substr(strtoupper($data), 0, 3) == '+OK') {
                // Check for string matching apop timestamp
                if (preg_match('/<.+@.+>/U', $data, $matches)) {
                    $this->_timestamp = $matches[0];
                }
                $this->_maildrop = array();
                $this->_state    = NET_POP3_STATE_AUTHORISATION;

                return true;
            }
        }

        $this->_socket->disconnect();
        return false;
    }

    /*
    * Disconnect function. Sends the QUIT command
    * and closes the socket.
    *
    * @return bool Success/Failure
    */
    function disconnect()
    {
        return $this->_cmdQuit();
    }

    /*
    * Performs the login procedure. If there is a timestamp
    * stored, APOP will be tried first, then basic USER/PASS.
    *
    * @param  string $user Username to use
    * @param  string $pass Password to use
    * @param  mixed $apop Whether to try APOP first, if used as string you can select the auth methd to use ( $pop3->login('validlogin', 'validpass', "CRAM-MD5");
    *          Valid methods are: 'DIGEST-MD5','CRAM-MD5','LOGIN','PLAIN','APOP','USER' 
    * @return mixed  true on Success/ PEAR_ERROR on error
    */
    function login($user, $pass, $apop = true)
    {
        if ($this->_state == NET_POP3_STATE_AUTHORISATION) {

            if(PEAR::isError($ret= $this->_cmdAuthenticate($user , $pass , $apop ) ) ){
                return $ret;
            }
            if( ! PEAR::isError($ret)){
                $this->_state = NET_POP3_STATE_TRANSACTION;
                return true;
            }

        }
        return $this->_raiseError('Generic login error' , 1);
    }



    /**
    * Parses the response from the capability command. Stores
    * the result in $this->_capability
    *
    * @access private
    */
    function _parseCapability()
    {

        if(!PEAR::isError($data = $this->_sendCmd('CAPA'))){
            $data = $this->_getMultiline();
        }else {
            // CAPA command not supported, reset data var
            //  to avoid Notice errors of preg_split on an object
            $data = '';
        }
        $data = preg_split('/\r?\n/', $data, -1, PREG_SPLIT_NO_EMPTY);

        for ($i = 0; $i < count($data); $i++) {

            $capa='';
            if (preg_match('/^([a-z,\-]+)( ((.*))|$)$/i', $data[$i], $matches)) {

                $capa=strtolower($matches[1]);
                switch ($capa) {
                    case 'implementation':
                        $this->_capability['implementation'] = $matches[3];
                        break;
                    case 'sasl':
                        $this->_capability['sasl'] = preg_split('/\s+/', $matches[3]);
                        break;
                    default :
                        $this->_capability[$capa] = $matches[2];
                        break;
                }
            }
        }
    }




    /**
     * Returns the name of the best authentication method that the server
     * has advertised.
     *
     * @param string if !=null,authenticate with this method ($userMethod).
     *
     * @return mixed    Returns a string containing the name of the best
     *                  supported authentication method or a PEAR_Error object
     *                  if a failure condition is encountered.
     * @access private
     * @since  1.0
     */
    function _getBestAuthMethod($userMethod = null)
    {

/*
       return 'USER';
       return 'APOP';
       return 'DIGEST-MD5';
       return 'CRAM-MD5';
*/


        $this->_parseCapability();

        //unset($this->_capability['sasl']);

       if( isset($this->_capability['sasl']) ){
           $serverMethods=$this->_capability['sasl'];
       }else{
            $serverMethods=array('USER');
            // Check for timestamp before attempting APOP
            if ($this->_timestamp != null)
            {
                $serverMethods[] = 'APOP';
            }
       }

        if($userMethod !== null && $userMethod !== true ){
            $methods = array();
            $methods[] = $userMethod;
            return $userMethod;
        }else{
            $methods = $this->supportedAuthMethods;
        }

        if( ($methods != null) && ($serverMethods != null)){

            foreach ( $methods as $method ) {

                if ( in_array( $method , $serverMethods ) ) {
                    return $method;
                }
            }
            $serverMethods=implode(',' , $serverMethods );
            $myMethods=implode(',' ,$this->supportedAuthMethods);
            return $this->_raiseError("$method NOT supported authentication method!. This server " .
                "supports these methods: $serverMethods, but I support $myMethods");
        }else{
            return $this->_raiseError("This server don't support any Auth methods");
        }
    }






    /* Handles the authentication using any known method
     *
     * @param string The userid to authenticate as.
     * @param string The password to authenticate with.
     * @param string The method to use ( if $usermethod == '' then the class chooses the best method (the stronger is the best ) )
     *
     * @return mixed  string or PEAR_Error
     *
     * @access private
     * @since  1.0
     */
    function _cmdAuthenticate($uid , $pwd , $userMethod = null )
    {


        if ( PEAR::isError( $method = $this->_getBestAuthMethod($userMethod) ) ) {
            return $method;
        }

        switch ($method) {
            case 'DIGEST-MD5':
                $result = $this->_authDigest_MD5( $uid , $pwd );
                break;
            case 'CRAM-MD5':
                $result = $this->_authCRAM_MD5( $uid , $pwd );
                break;
            case 'LOGIN':
                $result = $this->_authLOGIN( $uid , $pwd );
                break;
            case 'PLAIN':
                $result = $this->_authPLAIN( $uid , $pwd );

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?