使用PHP Socket写的POP3类

前端技术 2023/09/08 PHP

查看 POP3/SMTP 协议的时候想尝试一下自己写一个操作类,核心没啥,就是使用 fsockopen ,然后写入/接收数据,只实现了最核心的部分功能,当作是学习 Socket 操作的练手。其中参考了 RFC 2449和一个国外的简单Web邮件系统 Uebimiau 的部分代码,不过绝对没有抄他滴,HOHO,绝对原创。

复制代码 代码如下:

<?php
class SocketPOPClient
{
    var $strMessage        = \'\';
    var $intErrorNum    = 0;
    var $bolDebug        = false;

    var $strEmail        = \'\';
    var $strPasswd        = \'\';
    var $strHost        = \'\';
    var $intPort        = 110;
    var $intConnSecond    = 30;
    var $intBuffSize    = 8192;

    var $resHandler        = NULL;
    var $bolIsLogin        = false;
    var $strRequest        = \'\';
    var $strResponse    = \'\';
    var $arrRequest        = array();
    var $arrResponse    = array();


    //---------------
    // 基础操作
    //---------------

    //构造函数
    function SocketPOP3Client($strLoginEmail, $strLoginPasswd, $strPopHost=\'\', $intPort=\'\')
    {
        $this->strEmail        = trim(strtolower($strLoginEmail));
        $this->strPasswd    = trim($strLoginPasswd);
        $this->strHost        = trim(strtolower($strPopHost));

        if ($this->strEmail==\'\' || $this->strPasswd==\'\')
        {
            $this->setMessage(\'Email address or Passwd is empty\', 1001);
            return false;
        }
        if (!PReg_match(\"/^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$/i\", $this->strEmail))
        {
            $this->setMessage(\'Email address invalid\', 1002);
            return false;
        }
        if ($this->strHost==\'\')
        {
            $this->strHost = substr(strrchr($this->strEmail, \"@\"), 1);
        }
        if ($intPort!=\'\')
        {
            $this->intPort = $intPort;
        }
        $this->connectHost();
    }

    //连接服务器
    function connectHost()
    {
        if ($this->bolDebug)
        {
            echo \"Connection \".$this->strHost.\" ...\\r\\n\";
        }
        if (!$this->getIsConnect())
        {
            if ($this->strHost==\'\' || $this->intPort==\'\')
            {
                $this->setMessage(\'POP3 host or Port is empty\', 1003);
                return false;            
            }
            $this->resHandler = @fsockopen($this->strHost, $this->intPort, &$this->intErrorNum, &$this->strMessage, $this->intConnSecond);
            if (!$this->resHandler)
            {
                $strErrMsg = \'Connection POP3 host: \'.$this->strHost.\' failed\';
                $intErrNum = 2001;
                $this->setMessage($strErrMsg, $intErrNum);
                return false;
            }
            $this->getLineResponse();
            if (!$this->getRestIsSucceed())
            {
                return false;
            }
        }
        return true;
    }

    //关闭连接
    function closeHost()
    {
        if ($this->resHandler)
        {
            fclose($this->resHandler);
        }
        return true;
    }

    //发送指令
    function sendCommand($strCommand)
    {
        if ($this->bolDebug)
        {
            if (!preg_match(\"/PASS/\", $strCommand))
            {
                echo \"Send Command: \".$strCommand.\"\\r\\n\";
            }
            else
            {
                echo \"Send Command: PASS ******\\r\\n\";
            }

        }
        if (!$this->getIsConnect())
        {
            return false;
        }
        if (trim($strCommand)==\'\')
        {
            $this->setMessage(\'Request command is empty\', 1004);
            return false;
        }
        $this->strRequest = $strCommand.\"\\r\\n\";
        $this->arrRequest[] = $strCommand;
        fputs($this->resHandler, $this->strRequest);
        return true;
    }

    //提取响应信息第一行
    function getLineResponse()
    {
        if (!$this->getIsConnect())
        {
            return false;
        }
        $this->strResponse = fgets($this->resHandler, $this->intBuffSize);
        $this->arrResponse[] = $this->strResponse;

        return $this->strResponse;        
    }

    //提取若干响应信息,$intReturnType是返回值类型, 1为字符串, 2为数组
    function getRespMessage($intReturnType)
    {
        if (!$this->getIsConnect())
        {
            return false;
        }
        if ($intReturnType == 1)
        {
            $strAllResponse = \'\';
            while(!feof($this->resHandler))
            {
                $strLineResponse = $this->getLineResponse();
                if (preg_match(\"/^\\+OK/\", $strLineResponse))
                {
                    continue;
                }
                if (trim($strLineResponse)==\'.\')
                {
                    break;
                }
                $strAllResponse .= $strLineResponse;
            }
            return $strAllResponse;
        }
        else
        {
            $arrAllResponse = array();
            while(!feof($this->resHandler))
            {
                $strLineResponse = $this->getLineResponse();
                if (preg_match(\"/^\\+OK/\", $strLineResponse))
                {
                    continue;
                }
                if (trim($strLineResponse)==\'.\')
                {
                    break;
                }
                $arrAllResponse[] = $strLineResponse;
            }
            return $arrAllResponse;            
        }
    }

    //提取请求是否成功
    function getRestIsSucceed($strRespMessage=\'\')
    {
        if (trim($responseMessage)==\'\')
        {
            if ($this->strResponse==\'\')
            {
                $this->getLineResponse();
            }
            $strRespMessage = $this->strResponse;
        }
        if (trim($strRespMessage)==\'\')
        {
            $this->setMessage(\'Response message is empty\', 2003);
            return false;
        }
        if (!preg_match(\"/^\\+OK/\", $strRespMessage))
        {
            $this->setMessage($strRespMessage, 2000);
            return false;
        }
        return true;
    }

    //获取是否已连接
    function getIsConnect()
    {
        if (!$this->resHandler)
        {
            $this->setMessage(\"Nonexistent availability connection handler\", 2002);
            return false;
        }
        return true;
    }


    //设置消息
    function setMessage($strMessage, $intErrorNum)
    {
        if (trim($strMessage)==\'\' || $intErrorNum==\'\')
        {
            return false;
        }
        $this->strMessage    = $strMessage;
        $this->intErrorNum    = $intErrorNum;
        return true;
    }

    //获取消息
    function getMessage()
    {
        return $this->strMessage;
    }

    //获取错误号
    function getErrorNum()
    {
        return $this->intErrorNum;
    }

    //获取请求信息
    function getRequest()
    {
        return $this->strRequest;        
    }

    //获取响应信息
    function getResponse()
    {
        return $this->strResponse;
    }


    //---------------
    // 邮件原子操作
    //---------------

    //登录邮箱
    function popLogin()
    {
        if (!$this->getIsConnect())
        {
            return false;
        }
        $this->sendCommand(\"USER \".$this->strEmail);
        $this->getLineResponse();
        $bolUserRight = $this->getRestIsSucceed();

        $this->sendCommand(\"PASS \".$this->strPasswd);
        $this->getLineResponse();
        $bolPassRight = $this->getRestIsSucceed();

        if (!$bolUserRight || !$bolPassRight)
        {
            $this->setMessage($this->strResponse, 2004);
            return false;
        }        
        $this->bolIsLogin = true;
        return true;
    }

    //退出登录
    function popLogout()
    {
        if (!$this->getIsConnect() && $this->bolIsLogin)
        {
            return false;
        }
        $this->sendCommand(\"QUIT\");
        $this->getLineResponse();
        if (!$this->getRestIsSucceed())
        {
            return false;
        }
        return true;
    }

    //获取是否在线
    function getIsOnline()
    {
        if (!$this->getIsConnect() && $this->bolIsLogin)
        {
            return false;
        }
        $this->sendCommand(\"NOOP\");
        $this->getLineResponse();
        if (!$this->getRestIsSucceed())
        {
            return false;
        }
        return true;        
    }

    //获取邮件数量和字节数(返回数组)
    function getMailSum($intReturnType=2)
    {
        if (!$this->getIsConnect() && $this->bolIsLogin)
        {
            return false;
        }
        $this->sendCommand(\"STAT\");
        $strLineResponse = $this->getLineResponse();
        if (!$this->getRestIsSucceed())
        {
            return false;
        }
        if ($intReturnType==1)
        {
            return     $this->strResponse;
        }
        else
        {
            $arrResponse = explode(\" \", $this->strResponse);
            if (!is_array($arrResponse) || count($arrResponse)<=0)
            {
                $this->setMessage(\'STAT command response message is error\', 2006);
                return false;
            }
            return array($arrResponse[1], $arrResponse[2]);
        }
    }

    //获取指定邮件得session Id
    function getMailSessId($intMailId, $intReturnType=2)
    {
        if (!$this->getIsConnect() && $this->bolIsLogin)
        {
            return false;
        }
        if (!$intMailId = intval($intMailId))
        {
            $this->setMessage(\'Mail message id invalid\', 1005);
            return false;
        }
        $this->sendCommand(\"UIDL \". $intMailId);
        $this->getLineResponse();
        if (!$this->getRestIsSucceed())
        {
            return false;
        }
        if ($intReturnType == 1)
        {
            return     $this->strResponse;
        }
        else
        {
            $arrResponse = explode(\" \", $this->strResponse);
            if (!is_array($arrResponse) || count($arrResponse)<=0)
            {
                $this->setMessage(\'UIDL command response message is error\', 2006);
                return false;
            }
            return array($arrResponse[1], $arrResponse[2]);
        }
    }

    //取得某个邮件的大小
    function getMailSize($intMailId, $intReturnType=2)
    {
        if (!$this->getIsConnect() && $this->bolIsLogin)
        {
            return false;
        }
        $this->sendCommand(\"LIST \".$intMailId);
        $this->getLineResponse();
        if (!$this->getRestIsSucceed())
        {
            return false;
        }
        if ($intReturnType == 1)
        {
            return $this->strResponse;
        }
        else
        {
            $arrMessage = explode(\' \', $this->strResponse);
            return array($arrMessage[1], $arrMessage[2]);
        }
    }

    //获取邮件基本列表数组
    function getMailBaseList($intReturnType=2)
    {
        if (!$this->getIsConnect() && $this->bolIsLogin)
        {
            return false;
        }
        $this->sendCommand(\"LIST\");
        $this->getLineResponse();
        if (!$this->getRestIsSucceed())
        {
            return false;
        }
        return $this->getRespMessage($intReturnType);
    }

    //获取指定邮件所有信息,intReturnType是返回值类型,1是字符串,2是数组
    function getMailMessage($intMailId, $intReturnType=1)
    {
        if (!$this->getIsConnect() && $this->bolIsLogin)
        {
            return false;
        }
        if (!$intMailId = intval($intMailId))
        {
            $this->setMessage(\'Mail message id invalid\', 1005);
            return false;
        }
        $this->sendCommand(\"RETR \". $intMailId);
        $this->getLineResponse();
        if (!$this->getRestIsSucceed())
        {
            return false;
        }
        return $this->getRespMessage($intReturnType);
    }

    //获取某邮件前指定行, $intReturnType 返回值类型,1是字符串,2是数组
    function getMailTopMessage($intMailId, $intTopLines=10, $intReturnType=1)
    {
        if (!$this->getIsConnect() && $this->bolIsLogin)
        {
            return false;
        }
        if (!$intMailId=intval($intMailId) || !$intTopLines=int($intTopLines))
        {
            $this->setMessage(\'Mail message id or Top lines number invalid\', 1005);
            return false;
        }
        $this->sendCommand(\"TOP \". $intMailId .\" \". $intTopLines);
        $this->getLineResponse();
        if (!$this->getRestIsSucceed())
        {
            return false;
        }
        return $this->getRespMessage($intReturnType);
    }

    //删除邮件
    function delMail($intMailId)
    {
        if (!$this->getIsConnect() && $this->bolIsLogin)
        {
            return false;
        }
        if (!$intMailId=intval($intMailId))
        {
            $this->setMessage(\'Mail message id invalid\', 1005);
            return false;
        }
        $this->sendCommand(\"DELE \".$intMailId);
        $this->getLineResponse();
        if (!$this->getRestIsSucceed())
        {
            return false;
        }
        return true;
    }

    //重置被删除得邮件标记为未删除
    function resetDeleMail()
    {
        if (!$this->getIsConnect() && $this->bolIsLogin)
        {
            return false;
        }
        $this->sendCommand(\"RSET\");
        $this->getLineResponse();
        if (!$this->getRestIsSucceed())
        {
            return false;
        }
        return true;        
    }

    //---------------
    // 调试操作
    //---------------

    //输出对象信息
    function printObject()
    {
        print_r($this);
        exit;
    }

    //输出错误信息
    function printError()
    {
        echo \"[Error Msg] : $strMessage     <br>\\n\";
        echo \"[Error Num] : $intErrorNum <br>\\n\";
        exit;
    }

    //输出主机信息
    function printHost()
    {
        echo \"[Host]  : $this->strHost <br>\\n\";
        echo \"[Port]  : $this->intPort <br>\\n\";
        echo \"[Email] : $this->strEmail <br>\\n\";
        echo \"[Passwd] : ******** <br>\\n\";
        exit;
    }

    //输出连接信息
    function printConnect()
    {
        echo \"[Connect] : $this->resHandler <br>\\n\";
        echo \"[Request] : $this->strRequest <br>\\n\";
        echo \"[Response] : $this->strResponse <br>\\n\";
        exit;
    }
}

?>
<?
//测试代码
//例如:$o = SocketPOP3Client(\'邮箱地址\', \'密码\', \'POP3服务器\', \'POP3端口\')

/*
set_time_limit(0);
$o = new SocketPOPClient(\'abc@126.com\', \'123456\', \'pop.126.com\', \'110\');
$o->popLogin();
print_r($o->getMailBaseList());
print_r($o->getMailSum(1));
print_r($o->getMailTopMessage(2, 2, 2));
$o->popLogout();
$o->closeHost();
$o->printObject();
*/
?>

本文地址:https://www.stayed.cn/item/20658

转载请注明出处。

本站部分内容来源于网络,如侵犯到您的权益,请 联系我

我的博客

人生若只如初见,何事秋风悲画扇。