PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/OurAPIServer/lib/smtp.php

https://gitlab.com/binhduong/test
PHP | 268 lines | 161 code | 15 blank | 92 comment | 22 complexity | ebe985f0a3630be9d086f72164fe5a52 MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /*
  3. Copyright (c) 2009-2014 F3::Factory/Bong Cosca, All rights reserved.
  4. This file is part of the Fat-Free Framework (http://fatfree.sf.net).
  5. THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF
  6. ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  7. IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  8. PURPOSE.
  9. Please see the license.txt file for more information.
  10. */
  11. //! SMTP plug-in
  12. class SMTP extends Magic {
  13. //@{ Locale-specific error/exception messages
  14. const
  15. E_Header='%s: header is required',
  16. E_Blank='Message must not be blank',
  17. E_Attach='Attachment %s not found';
  18. //@}
  19. private
  20. //! Message properties
  21. $headers,
  22. //! E-mail attachments
  23. $attachments,
  24. //! SMTP host
  25. $host,
  26. //! SMTP port
  27. $port,
  28. //! TLS/SSL
  29. $scheme,
  30. //! User ID
  31. $user,
  32. //! Password
  33. $pw,
  34. //! TCP/IP socket
  35. $socket,
  36. //! Server-client conversation
  37. $log;
  38. /**
  39. * Fix header
  40. * @return string
  41. * @param $key string
  42. **/
  43. protected function fixheader($key) {
  44. return str_replace(' ','-',
  45. ucwords(preg_replace('/[_-]/',' ',strtolower($key))));
  46. }
  47. /**
  48. * Return TRUE if header exists
  49. * @return bool
  50. * @param $key
  51. **/
  52. function exists($key) {
  53. $key=$this->fixheader($key);
  54. return isset($this->headers[$key]);
  55. }
  56. /**
  57. * Bind value to e-mail header
  58. * @return string
  59. * @param $key string
  60. * @param $val string
  61. **/
  62. function set($key,$val) {
  63. $key=$this->fixheader($key);
  64. return $this->headers[$key]=$val;
  65. }
  66. /**
  67. * Return value of e-mail header
  68. * @return string|NULL
  69. * @param $key string
  70. **/
  71. function get($key) {
  72. $key=$this->fixheader($key);
  73. return isset($this->headers[$key])?$this->headers[$key]:NULL;
  74. }
  75. /**
  76. * Remove header
  77. * @return NULL
  78. * @param $key string
  79. **/
  80. function clear($key) {
  81. $key=$this->fixheader($key);
  82. unset($this->headers[$key]);
  83. }
  84. /**
  85. * Return client-server conversation history
  86. * @return string
  87. **/
  88. function log() {
  89. return str_replace("\n",PHP_EOL,$this->log);
  90. }
  91. /**
  92. * Send SMTP command and record server response
  93. * @return NULL
  94. * @param $cmd string
  95. * @param $log bool
  96. **/
  97. protected function dialog($cmd=NULL,$log=TRUE) {
  98. $socket=&$this->socket;
  99. if (!is_null($cmd))
  100. fputs($socket,$cmd."\r\n");
  101. $reply='';
  102. while (!feof($socket) && ($info=stream_get_meta_data($socket)) &&
  103. !$info['timed_out'] && $str=fgets($socket,4096)) {
  104. $reply.=$str;
  105. if (preg_match('/(?:^|\n)\d{3} .+?\r\n/s',$reply))
  106. break;
  107. }
  108. if ($log) {
  109. $this->log.=$cmd."\n";
  110. $this->log.=str_replace("\r",'',$reply);
  111. }
  112. }
  113. /**
  114. * Add e-mail attachment
  115. * @return NULL
  116. * @param $file
  117. **/
  118. function attach($file) {
  119. if (!is_file($file))
  120. user_error(sprintf(self::E_Attach,$file));
  121. $this->attachments[]=$file;
  122. }
  123. /**
  124. * Transmit message
  125. * @return bool
  126. * @param $message string
  127. * @param $log bool
  128. **/
  129. function send($message,$log=TRUE) {
  130. if ($this->scheme=='ssl' && !extension_loaded('openssl'))
  131. return FALSE;
  132. $fw=Base::instance();
  133. // Connect to the server
  134. $socket=&$this->socket;
  135. $socket=@fsockopen($this->host,$this->port);
  136. if (!$socket)
  137. return FALSE;
  138. stream_set_blocking($socket,TRUE);
  139. // Get server's initial response
  140. $this->dialog(NULL,FALSE);
  141. // Announce presence
  142. $this->dialog('EHLO '.$fw->get('HOST'));
  143. if (strtolower($this->scheme)=='tls') {
  144. $this->dialog('STARTTLS');
  145. stream_socket_enable_crypto(
  146. $socket,TRUE,STREAM_CRYPTO_METHOD_TLS_CLIENT);
  147. $this->dialog('EHLO '.$fw->get('HOST'));
  148. }
  149. if ($this->user && $this->pw) {
  150. // Authenticate
  151. $this->dialog('AUTH LOGIN');
  152. $this->dialog(base64_encode($this->user));
  153. $this->dialog(base64_encode($this->pw));
  154. }
  155. // Required headers
  156. $reqd=array('From','To','Subject');
  157. // Retrieve headers
  158. $headers=$this->headers;
  159. foreach ($reqd as $id)
  160. if (empty($headers[$id]))
  161. user_error(sprintf(self::E_Header,$id));
  162. // Message should not be blank
  163. if (!$message)
  164. user_error(self::E_Blank);
  165. $eol="\r\n";
  166. $str='';
  167. // Stringify headers
  168. foreach ($headers as $key=>$val)
  169. if (!in_array($key,$reqd))
  170. $str.=$key.': '.$val.$eol;
  171. // Start message dialog
  172. $this->dialog('MAIL FROM: '.strstr($headers['From'],'<'));
  173. foreach ($fw->split($headers['To'].
  174. (isset($headers['Cc'])?(';'.$headers['Cc']):'').
  175. (isset($headers['Bcc'])?(';'.$headers['Bcc']):'')) as $dst)
  176. $this->dialog('RCPT TO: '.strstr($dst,'<'));
  177. $this->dialog('DATA');
  178. if ($this->attachments) {
  179. // Replace Content-Type
  180. $hash=uniqid(NULL,TRUE);
  181. $type=$headers['Content-Type'];
  182. $headers['Content-Type']='multipart/mixed; '.
  183. 'boundary="'.$hash.'"';
  184. // Send mail headers
  185. $out='';
  186. foreach ($headers as $key=>$val)
  187. if ($key!='Bcc')
  188. $out.=$key.': '.$val.$eol;
  189. $out.=$eol;
  190. $out.='This is a multi-part message in MIME format'.$eol;
  191. $out.=$eol;
  192. $out.='--'.$hash.$eol;
  193. $out.='Content-Type: '.$type.$eol;
  194. $out.=$eol;
  195. $out.=$message.$eol;
  196. foreach ($this->attachments as $attachment) {
  197. $out.='--'.$hash.$eol;
  198. $out.='Content-Type: application/octet-stream'.$eol;
  199. $out.='Content-Transfer-Encoding: base64'.$eol;
  200. $out.='Content-Disposition: attachment; '.
  201. 'filename="'.basename($attachment).'"'.$eol;
  202. $out.=$eol;
  203. $out.=chunk_split(
  204. base64_encode(file_get_contents($attachment))).$eol;
  205. }
  206. $out.=$eol;
  207. $out.='--'.$hash.'--'.$eol;
  208. $out.='.';
  209. $this->dialog($out);
  210. }
  211. else {
  212. // Send mail headers
  213. $out='';
  214. foreach ($headers as $key=>$val)
  215. if ($key!='Bcc')
  216. $out.=$key.': '.$val.$eol;
  217. $out.=$eol;
  218. $out.=$message.$eol;
  219. $out.='.';
  220. // Send message
  221. $this->dialog($out);
  222. }
  223. $this->dialog('QUIT');
  224. if ($socket)
  225. fclose($socket);
  226. return TRUE;
  227. }
  228. /**
  229. * Instantiate class
  230. * @param $host string
  231. * @param $port int
  232. * @param $scheme string
  233. * @param $user string
  234. * @param $pw string
  235. **/
  236. function __construct($host,$port,$scheme,$user,$pw) {
  237. $this->headers=array(
  238. 'MIME-Version'=>'1.0',
  239. 'Content-Type'=>'text/plain; '.
  240. 'charset='.Base::instance()->get('ENCODING'),
  241. 'Content-Transfer-Encoding'=>'8bit'
  242. );
  243. $this->host=$host;
  244. if (strtolower($this->scheme=strtolower($scheme))=='ssl')
  245. $this->host='ssl://'.$host;
  246. $this->port=$port;
  247. $this->user=$user;
  248. $this->pw=$pw;
  249. }
  250. }