PageRenderTime 43ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/framework/F3/smtp.php

https://bitbucket.org/lxa478/qcrt
PHP | 261 lines | 155 code | 18 blank | 88 comment | 15 complexity | ea1d4ae51604a220481cd809e8325b9f MD5 | raw file
Possible License(s): GPL-3.0
  1. <?php
  2. /**
  3. SMTP plugin for the PHP Fat-Free Framework
  4. The contents of this file are subject to the terms of the GNU General
  5. Public License Version 3.0. You may not use this file except in
  6. compliance with the license. Any of the license terms and conditions
  7. can be waived if you get permission from the copyright holder.
  8. Copyright (c) 2009-2012 F3::Factory
  9. Bong Cosca <bong.cosca@yahoo.com>
  10. @package SMTP
  11. @version 2.1.0
  12. **/
  13. //! SMTP plugin
  14. class SMTP extends Base {
  15. //@{ Locale-specific error/exception messages
  16. const
  17. TEXT_MailHeader='%s: header is required',
  18. TEXT_MailBlank='Message must not be blank',
  19. TEXT_MailAttach='Attachment %s not found';
  20. //@}
  21. const
  22. //! Carriage return/line feed sequence
  23. EOL="\r\n";
  24. //@{ SMTP headers
  25. const
  26. SMTP_Content='Content-Type',
  27. SMTP_Disposition='Content-Disposition',
  28. SMTP_Encoding='Content-Transfer-Encoding',
  29. SMTP_MIME='MIME-Version';
  30. //@}
  31. const
  32. // Notice to mail clients
  33. SMTP_Notice='This is a multi-part message in MIME format';
  34. private
  35. //! Message properties
  36. $headers,
  37. //! Connection parameters
  38. $socket,$server,$port,$enc,
  39. //! E-mail attachments
  40. $attachments;
  41. public
  42. //! Server-client conversation
  43. $log;
  44. /**
  45. Fix header
  46. @param $key
  47. @private
  48. **/
  49. private function fixheader($key) {
  50. return str_replace(' ','-',
  51. ucwords(str_replace('-',' ',self::resolve($key))));
  52. }
  53. /**
  54. Add e-mail attachment
  55. @param $file
  56. @public
  57. **/
  58. function attach($file) {
  59. if (!is_file($file)) {
  60. trigger_error(sprintf(self::TEXT_MailAttach,$file));
  61. return;
  62. }
  63. $this->attachments[]=$file;
  64. }
  65. /**
  66. Bind value to e-mail header
  67. @param $key string
  68. @param $val string
  69. @public
  70. **/
  71. function set($key,$val) {
  72. $key=$this->fixheader($key);
  73. $this->headers[$key]=self::resolve($val);
  74. }
  75. /**
  76. Return value of e-mail header
  77. @param $key string
  78. @public
  79. **/
  80. function get($key) {
  81. $key=$this->fixheader($key);
  82. return isset($this->headers[$key])?$this->headers[$key]:NULL;
  83. }
  84. /**
  85. Remove header
  86. @param $key
  87. @public
  88. **/
  89. function clear($key) {
  90. $key=$this->fixheader($key);
  91. unset($this->headers[$key]);
  92. }
  93. /**
  94. Send SMTP command and record server response
  95. @param $cmd string
  96. @param $log boolean
  97. @public
  98. **/
  99. function dialog($cmd=NULL,$log=TRUE) {
  100. $socket=&$this->socket;
  101. fputs($socket,$cmd.self::EOL);
  102. if ($log) {
  103. $reply='';
  104. while ($str=fgets($socket,512)) {
  105. $reply.=$str;
  106. if (preg_match('/\d{3}\s/',$str))
  107. break;
  108. }
  109. $this->log.=$cmd."\n";
  110. $this->log.=$reply;
  111. }
  112. else
  113. $this->log.=$cmd."\n";
  114. }
  115. /**
  116. Transmit message
  117. @param $message string
  118. @public
  119. **/
  120. function send($message) {
  121. // Required headers
  122. $reqd=array('From','To','Subject');
  123. // Retrieve headers
  124. $headers=$this->headers;
  125. foreach ($reqd as $id)
  126. if (!isset($headers[$id])) {
  127. trigger_error(sprintf(self::TEXT_MailHeader,$id));
  128. return;
  129. }
  130. // Message should not be blank
  131. $message=self::resolve($message);
  132. if (!$message) {
  133. trigger_error(self::TEXT_MailBlank);
  134. return;
  135. }
  136. $str='';
  137. // Stringify headers
  138. foreach ($headers as $key=>$val)
  139. if (!in_array($key,$reqd))
  140. $str.=$key.': '.$val."\r\n";
  141. // Start message dialog
  142. $this->dialog('MAIL FROM: '.strstr($headers['From'],'<'));
  143. $this->dialog('RCPT TO: '.$headers['To']);
  144. $this->dialog('DATA');
  145. if ($this->attachments) {
  146. // Replace Content-Type
  147. $hash=self::hash(mt_rand());
  148. $type=$headers[self::SMTP_Content];
  149. $headers[self::SMTP_Content]='multipart/mixed; '.
  150. 'boundary="'.$hash.'"';
  151. // Send mail headers
  152. foreach ($headers as $key=>$val)
  153. $this->dialog($key.': '.$val,FALSE);
  154. $this->dialog(NULL,FALSE);
  155. $this->dialog(self::SMTP_Notice,FALSE);
  156. $this->dialog(NULL,FALSE);
  157. $this->dialog('--'.$hash,FALSE);
  158. $this->dialog(self::SMTP_Content.': '.$type,FALSE);
  159. $this->dialog(NULL,FALSE);
  160. $this->dialog($message,FALSE);
  161. foreach ($this->attachments as $attachment) {
  162. $this->dialog('--'.$hash,FALSE);
  163. $this->dialog(self::SMTP_Content.': '.
  164. 'application/octet-stream',FALSE);
  165. $this->dialog(self::SMTP_Encoding.': base64',FALSE);
  166. $this->dialog(self::SMTP_Disposition.': '.
  167. 'attachment; filename="'.basename($attachment).'"',FALSE);
  168. $this->dialog(NULL,FALSE);
  169. $this->dialog(chunk_split(base64_encode(
  170. self::getfile($attachment))),FALSE);
  171. }
  172. $this->dialog('--'.$hash.'--',FALSE);
  173. }
  174. else {
  175. // Send mail headers
  176. foreach ($headers as $key=>$val)
  177. $this->dialog($key.': '.$val,FALSE);
  178. $this->dialog(NULL,FALSE);
  179. // Send message
  180. $this->dialog($message,FALSE);
  181. }
  182. $this->dialog('.');
  183. }
  184. /**
  185. Class constructor
  186. @param $server string
  187. @param $port int
  188. @param $enc string
  189. @param $user string
  190. @param $pw string
  191. @public
  192. **/
  193. function __construct(
  194. $server='localhost',$port=25,$enc=NULL,$user=NULL,$pw=NULL) {
  195. $this->headers=array(
  196. self::SMTP_MIME=>'1.0',
  197. self::SMTP_Content=>'text/plain; charset='.self::ref('ENCODING'),
  198. self::SMTP_Encoding=>'8bit'
  199. );
  200. if ($enc && $enc!='TLS')
  201. $server=strtolower($enc).'://'.$server;
  202. $this->server=$server;
  203. $this->port=$port;
  204. $this->enc=$enc;
  205. // Connect to the server
  206. $socket=&$this->socket;
  207. $socket=@fsockopen($server,$port,$errno,$errstr);
  208. if (!$socket) {
  209. trigger_error($errstr);
  210. return;
  211. }
  212. stream_set_blocking($socket,TRUE);
  213. stream_set_timeout($socket,ini_get('default_socket_timeout'));
  214. // Get server's initial response
  215. $this->log=fgets($socket,512);
  216. // Indicate presence
  217. $this->dialog('EHLO '.$_SERVER['SERVER_NAME']);
  218. if ($enc=='TLS') {
  219. $this->dialog('STARTTLS');
  220. stream_socket_enable_crypto(
  221. $socket,TRUE,STREAM_CRYPTO_METHOD_TLS_CLIENT);
  222. $this->dialog('EHLO '.$_SERVER['SERVER_NAME']);
  223. }
  224. if ($user) {
  225. // Authenticate
  226. $this->dialog('AUTH LOGIN');
  227. $this->dialog(base64_encode($user));
  228. $this->dialog(base64_encode($pw));
  229. }
  230. }
  231. /**
  232. Free up resources
  233. @public
  234. **/
  235. function __destruct() {
  236. $this->dialog('QUIT');
  237. if ($this->socket)
  238. fclose($this->socket);
  239. }
  240. }