<?php
/*******************************************************************
 * 版权协议：2009-2019
 * 版权所有: PHP-北京金南曦网络技术有限公司旗下PHPWMS，PHP商城系统技术支持中心http://www.php188.net，并保留所有权利。 
* PHP商城系统网址: http://www.php188.com
 * PHPWMS系统网址：http://www.phpwms.com
 * 销售电话：010-87875088
 * 销售电话：010-87875188 
*------------------------------------------------------------------
 * 这不是一个完全免费软件！您只能在不用于商业目的的前提下对程序代码进
 * 行修改和使用；不允许对程序代码以任何形式任何目的的再发布。
 *------------------------------------------------------------------
 * 文件名称：cls.smtp.php
 * 摘    要：smtp邮件发送类 for PHP5
 * 适用范围：PHPWMS 1.0
 * 版    本：1.0
 *------------------------------------------------------------------
 * Script Written By phpwms项目组
 * 最后更新： 2009-09-24 phpwms 由PHP金南曦网络技术有限公司整理发布
 *******************************************************************/

	!defined('IN_SYS') and die('Hacking attempt');

	class smtp {
		# 常规定义
		private $_host;                                   //smtp服务器地址
		private $_auth;                                   //是否需要身份验证
		private $_user;                                   //smtp帐号
		private $_pass;                                   //smtp密码
		private $_debug = false;                          //是否显示调试信息
		private $_magicFile;                              //mime文件所在路径
		private $_Subject;                                //邮件主题
		private $_From;                                   //发送人邮箱地址
		private $_To = array();                           //收件人
		private $_Cc = array();                           //抄送
		private $_Bcc = array();                          //暗送
		private $_attachment = array();                   //附件
		private $_mailtype = 'text';                      //邮件类型('text':纯文本,'html':HTML邮件)
		private $_charset = 'gbk';						  //邮件编码
		private $_mimemail;                               //邮件内容
		private $_socket;                                 //smtp连接
		private $_port = 25;                              //smtp端口
		private $_timeout = 30;                           //超时时间
		# 安全选项
		private $_script = false;						  //是否禁止邮件内容中使用脚本
		private $_iframe = false;						  //是否禁止邮件内容中使用框架
		private $_style  = false;						  //是否禁止邮件内容中使用样式
		
		//构造函数
		public function __construct($host, $port = 25, $auth = false, $user = '', $pass = '') {
			$this -> _host = $host;
			$this -> _auth = $auth;
			$this -> _user = $user;
			$this -> _pass = $pass;
			$this -> _port = $port;
		}
		
		//设置是否显示调试信息
		public function setDebug($boolDebug) {
			$this -> _debug = $boolDebug;
		}
		
		//设置mime文件所在路径
		public function setMagicFile($filename) {
			$this -> _magicFile = $filename;
		}
		
		//设置邮件主题
		public function setSubject($str) {
			$this -> _Subject = $str;
		}
		
		//设置发件人
		public function setFrom($email) {
			$email = $this -> stripComment($email);
			$this -> _From = $email;
		}
		
		//添加收件人
		public function addTo($email) {
			$email = $this -> stripComment($email);
			$this -> _To[] = $email;
		}
		
		//添加抄送人
		public function addCc($email) {
			$email = $this -> stripComment($email);
			$this -> _Cc[] = $email;
		}
		
		//添加暗送人
		public function addBcc($email) {
			$email = $this -> stripComment($email);
			$this -> _Bcc[] = $email;
		}
		
		//添加附件
		public function addAttachment($filename) {
			if(is_file($filename)) $this -> _attachment[] = $filename;
		}
		
		//设置邮件类型
		public function setMailType($type) {
			$this -> _mailtype = $type;
		}
		
		//设置邮件编码
		public function setCharset($strCharset) {
			$this -> _charset = $strCharset;
		}
		
		//设置邮件内容
		public function setMimeMail($str) {
			$boundary = uniqid('');
			
			$this -> _mimemail = "From: " . $this -> _From . "\r\n";
			$this -> _mimemail .= "Reply-To: " . $this -> _From . "\r\n";
			$this -> _mimemail .= "To: " . implode(",", $this -> _To) . "\r\n";
			
			if(count($this -> _Cc)) $this -> _mimemail .= "Cc: " . implode(",", $this -> _Cc) . "\r\n";
			if(count($this -> _Bcc)) $this -> _mimemail .= "Bcc: " . implode(",", $this -> _Bcc) . "\r\n";
			
			$this -> _mimemail .= "Subject: " . $this -> _Subject . "\r\n";
			$this -> _mimemail .= "Message-ID: <" . time() .  "." . $this -> _From . ">\r\n";
			$this -> _mimemail .= "Date: " . date("r") . "\r\n";
			$this -> _mimemail .= "MIME-Version: 1.0\r\n";
			$this -> _mimemail .= "Content-type: multipart/mixed; boundary=\"" . $boundary . "\"\r\n\r\n";
			$this -> _mimemail .= "--" . $boundary . "\r\n";
			
			if($this -> _mailtype == 'text') {
				$this -> _mimemail .= "Content-type: text/plain; charset=\"" . $this -> _charset . "\"\r\n\r\n";
			}
			else if($this -> _mailtype == 'html') {
				$this -> _mimemail .= "Content-type: text/html; charset=\"" . $this -> _charset . "\"\r\n\r\n";
			}
			
			if (strtolower($this -> _mailtype) == 'text') {
				$this -> _mimemail .= $str . "\r\n\r\n";
			} else {
				$this -> _mimemail .= $this -> html($str) . "\r\n\r\n";
			}			
			
			if(count($this -> _attachment)) {
				$finfo = new finfo(FILEINFO_MIME, $this -> _magicFile);
				foreach($this -> _attachment as $k => $filename) {
					$f = @fopen($filename, 'r');
					if(!$f) continue;
					
					$mimetype = $finfo -> file(realpath($filename));
					$attachment = @fread($f, filesize($filename));
					$attachment = base64_encode($attachment);
					$attachment = chunk_split($attachment);
					
					$this -> _mimemail .= "--" . $boundary . "\r\n";
					$this -> _mimemail .= "Content-type: " . $mimetype . "; name=" . basename($filename) . "\r\n";
					$this -> _mimemail .= "Content-disposition: attachment; filename=" . basename($filename) . "\r\n";
					$this -> _mimemail .= "Content-transfer-encoding: base64\r\n\r\n";
					$this -> _mimemail .= $attachment . "\r\n\r\n";
					
					unset($f);
					unset($mimetype);
					unset($attachment);
				}
			}
			
			$this -> _mimemail .= "--" . $boundary . "--";
		}
		
		public function send() {
			$arrToEmail = $this -> _To;
			if(count($this -> _Cc)) $arrToEmail = array_merge($arrToEmail, $this -> _Cc);
			if(count($this -> _Bcc)) $arrToEmail = array_merge($arrToEmail, $this -> _Bcc);
			
			$flag = $this -> connect();
			if (!$flag) { # 连接失败
				$this -> disconnect();
				return '000';
			}

			$this -> sendCMD('HELO localhost');
			$flag = $this -> smtpOK();
			if (!$flag) { # 发送命令失败
				$this -> disconnect();
				return '001';
			}

			
			if($this -> _auth) {
				$this -> sendCMD('AUTH LOGIN ' . base64_encode($this -> _user));
				$flag = $this -> smtpOK();
				if (!$flag) { # 认证失败
					$this -> disconnect();
					return '002';
				}
				$this -> sendCMD(base64_encode($this -> _pass));
				$flag = $this -> smtpOK();
				if (!$flag) { # 认证成功但验证密码失败
					$this -> disconnect();
					return '003';
				}
			}

			$this -> sendCMD('MAIL FROM:<' . $this -> _From . '>');
			$this -> smtpOK();
			
			$i = 0;
			foreach($arrToEmail as $k => $toEmail) {
				$this -> sendCMD('RCPT TO:<' . $toEmail . '>');
				$this -> smtpOK();
				$i += 1;
			}
			
			$this -> sendCMD('DATA');
			$this -> smtpOK();
			$this -> sendCMD($this -> _mimemail);
			$this -> smtpOK();
			
			$this -> sendCMD('.');
			$flag = $this -> smtpOK();
			$this -> disconnect();
			if ($flag) {
				return '11'.$i;
			} else {
				return '01'.$i;
			}
		}
		
		//连接smtp服务器
		private function connect() {
			$fp = @fsockopen($this -> _host, $this -> _port, $errno, $errstr, $this -> _timeout);
			
			if(!$fp) {
				if($this -> _debug) $this -> showMessage('错误:无法与smtp服务器建立连接！');
				return false;
			} else {
				$this -> _socket = $fp;
				if($this -> _debug) $this -> showMessage('正在与smtp服务器建立连接...成功！');
				return true;
			}
		}
		
		//关闭smtp服务器连接
		private function disconnect() {
			$this -> sendCMD('QUIT');
			@fclose($this -> _socket);
			$this -> _socket = null;
			if($this -> _debug) $this -> showMessage('断开与smtp服务器的连接');
		}
		
		//显示信息
		private function showMessage($msg) {
			echo "[" . date("H:i") . "]" . $msg . "<br/>";
		}
		
		//发送指令
		private function sendCMD($cmd) {
			@fputs($this -> _socket, $cmd . "\r\n");
			if($this -> _debug) $this -> showMessage($cmd);
		}
		
		//判断指令是否成功
		private function smtpOK() {
			$res = str_replace("\r\n", "", @fgets($this -> _socket, 512));
			
			if(ereg("^[23]", $res)) {
				if($this -> _debug) $this -> showMessage('请求成功！');
				return true;
			} else {
				if($this -> _debug) $this -> showMessage('错误:服务器返回信息<' . $res . '>');
				$this -> disconnect();
				return false;
			}
		}
		
		//过滤邮箱地址中的非法字符
		private function stripComment($email) {
			$comment = "\([^()]*\)";
			
			while(ereg($comment, $email)) {
				$email = ereg_replace($comment, "", $email);
			}
			
			$email = ereg_replace("([ \t\r\n])+", "", $email);
			$email = ereg_replace("^.*<(.+)>.*$", "\1", $email);
			
			return $email;
		}

		//过滤邮箱内容中的非法字符
		private function html($msg) {
			if(is_array($msg)) {
				foreach($msg AS $key=>$value) {
					$msg[$key] = $this -> html($value);
				}
			} else {
				$msg = trim($msg);
				$msg = stripslashes($msg);
				if(!$this -> _script) {
					$msg = preg_replace("/<script(.*)<\/script>/isU","",$msg);
				}
				if(!$this -> _iframe) {
					$msg = preg_replace("/<frame(.*)>/isU","",$msg);
					$msg = preg_replace("/<\/fram(.*)>/isU","",$msg);
					$msg = preg_replace("/<iframe(.*)>/isU","",$msg);
					$msg = preg_replace("/<\/ifram(.*)>/isU","",$msg);
				}
				if(!$this -> _style) {
					$msg = preg_replace("/<style(.*)<\/style>/isU","",$msg);
				}
				#[超链接在新窗口打开]
				$msg = preg_replace("/<a(.*)target=[ |'|\"](.*)[ |'|\"](.*)>/isU","<a\\1 \\3>",$msg);
				$msg = preg_replace("/<a(.*)>/isU","<a\\1 target='_blank'>",$msg);

				!get_magic_quotes_gpc() and $msg = addslashes($msg);
			}
			return $msg;
		}
	}
?>