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

/vendor/nette/mail/src/Mail/SmtpMailer.php

https://gitlab.com/kubinos/writeoff
PHP | 195 lines | 123 code | 33 blank | 39 comment | 22 complexity | 47f123db4a2646f4f0ef29bceae0661b MD5 | raw file
  1. <?php
  2. /**
  3. * This file is part of the Nette Framework (https://nette.org)
  4. * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
  5. */
  6. namespace Nette\Mail;
  7. use Nette;
  8. /**
  9. * Sends emails via the SMTP server.
  10. */
  11. class SmtpMailer extends Nette\Object implements IMailer
  12. {
  13. /** @var resource */
  14. private $connection;
  15. /** @var string */
  16. private $host;
  17. /** @var int */
  18. private $port;
  19. /** @var string */
  20. private $username;
  21. /** @var string */
  22. private $password;
  23. /** @var string ssl | tls | (empty) */
  24. private $secure;
  25. /** @var int */
  26. private $timeout;
  27. /** @var bool */
  28. private $persistent;
  29. public function __construct(array $options = array())
  30. {
  31. if (isset($options['host'])) {
  32. $this->host = $options['host'];
  33. $this->port = isset($options['port']) ? (int) $options['port'] : NULL;
  34. } else {
  35. $this->host = ini_get('SMTP');
  36. $this->port = (int) ini_get('smtp_port');
  37. }
  38. $this->username = isset($options['username']) ? $options['username'] : '';
  39. $this->password = isset($options['password']) ? $options['password'] : '';
  40. $this->secure = isset($options['secure']) ? $options['secure'] : '';
  41. $this->timeout = isset($options['timeout']) ? (int) $options['timeout'] : 20;
  42. if (!$this->port) {
  43. $this->port = $this->secure === 'ssl' ? 465 : 25;
  44. }
  45. $this->persistent = !empty($options['persistent']);
  46. }
  47. /**
  48. * Sends email.
  49. * @return void
  50. * @throws SmtpException
  51. */
  52. public function send(Message $mail)
  53. {
  54. $mail = clone $mail;
  55. try {
  56. if (!$this->connection) {
  57. $this->connect();
  58. }
  59. if (($from = $mail->getHeader('Return-Path'))
  60. || ($from = key($mail->getHeader('From')))
  61. ) {
  62. $this->write("MAIL FROM:<$from>", 250);
  63. }
  64. foreach (array_merge(
  65. (array) $mail->getHeader('To'),
  66. (array) $mail->getHeader('Cc'),
  67. (array) $mail->getHeader('Bcc')
  68. ) as $email => $name) {
  69. $this->write("RCPT TO:<$email>", array(250, 251));
  70. }
  71. $mail->setHeader('Bcc', NULL);
  72. $data = $mail->generateMessage();
  73. $this->write('DATA', 354);
  74. $data = preg_replace('#^\.#m', '..', $data);
  75. $this->write($data);
  76. $this->write('.', 250);
  77. if (!$this->persistent) {
  78. $this->write('QUIT', 221);
  79. $this->disconnect();
  80. }
  81. } catch (SmtpException $e) {
  82. if ($this->connection) {
  83. $this->disconnect();
  84. }
  85. throw $e;
  86. }
  87. }
  88. /**
  89. * Connects and authenticates to SMTP server.
  90. * @return void
  91. */
  92. protected function connect()
  93. {
  94. $this->connection = @stream_socket_client( // @ is escalated to exception
  95. ($this->secure === 'ssl' ? 'ssl://' : '') . $this->host . ':' . $this->port,
  96. $errno, $error, $this->timeout
  97. );
  98. if (!$this->connection) {
  99. throw new SmtpException($error, $errno);
  100. }
  101. stream_set_timeout($this->connection, $this->timeout, 0);
  102. $this->read(); // greeting
  103. $self = isset($_SERVER['HTTP_HOST']) && preg_match('#^[\w.-]+\z#', $_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost';
  104. $this->write("EHLO $self");
  105. if ((int) $this->read() !== 250) {
  106. $this->write("HELO $self", 250);
  107. }
  108. if ($this->secure === 'tls') {
  109. $this->write('STARTTLS', 220);
  110. if (!stream_socket_enable_crypto($this->connection, TRUE, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
  111. throw new SmtpException('Unable to connect via TLS.');
  112. }
  113. $this->write("EHLO $self", 250);
  114. }
  115. if ($this->username != NULL && $this->password != NULL) {
  116. $this->write('AUTH LOGIN', 334);
  117. $this->write(base64_encode($this->username), 334, 'username');
  118. $this->write(base64_encode($this->password), 235, 'password');
  119. }
  120. }
  121. /**
  122. * Disconnects from SMTP server.
  123. * @return void
  124. */
  125. protected function disconnect()
  126. {
  127. fclose($this->connection);
  128. $this->connection = NULL;
  129. }
  130. /**
  131. * Writes data to server and checks response against expected code if some provided.
  132. * @param string
  133. * @param int response code
  134. * @param string error message
  135. * @return void
  136. */
  137. protected function write($line, $expectedCode = NULL, $message = NULL)
  138. {
  139. fwrite($this->connection, $line . Message::EOL);
  140. if ($expectedCode) {
  141. $response = $this->read();
  142. if (!in_array((int) $response, (array) $expectedCode, TRUE)) {
  143. throw new SmtpException('SMTP server did not accept ' . ($message ? $message : $line) . ' with error: ' . trim($response));
  144. }
  145. }
  146. }
  147. /**
  148. * Reads response from server.
  149. * @return string
  150. */
  151. protected function read()
  152. {
  153. $s = '';
  154. while (($line = fgets($this->connection, 1e3)) != NULL) { // intentionally ==
  155. $s .= $line;
  156. if (substr($line, 3, 1) === ' ') {
  157. break;
  158. }
  159. }
  160. return $s;
  161. }
  162. }