Mail.php 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. <?php
  2. /**
  3. * 邮件帮助类
  4. */
  5. namespace app\common\library;
  6. use PHPMailer\PHPMailer;
  7. use think\Cache;
  8. use think\Env;
  9. class Mail
  10. {
  11. protected $_brand_name = BRAND_NAME; // 网站名称
  12. protected $_website = WEBSITE; // 站点地址
  13. protected $_phpmailer = null; // 对象实例
  14. // protected $_preg_mail = '/^(\w)+(\.\-\w+)*@(\w)+((\.\w+)+)$/i'; // 邮箱正则
  15. protected $_preg_mail = '/^[a-z0-9]+([._-][a-z0-9]+)*@([0-9a-z]+\.[a-z]{2,14}(\.[a-z]{2})?)$/i'; // 邮箱正则
  16. protected $_cache_key = null; // redis缓存中的key
  17. protected $_now_time = NOW_TIMESTAMP; // 当前时间
  18. protected $_redis = null; // redis对象实例
  19. protected $_last_time = null;
  20. protected $_expire_time = 1800; // 邮件验证过期时间
  21. protected $_username = null; // 玩家账号
  22. protected $_code = null; // 验证码
  23. protected $_mail = null; // 发送的邮箱
  24. protected $_is_error = false;
  25. protected $_error_msg = null;
  26. protected $_status = false;
  27. protected $_cache_key_prefix = 'wl_game:mail_'; // key前缀
  28. protected $_url = null; // 邮件中的回跳url
  29. protected $_template = '';
  30. protected $_interval = 60; // 发送间隔
  31. protected $_cache_mail_key = null; // redis缓存中的key 发送验证码用到
  32. // 找回密码邮件内容模板
  33. protected $_template1 = <<<EOF
  34. <div style='width:680px;padding:0 10px;margin:0 auto;'>
  35. <div style='line-height:1.5;font-size:14px;margin-bottom:25px;color:#4d4d4d;'>
  36. <strong style='display:block;margin-bottom:15px;'>亲爱的会员:%username% 您好!</strong>
  37. <p>您使用了本站提供的邮箱验证功能,如果您确认此功能是您启用的,请点击下面的链接,<br>该链接在30分钟内有效,请在有效时间内操作:
  38. </p>
  39. </div>
  40. <div style='margin-bottom:30px;'><strong style='display:block;margin-bottom:20px;font-size:14px;'>
  41. <a target='_blank' style='color:#f60;' href='%url%'>确认找回密码</a></strong>
  42. <p style='color:#666;'><small style='display:block;font-size:12px;margin-bottom:5px;'>如果上述文字点击无效,请把下面网页地址复制到浏览器地址栏中打开:
  43. </small><span style='color:#666;'>%url%</span></p></div></div>
  44. <div style='padding:10px 10px 0;border-top:1px solid #ccc;color:#999;margin-bottom:20px;line-height:1.3em;font-size:12px;'>
  45. <p style='margin-bottom:15px;'>此为系统邮件,请勿回复<br/>请保管好您的邮箱,避免%BRAND_NAME%账户被他人盗用</p>
  46. <p>如有任何疑问,可查看 <a target='_blank' style='color:#666;text-decoration:none;' href='%WEBSITE%/xieyi.php'>%BRAND_NAME%相关规则</a>,
  47. <a target='_blank' style='color:#666;text-decoration:none;' href='%WEBSITE%'>访问%BRAND_NAME%</a><br/>
  48. Copyright © %YEAR% All Right Reserved</p>
  49. </div>
  50. EOF;
  51. // 验证邮箱邮件内容模板
  52. protected $_template2 = <<<EOF
  53. <div style='width:680px;padding:0 10px;margin:0 auto;'>
  54. <div style='line-height:1.5;font-size:14px;margin-bottom:25px;color:#4d4d4d;'>
  55. <strong style='display:block;margin-bottom:15px;'>亲爱的会员:%username% 您好!</strong>
  56. <p>您使用了本站提供的邮箱验证功能,如果您确认此功能是您启用的,请点击下面的链接,<br>该链接在30分钟内有效,请在有效时间内操作:
  57. </p>
  58. </div>
  59. <div style='margin-bottom:30px;'><strong style='display:block;margin-bottom:20px;font-size:14px;'>
  60. <a target='_blank' style='color:#f60;' href='%url%'>确认验证邮箱</a></strong>
  61. <p style='color:#666;'><small style='display:block;font-size:12px;margin-bottom:5px;'>如果上述文字点击无效,请把下面网页地址复制到浏览器地址栏中打开:
  62. </small><span style='color:#666;'>%url%</span></p></div></div>
  63. <div style='padding:10px 10px 0;border-top:1px solid #ccc;color:#999;margin-bottom:20px;line-height:1.3em;font-size:12px;'>
  64. <p style='margin-bottom:15px;'>此为系统邮件,请勿回复<br/>请保管好您的邮箱,避免%BRAND_NAME%账户被他人盗用</p>
  65. <p>如有任何疑问,可查看 <a target='_blank' style='color:#666;text-decoration:none;' href='%WEBSITE%/xieyi.php'>%BRAND_NAME%相关规则</a>,
  66. <a target='_blank' style='color:#666;text-decoration:none;' href='%WEBSITE%'>访问%BRAND_NAME%</a><br/>
  67. Copyright © %YEAR% All Right Reserved</p>
  68. </div>
  69. EOF;
  70. // 申述编码内容模板
  71. protected $_template3 = <<<EOF
  72. <div style='width:680px;padding:0 10px;margin:0 auto;'>
  73. <div style='line-height:1.5;font-size:14px;margin-bottom:25px;color:#4d4d4d;'>
  74. <strong style='display:block;margin-bottom:15px;'>尊敬的麻花网络互娱用户,您好!</strong>
  75. <p>您正在进行麻花网络账号申述的<span color="red">联系方式验证</span>验证码为<span color="red">%code%</span>,此码<span color="red">30分钟内有效</span>。
  76. </p>
  77. </div>
  78. <div style='margin-bottom:30px;'>
  79. <p style='color:#666;'><small style='display:block;font-size:12px;margin-bottom:5px;'>若非本人操作,请忽略此邮件。如有任何疑问可查看帮助中心,此邮件为系统自动发送,请勿回复。
  80. </small><span style='color:#666;'></span></p></div></div>
  81. EOF;
  82. // 申述验证码邮件内容模板
  83. protected $_template4 = <<<EOF
  84. <div style='width:680px;padding:0 10px;margin:0 auto;'>
  85. <div style='line-height:1.5;font-size:14px;margin-bottom:25px;color:#4d4d4d;'>
  86. <strong style='display:block;margin-bottom:15px;'>尊敬的麻花网络用户,您好!</strong>
  87. <p>您的帐号[%username%]的申诉已受理,申诉编码为[%code%],请妥善保管此申诉编码,以备后续使用。申诉结果将在%day%个工作日内发送至您的邮箱,结果未给出前请勿重复申诉!</p>
  88. <p>您可以随时访问客服中心内的申诉查询[http://www.weilongwl.com/kefu/sscx/]了解您账号当前的申诉处理进度。</p>
  89. </div>
  90. <div style='margin-bottom:30px;'>
  91. <p style='color:#666;'><small style='display:block;font-size:12px;margin-bottom:5px;'>如有任何问题请联系麻花网络客服。
  92. </small><span style='color:#666;'></span></p>
  93. <p style='color:#666;'><small style='display:block;font-size:12px;margin-bottom:5px;'>客服QQ:%qq%;
  94. </small><span style='color:#666;'></span></p>
  95. <p style='color:#666;'><small style='display:block;font-size:12px;margin-bottom:5px;'>微信公众号:%wechat%;
  96. </small><span style='color:#666;'></span></p>
  97. <p style='color:#666;'><small style='display:block;font-size:12px;margin-bottom:5px;'>客服电话:%servicephone%。
  98. </small><span style='color:#666;'></span></p>
  99. <p style='color:#666;'><small style='display:block;font-size:12px;margin-bottom:5px;'>工作时间:%servicetime%。
  100. </small><span style='color:#666;'></span></p>
  101. </div></div>
  102. EOF;
  103. // 申述结果失败邮件内容模板
  104. protected $_template5 = <<<EOF
  105. <div style='width:680px;padding:0 10px;margin:0 auto;'>
  106. <div style='line-height:1.5;font-size:14px;margin-bottom:25px;color:#4d4d4d;'>
  107. <strong style='display:block;margin-bottom:15px;'>尊敬的麻花网络用户,您好!</strong>
  108. <p>很抱歉,您申诉的账号:[%username%]因提供的资料不完善而未通过,申诉编码为:[%code%]。</p>
  109. <p>建议您查看是否申诉错帐号。若帐号无误,建议您稍后重新进行申诉,并提供更为详情的信息。</p>
  110. </div>
  111. <div style='margin-bottom:30px;'>
  112. <p style='color:#666;'><small style='display:block;font-size:12px;margin-bottom:5px;'>如有任何问题请联系麻花网络客服。
  113. </small><span style='color:#666;'></span></p>
  114. <p style='color:#666;'><small style='display:block;font-size:12px;margin-bottom:5px;'>客服QQ:%qq%;
  115. </small><span style='color:#666;'></span></p>
  116. <p style='color:#666;'><small style='display:block;font-size:12px;margin-bottom:5px;'>微信公众号:%wechat%;
  117. </small><span style='color:#666;'></span></p>
  118. <p style='color:#666;'><small style='display:block;font-size:12px;margin-bottom:5px;'>客服电话:%servicephone%。
  119. </small><span style='color:#666;'></span></p>
  120. <p style='color:#666;'><small style='display:block;font-size:12px;margin-bottom:5px;'>工作时间:%servicetime%。
  121. </small><span style='color:#666;'></span></p>
  122. </div></div>
  123. EOF;
  124. // 申述结果成功邮件内容模板
  125. protected $_template6 = <<<EOF
  126. <div style='width:680px;padding:0 10px;margin:0 auto;'>
  127. <div style='line-height:1.5;font-size:14px;margin-bottom:25px;color:#4d4d4d;'>
  128. <strong style='display:block;margin-bottom:15px;'>尊敬的麻花网络用户,您好!</strong>
  129. <p>恭喜您,您申诉的账号:[%username%]的申诉已通过,申诉编码号为:[%code%], 成功凭证为:[%certificate%]。</p>
  130. <p>请进入,麻花网络客服中心内的“申诉查询”[http://www.weilongwl.com/kefu/sscx/],输入申诉编码和成功凭证后,即可重置密码。</p>
  131. </div>
  132. <div style='margin-bottom:30px;'>
  133. <span style='color:#666;'></span></p></div></div>
  134. EOF;
  135. // 忘记密码-邮箱验证身份
  136. protected $_template7 = <<<EOF
  137. <div style='width:680px;padding:0 10px;margin:0 auto;'>
  138. <div style='line-height:1.5;font-size:14px;margin-bottom:25px;color:#4d4d4d;'>
  139. <strong style='display:block;margin-bottom:15px;'>亲爱的麻花网络用户:<span style="font-size: 20px">%username%</span> 您好!</strong>
  140. <p>您正在找回密码,验证码:<span style="font-size: 20px;font-weight: bold;color: red">%code%</span>,验证码有效期为30分钟,请及时输入。
  141. </p>
  142. </div>
  143. <div style='margin-bottom:30px;'>
  144. <p style='color:#666;'><small style='display:block;font-size:12px;margin-bottom:5px;'> 为保证账号安全,请勿向任何人提供此验证码。
  145. </small><span style='color:#666;'></span></p></div></div>
  146. EOF;
  147. // 绑定手机-邮箱验证身份(没绑过手机)
  148. protected $_template8 = <<<EOF
  149. <div style='width:680px;padding:0 10px;margin:0 auto;'>
  150. <div style='line-height:1.5;font-size:14px;margin-bottom:25px;color:#4d4d4d;'>
  151. <strong style='display:block;margin-bottom:15px;'>亲爱的麻花网络用户:<span style="font-size: 20px">%username%</span> 您好!</strong>
  152. <p>您正在绑定手机,验证码:<span style="font-size: 20px;font-weight: bold;color: red">%code%</span>,验证码有效期为30分钟,请及时输入。
  153. </p>
  154. </div>
  155. <div style='margin-bottom:30px;'>
  156. <p style='color:#666;'><small style='display:block;font-size:12px;margin-bottom:5px;'> 为保证账号安全,请勿向任何人提供此验证码。
  157. </small><span style='color:#666;'></span></p></div></div>
  158. EOF;
  159. // 绑定邮箱--验证码
  160. protected $_template9 = <<<EOF
  161. <div style='width:680px;padding:0 10px;margin:0 auto;'>
  162. <div style='line-height:1.5;font-size:14px;margin-bottom:25px;color:#4d4d4d;'>
  163. <strong style='display:block;margin-bottom:15px;'>亲爱的麻花网络用户:<span style="font-size: 20px">%username%</span> 您好!</strong>
  164. <p>您正在绑定邮箱,验证码:<span style="font-size: 20px;font-weight: bold;color: red">%code%</span>,验证码有效期为30分钟,请及时输入。
  165. </p>
  166. </div>
  167. <div style='margin-bottom:30px;'>
  168. <p style='color:#666;'><small style='display:block;font-size:12px;margin-bottom:5px;'> 为保证账号安全,请勿向任何人提供此验证码。
  169. </small><span style='color:#666;'></span></p></div></div>
  170. EOF;
  171. // 账号申诉-邮件验证身份
  172. protected $_template10 = <<<EOF
  173. <div style='width:680px;padding:0 10px;margin:0 auto;'>
  174. <div style='line-height:1.5;font-size:14px;margin-bottom:25px;color:#4d4d4d;'>
  175. <strong style='display:block;margin-bottom:15px;'>亲爱的麻花网络用户:<span style="font-size: 20px">%username%</span> 您好!</strong>
  176. <p>您正在账号申诉,验证码:<span style="font-size: 20px;font-weight: bold;color: red">%code%</span>,有效期为30分钟,请及时输入。
  177. </p>
  178. </div>
  179. <div style='margin-bottom:30px;'>
  180. <p style='color:#666;'><small style='display:block;font-size:12px;margin-bottom:5px;'> 为保证账号安全,请勿向任何人提供此验证码。
  181. </small><span style='color:#666;'></span></p></div></div>
  182. EOF;
  183. // 绑定邮箱--验证邮箱
  184. protected $_template11 = <<<EOF
  185. <div style='width:680px;padding:0 10px;margin:0 auto;'>
  186. <div style='line-height:1.5;font-size:14px;margin-bottom:25px;color:#4d4d4d;'>
  187. <strong style='display:block;margin-bottom:15px;'>亲爱的麻花网络用户:<span style="font-size: 20px">%username%</span> 您好!</strong>
  188. <p>您正在换绑邮箱,验证码:<span style="font-size: 20px;font-weight: bold;color: red">%code%</span>,验证码有效期为30分钟,请及时输入。
  189. </p>
  190. </div>
  191. <div style='margin-bottom:30px;'>
  192. <p style='color:#666;'><small style='display:block;font-size:12px;margin-bottom:5px;'> 为保证账号安全,请勿向任何人提供此验证码。
  193. </small><span style='color:#666;'></span></p></div></div>
  194. EOF;
  195. // 绑定手机-邮箱验证身份(换绑手机)
  196. protected $_template12 = <<<EOF
  197. <div style='width:680px;padding:0 10px;margin:0 auto;'>
  198. <div style='line-height:1.5;font-size:14px;margin-bottom:25px;color:#4d4d4d;'>
  199. <strong style='display:block;margin-bottom:15px;'>亲爱的麻花网络用户:<span style="font-size: 20px">%username%</span> 您好!</strong>
  200. <p>您正在换绑手机,验证码:<span style="font-size: 20px;font-weight: bold;color: red">%code%</span>,验证码有效期为30分钟,请及时输入。
  201. </p>
  202. </div>
  203. <div style='margin-bottom:30px;'>
  204. <p style='color:#666;'><small style='display:block;font-size:12px;margin-bottom:5px;'> 为保证账号安全,请勿向任何人提供此验证码。
  205. </small><span style='color:#666;'></span></p></div></div>
  206. EOF;
  207. // 绑定邮箱--验证邮箱
  208. protected $_template15 = <<<EOF
  209. <div style='width:680px;padding:0 10px;margin:0 auto;'>
  210. <div style='line-height:1.5;font-size:14px;margin-bottom:25px;color:#4d4d4d;'>
  211. <strong style='display:block;margin-bottom:15px;'>亲爱的麻花网络用户:<span style="font-size: 20px">%username%</span> 您好!</strong>
  212. <p>您正在通过邮箱找回密码,验证码:<span style="font-size: 20px;font-weight: bold;color: red">%code%</span>,验证码有效期为30分钟,请及时输入。
  213. </p>
  214. </div>
  215. <div style='margin-bottom:30px;'>
  216. <p style='color:#666;'><small style='display:block;font-size:12px;margin-bottom:5px;'> 为保证账号安全,请勿向任何人提供此验证码。
  217. </small><span style='color:#666;'></span></p></div></div>
  218. EOF;
  219. public function __construct()
  220. {
  221. $this->_redis = Cache::store('redis');
  222. }
  223. /**
  224. * 发送找回密码邮件
  225. * @param string $username 玩家用户名
  226. * @param string $mail 邮箱地址
  227. */
  228. public function sendFindMail($username, $mail)
  229. {
  230. $this->_instantiate();
  231. $token = array('username' => $username, 'email' => $mail, 'time' => $this->_now_time);
  232. $token = json_encode($token);
  233. $token = auth_code($token, 'ENCODE', Env::get('auth_key'));
  234. $token = urlencode($token);
  235. $this->_url = $this->_website . "/user/findpwd.php?u={$token}";
  236. $this->_template = $this->_template1;
  237. $this->_keywordReplace($username, $this->_url);
  238. $this->_phpmailer->AddAddress($mail, $username); // 收件人邮箱和姓名
  239. $this->_phpmailer->Body = $this->_template;
  240. $result = $this->_phpmailer->Send();
  241. if (!$result) {
  242. $this->_is_error = true;
  243. $this->_error_msg = $this->_phpmailer->ErrorInfo;
  244. }
  245. if (!$this->_is_error) {
  246. $this->_insertLog($mail, $this->_template, 'mail');
  247. $this->_status = true;
  248. }
  249. return array('status' => $this->_status, 'msg' => $this->_status ? '' : $this->_error_msg);
  250. }
  251. /**
  252. * 发送验证邮件(带url供用户直接跳转)
  253. * @param string $username 玩家用户名
  254. * @param string $mail 要送到的邮箱地址
  255. * @param string $url 邮件中的回跳链接,不需要传入后面的t参数,例如 http://www.weilongwl.com/user/mail.php?action=xxx
  256. */
  257. public function sendCheckMail($username, $mail, $url)
  258. {
  259. $this->_username = $username;
  260. $this->_instantiate();
  261. $key = $this->_makeKey();
  262. if (false === strstr($url, '?')) {
  263. $this->_url = $url . '?t=' . $key;
  264. } else {
  265. $this->_url = $url . '&t=' . $key;
  266. }
  267. $this->_template = $this->_template2;
  268. $this->_keywordReplace($username, $this->_url);
  269. $this->_phpmailer->AddAddress($mail, $username); // 收件人邮箱和姓名
  270. $this->_phpmailer->Body = $this->_template;
  271. $result = $this->_phpmailer->Send();
  272. if (!$result) {
  273. $this->_is_error = true;
  274. $this->_error_msg = $this->_phpmailer->ErrorInfo;
  275. }
  276. if (!$this->_is_error) { // 写入redis
  277. $res = $this->_insertLog($mail, $this->_template, 'mail');
  278. $data = array('username' => $username, 'mail' => $mail, 't' => $key, 'create_time' => $this->_now_time);
  279. $this->_redis->set($this->_cache_key, json_encode($data), $this->_expire_time);
  280. $this->_status = true;
  281. }
  282. return array('status' => $this->_status, 'msg' => $this->_status ? '' : $this->_error_msg);
  283. }
  284. /**
  285. * 发送验证邮件(带数字验证码)
  286. * @param string $mail 要送到的邮箱地址
  287. */
  288. public function sendCodeMail($mail)
  289. {
  290. $this->_mail = $mail;
  291. $this->_makeCode();
  292. $this->_makeMailKey();
  293. $res = $this->_sendCodeRuler();
  294. if (!$res['status']) return $res;
  295. $this->_instantiate();
  296. $key = $this->_makeKey();
  297. $this->_template = $this->_template3;
  298. $this->_template = str_replace('%code%', $this->_code, $this->_template);
  299. $this->_phpmailer->AddAddress($mail); // 收件人邮箱和姓名
  300. $this->_phpmailer->Body = $this->_template;
  301. $result = $this->_phpmailer->Send();
  302. if (!$result) {
  303. $this->_is_error = true;
  304. $this->_error_msg = $this->_phpmailer->ErrorInfo;
  305. }
  306. if (!$this->_is_error) { // 写入redis
  307. $res = $this->_insertLog($mail, $this->_template, 'mail');
  308. $data = array('mail' => $mail, 'create_time' => $this->_now_time, 'code' => $this->_code);//now-here
  309. $this->_redis->set($this->_cache_key, json_encode($data), $this->_expire_time);
  310. $this->_setSendCodeRedisData();
  311. $this->_status = true;
  312. }
  313. return array('status' => $this->_status, 'msg' => $this->_status ? '' : $this->_error_msg);
  314. }
  315. /**
  316. * 发送申诉编码/通知邮件
  317. * @param string $mail 要送到的邮箱地址
  318. */
  319. public function sendAppealCodeMail($username, $code, $mail, $day, $certificate, $status)
  320. {
  321. $this->_instantiate();
  322. if ($status == 1) {
  323. $this->_template = $this->_template6;
  324. $this->_template = str_replace('%username%', $username, $this->_template);
  325. $this->_template = str_replace('%code%', $code, $this->_template);
  326. $this->_template = str_replace('%certificate%', $certificate, $this->_template);
  327. } elseif ($status == 2 || $status == 4) {
  328. $this->_template = $this->_template5;
  329. $this->_template = str_replace('%username%', $username, $this->_template);
  330. $this->_template = str_replace('%code%', $code, $this->_template);
  331. } else {
  332. $this->_template = $this->_template4;
  333. $this->_template = str_replace('%username%', $username, $this->_template);
  334. $this->_template = str_replace('%code%', $code, $this->_template);
  335. $this->_template = str_replace('%day%', $day, $this->_template);
  336. }
  337. if ($status != 1){
  338. $qqArr = model('Common/Kefu')->column('qq');
  339. $qq = implode('、',$qqArr);
  340. $this->_template = str_replace('%qq%', $qq, $this->_template);
  341. $time = model('Setting')->where('name','CUSTOMER_SERVICE_TIME')->value('value');
  342. $this->_template = str_replace('%servicetime%', $time, $this->_template);
  343. $phone = model('Setting')->where('name','CUSTOMER_SERVICE_PHONE')->value('value');
  344. $this->_template = str_replace('%servicephone%', $phone, $this->_template);
  345. $wechat = model('Setting')->where('name','WECHAT_NUMBER')->value('value');
  346. $this->_template = str_replace('%wechat%', $wechat, $this->_template);
  347. }
  348. $this->_phpmailer->AddAddress($mail); // 收件人邮箱和姓名
  349. $this->_phpmailer->Body = $this->_template;
  350. $result = $this->_phpmailer->Send();
  351. if (!$result) {
  352. $this->_is_error = true;
  353. $this->_error_msg = $this->_phpmailer->ErrorInfo;
  354. }
  355. if (!$this->_is_error) { // 写入redis
  356. $res = $this->_insertLog($mail, $this->_template, 'mail');
  357. $data = array('mail' => $mail, 'create_time' => $this->_now_time);
  358. $this->_redis->set($this->_cache_key, json_encode($data), $this->_expire_time);
  359. $this->_status = true;
  360. }
  361. return array('status' => $this->_status, 'msg' => $this->_status ? '' : $this->_error_msg);
  362. }
  363. /**
  364. * 自定义发送内容
  365. * @param $template 模板
  366. * @param $address 邮件地址
  367. * @return array 发送状态和信息
  368. */
  369. public function sendMail($template, $address)
  370. {
  371. $this->_instantiate();
  372. if (is_array($address)) {
  373. foreach ($address as $mail) {
  374. $this->_phpmailer->AddAddress($mail); // 批量收件
  375. }
  376. } else {
  377. $this->_phpmailer->AddAddress($address); // 单个收件人
  378. }
  379. $this->_phpmailer->Body = $template;
  380. $result = $this->_phpmailer->Send();
  381. if (!$result) {
  382. $this->_is_error = true;
  383. $this->_error_msg = $this->_phpmailer->ErrorInfo;
  384. }
  385. if (!$this->_is_error) {
  386. $this->_insertLog(implode(',', $address), $template, 'mail');
  387. $this->_status = true;
  388. }
  389. return array('status' => $this->_status, 'msg' => $this->_status ? '' : $this->_error_msg);
  390. }
  391. /**
  392. * 校验邮箱验证码是否正确,同时判断是否发送过
  393. *
  394. */
  395. public function checkMail($username, $mail)
  396. {
  397. $this->_username = $username;
  398. $key = $this->_makeKey();
  399. if (!$this->isMail($mail)) {
  400. $this->_is_error = true;
  401. $this->_error_msg = '邮箱号码错误';
  402. }
  403. $this->_username = $username;
  404. if (!$this->_is_error && !$res = $this->queryKey($key)) {
  405. $this->_is_error = true;
  406. $this->_error_msg = '验证码不存在,请先发送';
  407. }
  408. if (!$this->_is_error && ($this->_now_time - $res['create_time'] > $this->_expire_time)) { // 判断是否过期
  409. $this->_is_error = true;
  410. $this->_error_msg = '验证码已过期';
  411. }
  412. if (!$this->_is_error) {
  413. $this->_status = true;
  414. }
  415. return array('status' => $this->_status, 'msg' => $this->_error_msg);
  416. }
  417. /**
  418. * 校验邮箱验证码是否正确,同时判断是否发送过
  419. *
  420. */
  421. public function checkMailToken($username, $token)
  422. {
  423. $this->_username = $username;
  424. $key = $this->_makeKey();
  425. $res = $this->queryKey($key);
  426. if (!$this->_is_error && !$res) {
  427. $this->_is_error = true;
  428. $this->_error_msg = '邮箱验证链接不存在,请先发送';
  429. }
  430. if (!$this->_is_error && ($this->_now_time - $res['create_time'] > $this->_expire_time)) { // 判断是否过期
  431. $this->_is_error = true;
  432. $this->_error_msg = '邮箱验证链接已过期';
  433. }
  434. if ($res['t'] !== $token) {
  435. $this->_is_error = true;
  436. $this->_error_msg = '邮箱验证链接已失效';
  437. }
  438. if (!$this->_is_error) {
  439. $this->_status = true;
  440. }
  441. return array('status' => $this->_status, 'msg' => $this->_error_msg ,'data'=>$res);
  442. }
  443. /**
  444. * 校验邮箱验证码是否正确,同时判断是否发送过
  445. *
  446. */
  447. public function checkCode($username, $mail, $code)
  448. {
  449. $this->_username = $username;
  450. $key = $this->_makeKey();
  451. if (!$this->isMail($mail)) {
  452. $this->_is_error = true;
  453. $this->_error_msg = '邮箱号码错误';
  454. }
  455. if (!$this->_is_error && (empty($this->_getLastTime()) || empty($this->_getCode()))) {
  456. $this->_is_error = true;
  457. $this->_error_msg = '验证码不存在,请先发送';
  458. }
  459. if (!$this->_is_error && ($this->_now_time - $this->_last_time > $this->_expire_time)) { // 判断是否过期
  460. $this->_is_error = true;
  461. $this->_error_msg = '验证码已失效';
  462. }
  463. if (!$this->_is_error && $code != $this->_code) {
  464. $this->_is_error = true;
  465. $this->_error_msg = '验证码输入错误';
  466. }
  467. if (!$this->_is_error) {
  468. $this->_status = true;
  469. }
  470. return array('status' => $this->_status, 'msg' => $this->_error_msg);
  471. }
  472. /**
  473. * 根据key查询出缓存中的数据
  474. * @param string $key
  475. */
  476. public function queryKey($key)
  477. {
  478. $this->_cache_key = $this->_cache_key_prefix . $key;
  479. if ($this->_redis->has($this->_cache_key)) {
  480. $result = $this->_redis->get($this->_cache_key);
  481. return json_decode($result, true);
  482. }
  483. return null;
  484. }
  485. /**
  486. * 删除key(邮件中传递来的key)
  487. * @param string $key
  488. */
  489. public function clearKey($key)
  490. {
  491. $this->_cache_key = $this->_cache_key_prefix . $key;
  492. $this->_redis->rm($this->_cache_key);
  493. }
  494. /**
  495. * 通过username查询出key,并删除
  496. */
  497. public function clearKeyByUsername($username)
  498. {
  499. $this->_username = $username;
  500. $this->_makeKey();
  501. $this->_redis->rm($this->_cache_key);
  502. }
  503. /**
  504. * 邮箱格式验证
  505. * @param string $mail 邮箱地址
  506. */
  507. public function isMail($mail)
  508. {
  509. return preg_match($this->_preg_mail, $mail);
  510. }
  511. /**
  512. * 设置以当前用户名创建的redis记录的数组指定key的value
  513. * @param unknown $key
  514. * @param unknown $value
  515. */
  516. public function setValue($username, $key, $value)
  517. {
  518. $this->_username = $username;
  519. $this->_makeKey();
  520. if ($cache_data = $this->_redis->get($this->_cache_key)) {
  521. $cache_data = json_decode($cache_data, true);
  522. } else {
  523. $cache_data = array();
  524. }
  525. $cache_data[ $key ] = $value;
  526. $this->_redis->set($this->_cache_key, json_encode($data), $this->_expire_time);
  527. }
  528. /**
  529. * 生成redis的缓存key,使用用户名+当前日期的规则生成,确保当天生成的链接一致
  530. * @return string $key 生成的key,这是用于发送邮件中带的key,不是redis中存储的key
  531. */
  532. protected function _makeKey()
  533. {
  534. $key = md5($this->_username . date('Ymd'));
  535. $this->_cache_key = $this->_cache_key_prefix . $key;
  536. return $key;
  537. }
  538. /**
  539. * 替换掉模板中的关键字符串
  540. * @param string $username 玩家账号
  541. * @param string $url 跳转链接
  542. */
  543. protected function _keywordReplace($username, $url)
  544. {
  545. $this->_template = str_replace('%BRAND_NAME%', $this->_brand_name, $this->_template);
  546. $this->_template = str_replace('%WEBSITE%', $this->_website, $this->_template);
  547. $this->_template = str_replace('%YEAR%', date('Y'), $this->_template);
  548. $this->_template = str_replace('%url%', $url, $this->_template);
  549. $this->_template = str_replace('%username%', $username, $this->_template);
  550. }
  551. /**
  552. * 实例化对象并加载通用配置
  553. */
  554. protected function _instantiate()
  555. {
  556. $this->_phpmailer = new PHPMailer\PHPMailer();
  557. $this->_configuration();
  558. }
  559. /**
  560. * phpmailer通用配置
  561. */
  562. protected function _configuration()
  563. {
  564. $this->_phpmailer->Mailer = 'SMTP';
  565. $this->_phpmailer->SMTPDebug = 0;
  566. $this->_phpmailer->SMTPSecure = 'ssl';
  567. $this->_phpmailer->SMTPAuth = true;
  568. $this->_phpmailer->Host = config('mail.host');
  569. $this->_phpmailer->Port = config('mail.port');
  570. $this->_phpmailer->Username = config('mail.username');
  571. $this->_phpmailer->Password = config('mail.password');
  572. $this->_phpmailer->From = config('mail.username'); // 发件人邮箱
  573. $this->_phpmailer->FromName = '麻花网络游戏'; // 发件人
  574. $this->_phpmailer->CharSet = 'utf-8'; // 这里指定字符集!
  575. $this->_phpmailer->Encoding = 'base64';
  576. $this->_phpmailer->Subject = $this->_brand_name . '官方邮箱验证';
  577. $this->_phpmailer->IsHTML(true);
  578. $this->_phpmailer->AddReplyTo(config('mail.username'), ''); // 回复地址
  579. $this->_phpmailer->AltBody = $this->_brand_name;
  580. }
  581. /**
  582. * 生成验证码
  583. * @return null
  584. */
  585. protected function _makeCode()
  586. {
  587. $code = rand(111111, 999999);
  588. $this->_code = $code;
  589. }
  590. /**
  591. * 获取最后一次发送时间
  592. * @return string
  593. */
  594. protected function _getLastTime()
  595. {
  596. $this->_last_time = $this->_getValue('create_time');
  597. return $this->_last_time;
  598. }
  599. /**
  600. * 获取redis中该邮箱的某个key的值
  601. */
  602. protected function _getValue($key)
  603. {
  604. $response = null;
  605. if ($this->_redis->has($this->_cache_key)) { // 存在这个key
  606. $data = $this->_redis->get($this->_cache_key);
  607. $data = json_decode($data, true);
  608. if (isset($data)) { // 该号码已经有发送记录
  609. $response = $data[ $key ];
  610. }
  611. }
  612. return $response;
  613. }
  614. /**
  615. * 获取redis中保存的该邮箱号的验证码
  616. */
  617. protected function _getCode()
  618. {
  619. $this->_code = $this->_getValue('code');
  620. return $this->_code;
  621. }
  622. /**
  623. * 写入发送日志
  624. * @param string $email
  625. * @param string $content
  626. * @param string $type
  627. * @return null
  628. */
  629. protected function _insertLog($email, $content, $type = 'mail')
  630. {
  631. $data = [];
  632. $data['content'] = addslashes($content);
  633. $data['type'] = $type;
  634. $data['target'] = $email;
  635. $data['create_time']= NOW_TIMESTAMP;
  636. model('MailLog')->save($data);
  637. }
  638. /**
  639. * 发送验证邮件(带数字验证码 和 用户名的)
  640. * @param string $mail 要送到的邮箱地址
  641. */
  642. public function sendCodeMailByType($username,$mail,$type = 'fogetpwd')
  643. {
  644. $this->_mail = $mail;
  645. if (!$this->isMail($mail)) {
  646. $this->_error_msg = '邮箱号码错误';
  647. return array('status' => false, 'msg' => $this->_error_msg);
  648. }
  649. $this->_makeCode();
  650. $this->_makeMailKey();
  651. $res = $this->_sendCodeRuler();
  652. if (!$res['status']) return $res;
  653. $this->_username = $username;
  654. $this->_instantiate();
  655. $key = $this->_makeKey();
  656. if ($type == 'fogetpwd'){ // 忘记密码-邮箱验证身份
  657. $this->_template = $this->_template7;
  658. }elseif ($type == 'bindMobilVLEmail'){ // 绑定手机-邮箱验证身份(换绑手机)
  659. $this->_template = $this->_template12;
  660. }elseif ($type == 'bindEmail'){ // 绑定邮箱
  661. $this->_template = $this->_template9;
  662. }elseif ($type == 'appeal'){ // 账号申诉-邮件验证身份
  663. $this->_template = $this->_template10;
  664. }elseif ($type == 'bindEmailVLEmail'){ // 绑定邮箱-邮箱验证身份
  665. $this->_template = $this->_template11;
  666. }elseif ($type == 'bindMobil'){ // 绑定手机-邮箱验证身份(没绑手机)
  667. $this->_template = $this->_template8;
  668. }elseif ($type == 'resetPasswordByEmail'){ // 通过邮箱找回密码
  669. $this->_template = $this->_template15;
  670. }
  671. $this->_template = str_replace('%code%', $this->_code, $this->_template);
  672. $this->_template = str_replace('%username%', $username, $this->_template);
  673. $this->_phpmailer->AddAddress($mail); // 收件人邮箱和姓名
  674. $this->_phpmailer->Body = $this->_template;
  675. $result = $this->_phpmailer->Send();
  676. if (!$result) {
  677. $this->_is_error = true;
  678. $this->_error_msg = $this->_phpmailer->ErrorInfo;
  679. }
  680. if (!$this->_is_error) { // 写入redis
  681. $res = $this->_insertLog($mail, $this->_template, 'mail');
  682. $data = array('mail' => $mail, 'create_time' => $this->_now_time, 'code' => $this->_code);//now-here
  683. $this->_redis->set($this->_cache_key, json_encode($data), $this->_expire_time);
  684. $this->_setSendCodeRedisData();
  685. $this->_status = true;
  686. }
  687. return array('status' => $this->_status, 'msg' => $this->_status ? '' : $this->_error_msg);
  688. }
  689. /**
  690. * 生成redis的缓存key,使用邮箱+当前日期的规则生成,确保当天生成的链接一致
  691. * @return string $key 生成的key,这是用于发送邮件中带的key,不是redis中存储的key
  692. */
  693. protected function _makeMailKey()
  694. {
  695. $key = md5($this->_mail . date('Ymd'));
  696. $this->_cache_mail_key = $this->_cache_key_prefix . $key;
  697. return $key;
  698. }
  699. /**
  700. * 写入redis数据
  701. * @return null
  702. */
  703. protected function _setSendCodeRedisData(){
  704. // 存在这个key
  705. if ($this->_redis->has($this->_cache_mail_key)) {
  706. $data = $this->_redis->get($this->_cache_mail_key);
  707. $data = json_decode($data, true);
  708. if (!isset($data)) {
  709. $data = array(
  710. 'times' => 1,
  711. 'sendtime' => $this->_now_time,
  712. 'code' => $this->_code,
  713. );
  714. } else {
  715. $data['times'] = ++$data['times'];
  716. $data['sendtime'] = $this->_now_time;
  717. $data['code'] = $this->_code;
  718. }
  719. } else { // 不存在这个key,新建
  720. $data = array(
  721. 'times' => 1,
  722. 'sendtime' => time(),
  723. 'code' => $this->_code,
  724. ); //now-here
  725. }
  726. $this->_redis->set($this->_cache_mail_key, json_encode($data), $this->_expire_time);
  727. }
  728. /**
  729. * 判断该邮箱是否在一定时间内,一直发验证码
  730. * @return array
  731. */
  732. protected function _sendCodeRuler(){
  733. // 存在这个key
  734. if ($this->_redis->has($this->_cache_mail_key)) {
  735. $data = $this->_redis->get($this->_cache_mail_key);
  736. $data = json_decode($data, true);
  737. if (isset($data)) {
  738. if ( ($this->_now_time - $data['sendtime']) < $this->_interval) {
  739. $this->_error_msg = '发送验证码操作太频繁,请稍后再试';
  740. return array('status' => false, 'msg' => $this->_error_msg);
  741. }
  742. }
  743. }
  744. return array('status' => true, 'msg' => '');
  745. }
  746. }