PageRenderTime 48ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/apps/libraries/swift_mailer/classes/Swift/Transport/AbstractSmtpTransport.php

https://gitlab.com/dsasmita/talita-shop
PHP | 507 lines | 318 code | 65 blank | 124 comment | 38 complexity | 96ce75f8614f92ae7ac6f0e8143248f3 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of SwiftMailer.
  4. * (c) 2004-2009 Chris Corbyn
  5. *
  6. * For the full copyright and license information, please view the LICENSE
  7. * file that was distributed with this source code.
  8. */
  9. /**
  10. * Sends Messages over SMTP.
  11. *
  12. * @package Swift
  13. * @subpackage Transport
  14. * @author Chris Corbyn
  15. */
  16. abstract class Swift_Transport_AbstractSmtpTransport implements Swift_Transport
  17. {
  18. /** Input-Output buffer for sending/receiving SMTP commands and responses */
  19. protected $_buffer;
  20. /** Connection status */
  21. protected $_started = false;
  22. /** The domain name to use in HELO command */
  23. protected $_domain = '[127.0.0.1]';
  24. /** The event dispatching layer */
  25. protected $_eventDispatcher;
  26. /** Source Ip */
  27. protected $_sourceIp;
  28. /** Return an array of params for the Buffer */
  29. abstract protected function _getBufferParams();
  30. /**
  31. * Creates a new EsmtpTransport using the given I/O buffer.
  32. *
  33. * @param Swift_Transport_IoBuffer $buf
  34. * @param Swift_Events_EventDispatcher $dispatcher
  35. */
  36. public function __construct(Swift_Transport_IoBuffer $buf, Swift_Events_EventDispatcher $dispatcher)
  37. {
  38. $this->_eventDispatcher = $dispatcher;
  39. $this->_buffer = $buf;
  40. $this->_lookupHostname();
  41. }
  42. /**
  43. * Set the name of the local domain which Swift will identify itself as.
  44. *
  45. * This should be a fully-qualified domain name and should be truly the domain
  46. * you're using.
  47. *
  48. * If your server doesn't have a domain name, use the IP in square
  49. * brackets (i.e. [127.0.0.1]).
  50. *
  51. * @param string $domain
  52. *
  53. * @return Swift_Transport_AbstractSmtpTransport
  54. */
  55. public function setLocalDomain($domain)
  56. {
  57. $this->_domain = $domain;
  58. return $this;
  59. }
  60. /**
  61. * Get the name of the domain Swift will identify as.
  62. *
  63. * @return string
  64. */
  65. public function getLocalDomain()
  66. {
  67. return $this->_domain;
  68. }
  69. /**
  70. * Sets the source IP.
  71. *
  72. * @param string $source
  73. */
  74. public function setSourceIp($source)
  75. {
  76. $this->_sourceIp=$source;
  77. }
  78. /**
  79. * Returns the IP used to connect to the destination
  80. *
  81. * @return string
  82. */
  83. public function getSourceIp()
  84. {
  85. return $this->_sourceIp;
  86. }
  87. /**
  88. * Start the SMTP connection.
  89. */
  90. public function start()
  91. {
  92. if (!$this->_started) {
  93. if ($evt = $this->_eventDispatcher->createTransportChangeEvent($this)) {
  94. $this->_eventDispatcher->dispatchEvent($evt, 'beforeTransportStarted');
  95. if ($evt->bubbleCancelled()) {
  96. return;
  97. }
  98. }
  99. try {
  100. $this->_buffer->initialize($this->_getBufferParams());
  101. } catch (Swift_TransportException $e) {
  102. $this->_throwException($e);
  103. }
  104. $this->_readGreeting();
  105. $this->_doHeloCommand();
  106. if ($evt) {
  107. $this->_eventDispatcher->dispatchEvent($evt, 'transportStarted');
  108. }
  109. $this->_started = true;
  110. }
  111. }
  112. /**
  113. * Test if an SMTP connection has been established.
  114. *
  115. * @return bool
  116. */
  117. public function isStarted()
  118. {
  119. return $this->_started;
  120. }
  121. /**
  122. * Send the given Message.
  123. *
  124. * Recipient/sender data will be retrieved from the Message API.
  125. * The return value is the number of recipients who were accepted for delivery.
  126. *
  127. * @param Swift_Mime_Message $message
  128. * @param string[] $failedRecipients An array of failures by-reference
  129. *
  130. * @return int
  131. */
  132. public function send(Swift_Mime_Message $message, &$failedRecipients = null)
  133. {
  134. $sent = 0;
  135. $failedRecipients = (array) $failedRecipients;
  136. if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) {
  137. $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed');
  138. if ($evt->bubbleCancelled()) {
  139. return 0;
  140. }
  141. }
  142. if (!$reversePath = $this->_getReversePath($message)) {
  143. throw new Swift_TransportException(
  144. 'Cannot send message without a sender address'
  145. );
  146. }
  147. $to = (array) $message->getTo();
  148. $cc = (array) $message->getCc();
  149. $bcc = (array) $message->getBcc();
  150. $message->setBcc(array());
  151. try {
  152. $sent += $this->_sendTo($message, $reversePath, $to, $failedRecipients);
  153. $sent += $this->_sendCc($message, $reversePath, $cc, $failedRecipients);
  154. $sent += $this->_sendBcc($message, $reversePath, $bcc, $failedRecipients);
  155. } catch (Exception $e) {
  156. $message->setBcc($bcc);
  157. throw $e;
  158. }
  159. $message->setBcc($bcc);
  160. if ($evt) {
  161. if ($sent == count($to) + count($cc) + count($bcc)) {
  162. $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS);
  163. } elseif ($sent > 0) {
  164. $evt->setResult(Swift_Events_SendEvent::RESULT_TENTATIVE);
  165. } else {
  166. $evt->setResult(Swift_Events_SendEvent::RESULT_FAILED);
  167. }
  168. $evt->setFailedRecipients($failedRecipients);
  169. $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed');
  170. }
  171. $message->generateId(); //Make sure a new Message ID is used
  172. return $sent;
  173. }
  174. /**
  175. * Stop the SMTP connection.
  176. */
  177. public function stop()
  178. {
  179. if ($this->_started) {
  180. if ($evt = $this->_eventDispatcher->createTransportChangeEvent($this)) {
  181. $this->_eventDispatcher->dispatchEvent($evt, 'beforeTransportStopped');
  182. if ($evt->bubbleCancelled()) {
  183. return;
  184. }
  185. }
  186. try {
  187. $this->executeCommand("QUIT\r\n", array(221));
  188. } catch (Swift_TransportException $e) {}
  189. try {
  190. $this->_buffer->terminate();
  191. if ($evt) {
  192. $this->_eventDispatcher->dispatchEvent($evt, 'transportStopped');
  193. }
  194. } catch (Swift_TransportException $e) {
  195. $this->_throwException($e);
  196. }
  197. }
  198. $this->_started = false;
  199. }
  200. /**
  201. * Register a plugin.
  202. *
  203. * @param Swift_Events_EventListener $plugin
  204. */
  205. public function registerPlugin(Swift_Events_EventListener $plugin)
  206. {
  207. $this->_eventDispatcher->bindEventListener($plugin);
  208. }
  209. /**
  210. * Reset the current mail transaction.
  211. */
  212. public function reset()
  213. {
  214. $this->executeCommand("RSET\r\n", array(250));
  215. }
  216. /**
  217. * Get the IoBuffer where read/writes are occurring.
  218. *
  219. * @return Swift_Transport_IoBuffer
  220. */
  221. public function getBuffer()
  222. {
  223. return $this->_buffer;
  224. }
  225. /**
  226. * Run a command against the buffer, expecting the given response codes.
  227. *
  228. * If no response codes are given, the response will not be validated.
  229. * If codes are given, an exception will be thrown on an invalid response.
  230. *
  231. * @param string $command
  232. * @param int[] $codes
  233. * @param string[] $failures An array of failures by-reference
  234. *
  235. * @return string
  236. */
  237. public function executeCommand($command, $codes = array(), &$failures = null)
  238. {
  239. $failures = (array) $failures;
  240. $seq = $this->_buffer->write($command);
  241. $response = $this->_getFullResponse($seq);
  242. if ($evt = $this->_eventDispatcher->createCommandEvent($this, $command, $codes)) {
  243. $this->_eventDispatcher->dispatchEvent($evt, 'commandSent');
  244. }
  245. $this->_assertResponseCode($response, $codes);
  246. return $response;
  247. }
  248. // -- Protected methods
  249. /** Read the opening SMTP greeting */
  250. protected function _readGreeting()
  251. {
  252. $this->_assertResponseCode($this->_getFullResponse(0), array(220));
  253. }
  254. /** Send the HELO welcome */
  255. protected function _doHeloCommand()
  256. {
  257. $this->executeCommand(
  258. sprintf("HELO %s\r\n", $this->_domain), array(250)
  259. );
  260. }
  261. /** Send the MAIL FROM command */
  262. protected function _doMailFromCommand($address)
  263. {
  264. $this->executeCommand(
  265. sprintf("MAIL FROM: <%s>\r\n", $address), array(250)
  266. );
  267. }
  268. /** Send the RCPT TO command */
  269. protected function _doRcptToCommand($address)
  270. {
  271. $this->executeCommand(
  272. sprintf("RCPT TO: <%s>\r\n", $address), array(250, 251, 252)
  273. );
  274. }
  275. /** Send the DATA command */
  276. protected function _doDataCommand()
  277. {
  278. $this->executeCommand("DATA\r\n", array(354));
  279. }
  280. /** Stream the contents of the message over the buffer */
  281. protected function _streamMessage(Swift_Mime_Message $message)
  282. {
  283. $this->_buffer->setWriteTranslations(array("\r\n." => "\r\n.."));
  284. try {
  285. $message->toByteStream($this->_buffer);
  286. $this->_buffer->flushBuffers();
  287. } catch (Swift_TransportException $e) {
  288. $this->_throwException($e);
  289. }
  290. $this->_buffer->setWriteTranslations(array());
  291. $this->executeCommand("\r\n.\r\n", array(250));
  292. }
  293. /** Determine the best-use reverse path for this message */
  294. protected function _getReversePath(Swift_Mime_Message $message)
  295. {
  296. $return = $message->getReturnPath();
  297. $sender = $message->getSender();
  298. $from = $message->getFrom();
  299. $path = null;
  300. if (!empty($return)) {
  301. $path = $return;
  302. } elseif (!empty($sender)) {
  303. // Don't use array_keys
  304. reset($sender); // Reset Pointer to first pos
  305. $path = key($sender); // Get key
  306. } elseif (!empty($from)) {
  307. reset($from); // Reset Pointer to first pos
  308. $path = key($from); // Get key
  309. }
  310. return $path;
  311. }
  312. /** Throw a TransportException, first sending it to any listeners */
  313. protected function _throwException(Swift_TransportException $e)
  314. {
  315. if ($evt = $this->_eventDispatcher->createTransportExceptionEvent($this, $e)) {
  316. $this->_eventDispatcher->dispatchEvent($evt, 'exceptionThrown');
  317. if (!$evt->bubbleCancelled()) {
  318. throw $e;
  319. }
  320. } else {
  321. throw $e;
  322. }
  323. }
  324. /** Throws an Exception if a response code is incorrect */
  325. protected function _assertResponseCode($response, $wanted)
  326. {
  327. list($code) = sscanf($response, '%3d');
  328. $valid = (empty($wanted) || in_array($code, $wanted));
  329. if ($evt = $this->_eventDispatcher->createResponseEvent($this, $response,
  330. $valid))
  331. {
  332. $this->_eventDispatcher->dispatchEvent($evt, 'responseReceived');
  333. }
  334. if (!$valid) {
  335. $this->_throwException(
  336. new Swift_TransportException(
  337. 'Expected response code ' . implode('/', $wanted) . ' but got code ' .
  338. '"' . $code . '", with message "' . $response . '"',
  339. $code)
  340. );
  341. }
  342. }
  343. /** Get an entire multi-line response using its sequence number */
  344. protected function _getFullResponse($seq)
  345. {
  346. $response = '';
  347. try {
  348. do {
  349. $line = $this->_buffer->readLine($seq);
  350. $response .= $line;
  351. } while (null !== $line && false !== $line && ' ' != $line{3});
  352. } catch (Swift_IoException $e) {
  353. $this->_throwException(
  354. new Swift_TransportException(
  355. $e->getMessage())
  356. );
  357. } catch (Swift_TransportException $e) {
  358. $this->_throwException($e);
  359. }
  360. return $response;
  361. }
  362. // -- Private methods
  363. /** Send an email to the given recipients from the given reverse path */
  364. private function _doMailTransaction($message, $reversePath, array $recipients, array &$failedRecipients)
  365. {
  366. $sent = 0;
  367. $this->_doMailFromCommand($reversePath);
  368. foreach ($recipients as $forwardPath) {
  369. try {
  370. $this->_doRcptToCommand($forwardPath);
  371. $sent++;
  372. } catch (Swift_TransportException $e) {
  373. $failedRecipients[] = $forwardPath;
  374. }
  375. }
  376. if ($sent != 0) {
  377. $this->_doDataCommand();
  378. $this->_streamMessage($message);
  379. } else {
  380. $this->reset();
  381. }
  382. return $sent;
  383. }
  384. /** Send a message to the given To: recipients */
  385. private function _sendTo(Swift_Mime_Message $message, $reversePath, array $to, array &$failedRecipients)
  386. {
  387. if (empty($to)) {
  388. return 0;
  389. }
  390. return $this->_doMailTransaction($message, $reversePath, array_keys($to),
  391. $failedRecipients);
  392. }
  393. /** Send a message to the given Cc: recipients */
  394. private function _sendCc(Swift_Mime_Message $message, $reversePath, array $cc, array &$failedRecipients)
  395. {
  396. if (empty($cc)) {
  397. return 0;
  398. }
  399. return $this->_doMailTransaction($message, $reversePath, array_keys($cc),
  400. $failedRecipients);
  401. }
  402. /** Send a message to all Bcc: recipients */
  403. private function _sendBcc(Swift_Mime_Message $message, $reversePath, array $bcc, array &$failedRecipients)
  404. {
  405. $sent = 0;
  406. foreach ($bcc as $forwardPath => $name) {
  407. $message->setBcc(array($forwardPath => $name));
  408. $sent += $this->_doMailTransaction(
  409. $message, $reversePath, array($forwardPath), $failedRecipients
  410. );
  411. }
  412. return $sent;
  413. }
  414. /** Try to determine the hostname of the server this is run on */
  415. private function _lookupHostname()
  416. {
  417. if (!empty($_SERVER['SERVER_NAME'])
  418. && $this->_isFqdn($_SERVER['SERVER_NAME']))
  419. {
  420. $this->_domain = $_SERVER['SERVER_NAME'];
  421. } elseif (!empty($_SERVER['SERVER_ADDR'])) {
  422. $this->_domain = sprintf('[%s]', $_SERVER['SERVER_ADDR']);
  423. }
  424. }
  425. /** Determine is the $hostname is a fully-qualified name */
  426. private function _isFqdn($hostname)
  427. {
  428. // We could do a really thorough check, but there's really no point
  429. if (false !== $dotPos = strpos($hostname, '.')) {
  430. return ($dotPos > 0) && ($dotPos != strlen($hostname) - 1);
  431. } else {
  432. return false;
  433. }
  434. }
  435. /**
  436. * Destructor.
  437. */
  438. public function __destruct()
  439. {
  440. $this->stop();
  441. }
  442. }