PageRenderTime 25ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/Jyxo/Mail/Sender/Smtp.php

https://github.com/jyxo/php-no-namespace
PHP | 342 lines | 161 code | 34 blank | 147 comment | 19 complexity | 07531588cf3cba21773f3660027f4ce9 MD5 | raw file
  1. <?php
  2. /**
  3. * Jyxo PHP Library
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file license.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * https://github.com/jyxo/php/blob/master/license.txt
  11. */
  12. /**
  13. * Class for sending emails using a SMTP server.
  14. * Works in combination with Jyxo_Mail_Sender.
  15. *
  16. * @category Jyxo
  17. * @package Jyxo_Mail
  18. * @subpackage Sender
  19. * @copyright Copyright (c) 2005-2011 Jyxo, s.r.o.
  20. * @license https://github.com/jyxo/php/blob/master/license.txt
  21. * @author Jaroslav HanslĂ­k
  22. */
  23. class Jyxo_Mail_Sender_Smtp
  24. {
  25. /**
  26. * Line endings.
  27. *
  28. * @var string
  29. */
  30. const LINE_END = "\r\n";
  31. /**
  32. * Established connection.
  33. *
  34. * @var resource
  35. */
  36. private $connection = null;
  37. /**
  38. * SMTP server.
  39. *
  40. * @var string
  41. */
  42. private $host = 'localhost';
  43. /**
  44. * SMTP port.
  45. *
  46. * @var integer
  47. */
  48. private $port = 25;
  49. /**
  50. * SMTP HELO value.
  51. *
  52. * @var string
  53. */
  54. private $helo = 'localhost';
  55. /**
  56. * SMTP connection timeout.
  57. *
  58. * @var string
  59. */
  60. private $timeout = 5;
  61. /**
  62. * Creates an instance.
  63. *
  64. * @param string $host Server hostname
  65. * @param integer $port Server port
  66. * @param string $helo HELO value
  67. * @param integer $timeout Connection timeout
  68. */
  69. public function __construct($host = 'localhost', $port = 25, $helo = 'localhost', $timeout = 5)
  70. {
  71. $this->host = (string) $host;
  72. $this->port = (int) $port;
  73. $this->timeout = (int) $timeout;
  74. $this->helo = (string) $helo;
  75. }
  76. /**
  77. * Destroys an instance and disconnects from the server.
  78. */
  79. public function __destruct()
  80. {
  81. if (is_resource($this->connection)) {
  82. $this->disconnect();
  83. }
  84. }
  85. /**
  86. * Connects to the SMTP server.
  87. *
  88. * @return Jyxo_Mail_Sender_Smtp
  89. * @throws Jyxo_Mail_Sender_SmtpException If a connection error occurs
  90. */
  91. public function connect()
  92. {
  93. $this->connection = fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
  94. if (false === $this->connection) {
  95. throw new Jyxo_Mail_Sender_SmtpException('CONNECTION: ' . $errno . ' ' . $errstr);
  96. }
  97. // Reads the initial connection data
  98. $this->readData();
  99. // Sends EHLO/HELO
  100. $this->commandHelo();
  101. return $this;
  102. }
  103. /**
  104. * Disconnects from server.
  105. *
  106. * @return Jyxo_Mail_Sender_Smtp
  107. */
  108. public function disconnect()
  109. {
  110. if (is_resource($this->connection)) {
  111. try {
  112. $this->reset();
  113. $this->writeData('QUIT');
  114. fclose($this->connection);
  115. $this->connection = null;
  116. } catch (Exception $e) {
  117. // Disconnecting; ignore possible exceptions
  118. }
  119. }
  120. return $this;
  121. }
  122. /**
  123. * Connects to the server using a username and password.
  124. *
  125. * @param string $user Username
  126. * @param string $password Password
  127. * @return Jyxo_Mail_Sender_Smtp
  128. * @throws Jyxo_Mail_Sender_SmtpException On authentication error
  129. */
  130. public function auth($user, $password)
  131. {
  132. $this->writeData('AUTH LOGIN');
  133. $response = $this->readData();
  134. if ('334' !== substr($response, 0, 3)) {
  135. throw new Jyxo_Mail_Sender_SmtpException('AUTH: ' . $response);
  136. }
  137. $this->writeData(base64_encode($user));
  138. $response = $this->readData();
  139. if ('334' !== substr($response, 0, 3)) {
  140. throw new Jyxo_Mail_Sender_SmtpException('AUTH: ' . $response);
  141. }
  142. $this->writeData(base64_encode($password));
  143. $response = $this->readData();
  144. if ('235' !== substr($response, 0, 3)) {
  145. throw new Jyxo_Mail_Sender_SmtpException('AUTH: ' . $response);
  146. }
  147. return $this;
  148. }
  149. /**
  150. * Sets the sender.
  151. *
  152. * @param string $from Sender
  153. * @return Jyxo_Mail_Sender_Smtp
  154. */
  155. public function from($from)
  156. {
  157. $this->commandMailFrom($from);
  158. return $this;
  159. }
  160. /**
  161. * Adds a recipient.
  162. *
  163. * @param string $recipient Recipient
  164. * @return Jyxo_Mail_Sender_Smtp
  165. */
  166. public function recipient($recipient)
  167. {
  168. $this->commandRcptTo($recipient);
  169. return $this;
  170. }
  171. /**
  172. * Sends email headers and body.
  173. *
  174. * @param string $header Headers
  175. * @param string $body Body
  176. * @return Jyxo_Mail_Sender_Smtp
  177. * @throws Jyxo_Mail_Sender_SmtpException On data sending error
  178. */
  179. public function data($header, $body)
  180. {
  181. $lineEnds = array(Jyxo_Mail_Sender::LINE_END . '.' => self::LINE_END . '..', Jyxo_Mail_Sender::LINE_END => self::LINE_END);
  182. $header = strtr($header, $lineEnds);
  183. $body = strtr($body, $lineEnds);
  184. if ('.' == $body[0]) {
  185. $body = '.' . $body;
  186. }
  187. $this->commandData();
  188. $this->writeData(trim($header));
  189. $this->writeData('');
  190. $this->writeData($body);
  191. $this->writeData('.');
  192. $response = $this->readData();
  193. if ('250' !== substr($response, 0, 3)) {
  194. throw new Jyxo_Mail_Sender_SmtpException('SEND: ' . $response);
  195. }
  196. return $this;
  197. }
  198. /**
  199. * Resets previous commands.
  200. *
  201. * @return Jyxo_Mail_Sender_Smtp
  202. */
  203. public function reset()
  204. {
  205. $this->commandRset();
  206. return $this;
  207. }
  208. /**
  209. * Sends the EHLO/HELO command.
  210. *
  211. * @throws Jyxo_Mail_Sender_SmtpException On error
  212. */
  213. private function commandHelo()
  214. {
  215. $this->writeData('EHLO ' . $this->helo);
  216. $response = $this->readData();
  217. if ('250' !== substr($response, 0, 3)) {
  218. $this->writeData('HELO ' . $this->helo);
  219. $response = $this->readData();
  220. if ('250' !== substr($response, 0, 3)) {
  221. throw new Jyxo_Mail_Sender_SmtpException('HELO: ' . $response);
  222. }
  223. }
  224. }
  225. /**
  226. * Sends the MAIL FROM command.
  227. *
  228. * @param string $from
  229. * @throws Jyxo_Mail_Sender_SmtpException On error
  230. */
  231. private function commandMailFrom($from)
  232. {
  233. $this->writeData('MAIL FROM: <' . $from . '>');
  234. $response = $this->readData();
  235. if ('250' !== substr($response, 0, 3)) {
  236. throw new Jyxo_Mail_Sender_SmtpException('MAIL FROM: ' . $response);
  237. }
  238. }
  239. /**
  240. * Sends the RCPT TO command.
  241. *
  242. * @param string $recipient
  243. * @throws Jyxo_Mail_Sender_SmtpException On error
  244. */
  245. private function commandRcptTo($recipient)
  246. {
  247. $this->writeData('RCPT TO: <' . $recipient . '>');
  248. $response = $this->readData();
  249. if ('250' !== substr($response, 0, 3)) {
  250. throw new Jyxo_Mail_Sender_SmtpException('RCPT TO: ' . $response);
  251. }
  252. }
  253. /**
  254. * Sends the DATA command.
  255. *
  256. * @throws Jyxo_Mail_Sender_SmtpException On error
  257. */
  258. private function commandData()
  259. {
  260. $this->writeData('DATA');
  261. $response = $this->readData();
  262. if ('354' !== substr($response, 0, 3)) {
  263. throw new Jyxo_Mail_Sender_SmtpException('DATA: ' . $response);
  264. }
  265. }
  266. /**
  267. * Sends the RSET command.
  268. *
  269. * @throws Jyxo_Mail_Sender_SmtpException On error
  270. */
  271. private function commandRset()
  272. {
  273. $this->writeData('RSET');
  274. $response = $this->readData();
  275. if ('250' !== substr($response, 0, 3)) {
  276. throw new Jyxo_Mail_Sender_SmtpException('RSET: ' . $response);
  277. }
  278. }
  279. /**
  280. * Reads data from the server.
  281. *
  282. * @return string
  283. */
  284. private function readData()
  285. {
  286. $data = '';
  287. $i = 0;
  288. while ($line = fgets($this->connection)) {
  289. $data .= $line;
  290. if (' ' == substr($line, 3, 1)) {
  291. break;
  292. }
  293. }
  294. return $data;
  295. }
  296. /**
  297. * Sends data to the server.
  298. *
  299. * @param string $data Data
  300. * @throws Jyxo_Mail_Sender_SmtpException On error
  301. */
  302. private function writeData($data)
  303. {
  304. if (!fwrite($this->connection, $data . self::LINE_END)) {
  305. throw new Jyxo_Mail_Sender_SmtpException('Error while writing data.');
  306. }
  307. }
  308. }