喜悦国际村 » 代码共享 » 一个smtp服务器的交互类

页: [1]
angeloisme2008-3-3 08:34 AM
一个smtp服务器的交互类

一个smtp服务器的交互类,其实pear中有类似的东西,反正闲着没事就自己写了一个.如果了解stmp协议看懂 应该不难.最后有例子.
[php]
class SMTP_Controller
{
  const DISCONNECTED  = 1;
  const AUTHORIZATION = 2;
  const TRANSACTION   = 3;
  
  protected $has_SMTP_Server_Extend;
  protected $SMTP_Server_Accept_Max_Size;
  protected $has_SMTP_Server_ETRN;
  protected $has_SMTP_Server_8BITMIME;
  
  protected $SMTP_Server_State;
  protected $SMTP_Server_Host;
  protected $SMTP_Server_Port;
  protected $User;
  protected $Password;
  
  protected $Socket_Resource;
  protected $Server_Response;
  
  public function __construct($host = null, $port = null, $user = null, $pass = null, $limit_time = null)
  {
    ini_set('max_execution_time', 0);
   
    $this->has_SMTP_Server_Extend      = false;
    $this->SMTP_Server_Accept_Max_Size = null;
    $this->has_SMTP_Server_ETRN        = false;
    $this->has_SMTP_Server_8BITMIME    = false;
    $this->SMTP_Server_State           = SMTP_Controller::DISCONNECTED;
    $this->Server_Response             = array();
   
    if (null !== $host) $this->set_SMTP_Server_Host($host);
    if (null !== $port) {
      $this->set_SMTP_Server_Port($port);
    } else  {
      $this->set_SMTP_Server_Port(25);
    }
    if (null !== $user) $this->set_User($user);
    if (null !== $pass) $this->set_Password($pass);
    if (null !== $limit_time) $this->set_Time_Limit($limit_time);
  }
  
  public function set_SMTP_Server_Host($host)
  {
    if (strlen($host) <= 0) {
      trigger_error('Bad host string, setting fault!' , E_USER_WARNING );
      return false;
    }
   
    if(ereg('^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$', $host, $regs)) {
      for($i = 1 ; $i <= 4 ; $i ++)
      {
        if((int)$regs[$i] > 255 && (int)$regs[$i] < 0) {
          trigger_error('Bad host string, setting fault!' , E_USER_WARNING );
          return false;
        }
      }
    }
   
    $this->SMTP_Server_Host = $host;
  }
  
  public function set_SMTP_Server_Port($port)
  {
    if(!is_int($port) || $port > 65535 || $port < 0) {
      trigger_error('Bad port string, setting fault!', E_USER_WARNING );
      return false;
    }
   
    $this->SMTP_Server_Port = $port;
  }
  
  public function set_User($user)
  {
    if (strlen($user) <= 0) {
      trigger_error('user is empty, setting fault!', E_USER_WARNING);
      return false;
    }
    $this->User = base64_encode($user);
  }
  
  public function set_Password($pass)
  {
    if (strlen($pass) <= 0) {
      trigger_error('Password is empty, setting fault!', E_USER_WARNING);
      return false;
    }
    $this->Password = base64_encode($pass);
  }
  
  public function set_Time_Limit($time)
  {
    ini_set('max_execution_time', $time);
  }
  
  protected function _socket_init()
  {
    $this->Socket_Resource = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    if ($this->Socket_Resource === false) {
      trigger_error('socket init fault! reason:' . socket_strerror(socket_last_error()), E_USER_WARNING );
      return false;
    }
    return true;
  }
  
  protected function _socket_connect()
  {
    if(!ereg('^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$' , $this->SMTP_Server_Host)) {
      $ip = gethostbyname($this->SMTP_Server_Host);
      if ($ip == $this->SMTP_Server_Host) {
        trigger_error('Parse host name fault!, Connect fault!' , E_USER_WARNING );
        return false;
      }
      $this->SMTP_Server_Host = $ip;
    }
    $result = socket_connect($this->Socket_Resource, $this->SMTP_Server_Host, $this->SMTP_Server_Port);
    if ($result === false) {
      trigger_error('socket connect fault! reason:' . socket_strerror(socket_last_error($this->Socket_Resource)),
                    E_USER_WARNING );
      return false;
    }
    return true;
  }
  
  protected function _socket_write($buffer)
  {
    $result = socket_write($this->Socket_Resource, $buffer, strlen($buffer));
    if (false === $result) trigger_error('socket write fault! reason:' .
                                         socket_strerror(socket_last_error($this->Socket_Resource)), E_USER_WARNING );
    return $result;
  }
  
  protected function _socket_read()
  {
    $response = '';
    while ($tmp_str = socket_read($this->Socket_Resource, 1448))
    {
      if (false === $tmp_str) {
         trigger_error('socket read fault! reason:' . socket_strerror(socket_last_error($this->Socket_Resource)),
                       E_USER_WARNING );
         return $tmp_str;
      }
      $response .= $tmp_str;
      if (preg_match("/[0-9][0-9][0-9]\s.+/", $response)) break;
    }
    return $response;
  }
  
  protected function _log_server_response($response)
  {
    $tmp_array = explode("\r\n", $response);
    $response_code = '';
    $response_test = array();
    $code_1bit = '';
    $code_2bit = '';
    $code_3bit = '';
   
    foreach ($tmp_array as $tmp_str)
    {
      if (preg_match("/^([0-9])([0-9])([0-9])-(.+)/", $tmp_str, $matches)) {
        if ('' === $response_code) {
          $response_code = $matches[1] . $matches[2] . $matches[3];
          $code_1bit = $matches[1];
          $code_2bit = $matches[2];
          $code_3bit = $matches[3];
        } else {
          if ($response_code !== $matches[1] . $matches[2] . $matches[3]) continue;
        }
        $response_test[] = $matches[4];
      } else if (preg_match("/^([0-9])([0-9])([0-9])\s(.+)/", $tmp_str, $matches)) {
        if ('' === $response_code) {
          $response_code = $matches[1] . $matches[2] . $matches[3];
          $code_1bit = $matches[1];
          $code_2bit = $matches[2];
          $code_3bit = $matches[3];
        } else {
          if ($response_code !== $matches[1] . $matches[2] . $matches[3]) continue;
        }
        $response_test[] = $matches[4];
        break;
      } else {
        continue;
      }
    }
    if ('' !== $response_test && '' !== $code_1bit && '' !== $code_2bit && '' !== $code_3bit ) {
      $tmp_array = array('code_1' => $code_1bit, 'code_2' => $code_2bit, 'code_3' => $code_3bit, 'response' => $response_test);
      $this->Server_Response[] = $tmp_array;
      return true;
    } else {
      trigger_error('Server Response Format Error, log fault!', E_USER_WARNING);
      return false;
    }
  }
  public function _send_command($command)
  {
    $command .= "\r\n";
    if (strlen($command) > 512) {
      trigger_error('Command String Is Too Lang, command fault!', E_USER_WARNING);
      return false;
    }
   
    $is_success = $this->_socket_write($command);
    if (!$is_success) return false;
    usleep(250000);
    $response = $this->_socket_read();
    $is_success = $this->_log_server_response($response);
    if ($is_success) return true;
    return false;
  }
  
  public function Connect_SMTP_Server()
  {
    if (SMTP_Controller::DISCONNECTED !== $this->SMTP_Server_State) {
      trigger_error('SMTP Server State not is Disconnected, connect fault!', E_USER_WARNING);
      return false;
    }
    if (strlen($this->SMTP_Server_Host) <= 0) {
      trigger_error('SMTP Server Host is empty, connect fault!', E_USER_WARNING);
      return false;
    }
    if (!$this->_socket_init())    return false;
    if (!$this->_socket_connect()) return false;
   
    $response = $this->_socket_read();
    $is_success = $this->_log_server_response($response);
    $last_response = end($this->Server_Response);
    if ($is_success && ('2' == $last_response['code_1'] || '220' == $last_response['code_1'] .
                                                                    $last_response['code_2'] .
                                                                    $last_response['code_3'])) {
      if (strlen($this->User) <= 0 || strlen($this->Password) <= 0) {
        $this->SMTP_Server_State = SMTP_Controller::TRANSACTION;
      } else {
        $this->SMTP_Server_State = SMTP_Controller::AUTHORIZATION;
      }
      return true;
    }
    return false;
  }
  public function Login_SMTP_Server()
  {
    if (SMTP_Controller::AUTHORIZATION !== $this->SMTP_Server_State) {
      trigger_error('SMTP Server State not is Authorization, login fault!', E_USER_WARNING);
      return false;
    }
    if (strlen($this->User) <= 0 || strlen($this->Password) <= 0) {
      trigger_error('User is empty or Password is empty, login fault!', E_USER_WARNING);
      return false;
    }
    $is_success = $this->_send_command('AUTH LOGIN');
    if (!$is_success) {
      trigger_error('Send Command Fault(AUTH LOGIN), login fault!', E_USER_WARNING);
      return false;
    }
    $last_response = end($this->Server_Response);
    if ('3' != $last_response['code_1'] && '334' != $last_response['code_1'] . $last_response['code_2'] .
                                                                               $last_response['code_3']) {
      trigger_error('Server Respone Error Code(AUTH LOGIN), login fault!', E_USER_WARNING);
      return false;
    }
    $is_success = $this->_send_command($this->User);
    if (!$is_success) {
      trigger_error('Send Command Fault(USER), login fault!', E_USER_WARNING);
      return false;
    }
    $last_response = end($this->Server_Response);
    if ('3' != $last_response['code_1'] && '334' != $last_response['code_1'] . $last_response['code_2'] .
                                                                               $last_response['code_3']) {
      trigger_error('Server Respone Error Code(USER), login fault!', E_USER_WARNING);
      return false;
    }
   
    $is_success = $this->_send_command($this->Password);
    if (!$is_success) {
      trigger_error('Send Command Fault(PASSWORD), login fault!', E_USER_WARNING);
      return false;
    }
    $last_response = end($this->Server_Response);
    if ('2' != $last_response['code_1'] && '235' != $last_response['code_1'] . $last_response['code_2'] .
                                                                               $last_response['code_3']) {
      trigger_error('Server Respone Error Code(PASSWORD), login fault!', E_USER_WARNING);
      return false;
    }
    $this->SMTP_Server_State = SMTP_Controller::TRANSACTION;
    return true;
  }
  
  public function Send_SMTP_EHLO($identity = 'MMOneDayPost')
  {
    $is_success = $this->_send_command("EHLO $identity");
    if (!$is_success) {
      trigger_error('Send Command Fault(EHLO), send fault!', E_USER_WARNING);
      return false;
    }
    $last_response = end($this->Server_Response);
    if ('2' != $last_response['code_1'] && '250' != $last_response['code_1'] . $last_response['code_2'] .
                                                                               $last_response['code_3']) {
      $is_success = $this->_send_command("HELO $identity");
      if (!$is_success) {
        trigger_error('Send Command Fault(HELO), send fault!', E_USER_WARNING);
        return false;
      }
      $last_response = end($this->Server_Response);
      if ('2' != $last_response['code_1'] && '250' != $last_response['code_1'] . $last_response['code_2'] .
                                                                                 $last_response['code_3']) {
        trigger_error('Server Respone Error Code(HELO), send fault!', E_USER_WARNING);
        return false;
      }
      return true;
    } else {
      $this->has_SMTP_Server_Extend = true;
    }
    foreach ($last_response['response'] as $tmp_str)
    {
      if (false === $this->has_SMTP_Server_ETRN && preg_match("/^etrn$/i", $tmp_str)) {
        $this->has_SMTP_Server_ETRN = true;
        continue;
      }
      if (false === $this->has_SMTP_Server_8BITMIME && preg_match("/^8bitmime$/i", $tmp_str)) {
        $this->has_SMTP_Server_8BITMIME = true;
        continue;  
      }
      if (null === $this->SMTP_Server_Accept_Max_Size && preg_match("/^size\s([0-9]+)$/i", $tmp_str, $matches)) {
        $this->SMTP_Server_Accept_Max_Size = $matches[1];
        continue;  
      }
    }
    return true;
  }
  
  public function Send_SMTP_QUIT()
  {
    $this->_send_command("QUIT");
    $last_response = end($this->Server_Response);
    if ('2' != $last_response['code_1'] && '210' != $last_response['code_1'] . $last_response['code_2'] .
                                                                               $last_response['code_3']) {
      trigger_error('Server Respone Error Code(QUIT), send fault!', E_USER_WARNING);
      return false;
    }
    return true;
  }
  
  public function Send_SMTP_HELP($command)
  {
    $this->_send_command("HELP $command");
    $last_response = end($this->Server_Response);
    if ('2' != $last_response['code_1'] && '214' != $last_response['code_1'] . $last_response['code_2'] .
                                                                               $last_response['code_3']) {
      trigger_error('Server Respone Error Code(HELP), send fault!', E_USER_WARNING);
      return false;
    }
    return true;
  }
  
  public function Send_SMTP_VRFY($mailbox)
  {
    $this->_send_command("VRFY $mailbox");
    $last_response = end($this->Server_Response);
    if ('2' != $last_response['code_1'] && '250' != $last_response['code_1'] . $last_response['code_2'] .
                                                                               $last_response['code_3']) {
      trigger_error('Server Respone Error Code(VRFY), send fault!', E_USER_WARNING);
      return false;
    }
    return true;
  }
  
  public function Send_SMTP_NOOP()
  {
    $this->_send_command("NOOP");
    $last_response = end($this->Server_Response);
    if ('2' != $last_response['code_1'] && '250' != $last_response['code_1'] . $last_response['code_2'] .
                                                                               $last_response['code_3']) {
      trigger_error('Server Respone Error Code(NOOP), send fault!', E_USER_WARNING);
      return false;
    }
    return true;
  }
  
  public function Send_SMTP_MAIL($email, $param = null)
  {
    if (SMTP_Controller::TRANSACTION !== $this->SMTP_Server_State) {
      trigger_error('Server State not is Transaction, send command(MAIL) fault!', E_USER_WARNING);
      return false;
    }
    $email = trim($email);
    $atom = '[-a-z0-9!#$%&*+/=?^_`{|}~]';
    $domain = '([a-z0-9]([-a-z0-9]*[a-z0-9]+)?)';
    $regex = '^' . $atom . '+' . '(\.' . $atom . '+)*'. '@' . '(' . $domain . '{1,63}\.)+' . $domain . '{2,63}' . '$';
    if (!eregi($regex, $email) || strlen($email) > 256) {
      trigger_error('E-Mail Address Error, send command(MAIL) fault!', E_USER_WARNING);
      return false;
    }
    $param_str = '';
    if (!empty($param) && is_array($param) && true === $this->has_SMTP_Server_Extend) {
      foreach ($param as $key => $value)
      {
        $param_str .= " $key=$value";
      }
    }
   
    $this->_send_command("MAIL FROM:<$email>$param_str");
    $last_response = end($this->Server_Response);
    if ('2' != $last_response['code_1'] && '250' != $last_response['code_1'] . $last_response['code_2'] .
                                                                               $last_response['code_3']) {
      trigger_error('Server Respone Error Code(MAIL), send fault!', E_USER_WARNING);
      return false;
    }
    return true;
  }
   
  public function Send_SMTP_RCPT($email, $param = null)
  {
    if (SMTP_Controller::TRANSACTION !== $this->SMTP_Server_State) {
      trigger_error('Server State not is Transaction, send command(RCPT) fault!', E_USER_WARNING);
      return false;
    }
    $email = trim($email);
    $atom = '[-a-z0-9!#$%&*+/=?^_`{|}~]';
    $domain = '([a-z0-9]([-a-z0-9]*[a-z0-9]+)?)';
    $regex = '^' . $atom . '+' . '(\.' . $atom . '+)*'. '@' . '(' . $domain . '{1,63}\.)+' . $domain . '{2,63}' . '$';
    if (!eregi($regex, $email) || strlen($email) > 256) {
      trigger_error('E-Mail Address Error, send command(RCPT) fault!', E_USER_WARNING);
      return false;
    }
    $param_str = '';
    if (!empty($param) && is_array($param) && true === $this->has_SMTP_Server_Extend) {
      foreach ($param as $key => $value)
      {
        $param_str .= " $key=$value";
      }
    }
   
    $this->_send_command("RCPT TO:<$email>$param_str");
    $last_response = end($this->Server_Response);
    if ('2' != $last_response['code_1'] && '250' != $last_response['code_1'] . $last_response['code_2'] .
                                                                               $last_response['code_3']) {
      trigger_error('Server Respone Error Code(RCPT), send fault!', E_USER_WARNING);
      return false;
    }
    return true;
  }
  
  public function Send_SMTP_DATA($mail)
  {
    $tmp_array = &preg_split ("/\r\n|\n|\n\r\n\r/", $mail);
    foreach ($tmp_array as $key => $value)
    {
      if (strlen($tmp_array[$key]) > 998) {
        trigger_error('Mail String Error, One Line Size Larger Than 998, send command(DATA) fault!', E_USER_WARNING);
        return false;
      }
    }
    if (false === $this->has_SMTP_Server_8BITMIME) {
      $tmp_mail_size = strlen($mail);
      for ($i = 0; $i < $tmp_mail_size; $i ++)
      {
        if (ord($mail[$i]) > 127) {
          trigger_error('Mail String Error, Server Not Support 8bitmime, send command(DATA) fault!', E_USER_WARNING);
          return false;
        }
      }
    }
    if (null !== $this->SMTP_Server_Accept_Max_Size && $tmp_mail_size > $this->SMTP_Server_Accept_Max_Size) {
      trigger_error('Mail String Error, Size Larger Than Server Max Size, send command(DATA) fault!', E_USER_WARNING);
      return false;
    }
    $this->_send_command("DATA");
    $last_response = end($this->Server_Response);
    if ('3' != $last_response['code_1'] && '354' != $last_response['code_1'] . $last_response['code_2'] .
                                                                               $last_response['code_3']) {
      trigger_error('Server Respone Error Code(DATA), send fault!', E_USER_WARNING);
      return false;
    }
    $this->_send_command("$mail\r\n.");
    $last_response = end($this->Server_Response);
    if ('2' != $last_response['code_1'] && '250' != $last_response['code_1'] . $last_response['code_2'] .
                                                                               $last_response['code_3']) {
      trigger_error('Server Respone Error Code(DATA), send fault!', E_USER_WARNING);
      return false;
    }
    return true;
  }
  
  public function Send_SMTP_REST()
  {
    $this->_send_command("RSET");
    $last_response = end($this->Server_Response);
    if ('2' != $last_response['code_1'] && '250' != $last_response['code_1'] . $last_response['code_2'] .
                                                                               $last_response['code_3']) {
      trigger_error('Server Respone Error Code(REST), send fault!', E_USER_WARNING);
      return false;
    }
    return true;
  }
  
  public function Send_SMTP_ETRN($domain)
  {
    if ($this->has_SMTP_Server_ETRN) {
      $command = "ETRN $domain";
    } else {
      $command = "TURN $domain";
    }
    $this->_send_command($command);
    $last_response = end($this->Server_Response);
    if ('2' != $last_response['code_1'] && '250' != $last_response['code_1'] . $last_response['code_2'] .
                                                                               $last_response['code_3']) {
      trigger_error('Server Respone Error Code(ETRN), send fault!', E_USER_WARNING);
      return false;
    }
    return true;
  }
  
}

以下是例子:
[php]
require_once('SMTP_Controller.php');
$aa = new SMTP_Controller('xxx.xxx.xxx', 25, 'user', 'password');
$aa->Connect_SMTP_Server();
$aa->Login_SMTP_Server();
$aa->Send_SMTP_EHLO();
//$aa->Send_SMTP_HELP('rcpt');
//$aa->Send_SMTP_VRFY('manhong');
//$aa->Send_SMTP_NOOP();
$aa->Send_SMTP_MAIL('[email]manhong@xxx.xxx.xxx[/email]');
$aa->Send_SMTP_RCPT('[email]manhong2@xxx.xxx.xxx[/email]');
//$aa->Send_SMTP_REST();
//$aa->Send_SMTP_ETRN();
$aa->Send_SMTP_DATA("to:manhong@xxx.xxx.xxx\r\nfrom:manhong2@xxx.xxx.xxx\r\n\r\nhi~~~~~~~~~~~~~~~~~~.\r\n.\r\n");
$aa->Send_SMTP_QUIT();
[/php]

maxyma2008-6-5 06:21 AM
呵呵 此牛人做过邮件开发 帮顶~


查看完整版本: 一个smtp服务器的交互类


Powered by Discuz! Archiver 6.1.0  © 2001-2006 Comsenz Inc.
Processed in 0.007306 second(s), 2 queries