update patch 1

This commit is contained in:
fiqhpratama
2024-12-02 01:18:34 +07:00
parent 453d9bb470
commit 25026b0a85
3380 changed files with 103529 additions and 363623 deletions
+1 -1
View File
@@ -31,7 +31,7 @@ abstract class AbstractApiTransport extends AbstractHttpTransport
try {
$email = MessageConverter::toEmail($message->getOriginalMessage());
} catch (\Exception $e) {
throw new RuntimeException(sprintf('Unable to send message with the "%s" transport: ', __CLASS__).$e->getMessage(), 0, $e);
throw new RuntimeException(\sprintf('Unable to send message with the "%s" transport: ', __CLASS__).$e->getMessage(), 0, $e);
}
return $this->doSendApi($message, $email, $message->getEnvelope());
+6 -5
View File
@@ -26,14 +26,15 @@ abstract class AbstractHttpTransport extends AbstractTransport
{
protected ?string $host = null;
protected ?int $port = null;
protected ?HttpClientInterface $client;
public function __construct(?HttpClientInterface $client = null, ?EventDispatcherInterface $dispatcher = null, ?LoggerInterface $logger = null)
{
$this->client = $client;
public function __construct(
protected ?HttpClientInterface $client = null,
?EventDispatcherInterface $dispatcher = null,
?LoggerInterface $logger = null,
) {
if (null === $client) {
if (!class_exists(HttpClient::class)) {
throw new \LogicException(sprintf('You cannot use "%s" as the HttpClient component is not installed. Try running "composer require symfony/http-client".', __CLASS__));
throw new \LogicException(\sprintf('You cannot use "%s" as the HttpClient component is not installed. Try running "composer require symfony/http-client".', __CLASS__));
}
$this->client = HttpClient::create();
+6 -6
View File
@@ -30,14 +30,14 @@ use Symfony\Component\Mime\RawMessage;
*/
abstract class AbstractTransport implements TransportInterface
{
private ?EventDispatcherInterface $dispatcher;
private LoggerInterface $logger;
private float $rate = 0;
private float $lastSent = 0;
public function __construct(?EventDispatcherInterface $dispatcher = null, ?LoggerInterface $logger = null)
{
$this->dispatcher = $dispatcher;
public function __construct(
private ?EventDispatcherInterface $dispatcher = null,
?LoggerInterface $logger = null,
) {
$this->logger = $logger ?? new NullLogger();
}
@@ -81,7 +81,7 @@ abstract class AbstractTransport implements TransportInterface
$message = $event->getMessage();
if ($message instanceof TemplatedEmail && !$message->isRendered()) {
throw new LogicException(sprintf('You must configure a "%s" when a "%s" instance has a text or HTML template set.', BodyRendererInterface::class, get_debug_type($message)));
throw new LogicException(\sprintf('You must configure a "%s" when a "%s" instance has a text or HTML template set.', BodyRendererInterface::class, get_debug_type($message)));
}
$sentMessage = new SentMessage($message, $envelope);
@@ -128,7 +128,7 @@ abstract class AbstractTransport implements TransportInterface
$sleep = (1 / $this->rate) - (microtime(true) - $this->lastSent);
if (0 < $sleep) {
$this->logger->debug(sprintf('Email transport "%s" sleeps for %.2f seconds', __CLASS__, $sleep));
$this->logger->debug(\sprintf('Email transport "%s" sleeps for %.2f seconds', __CLASS__, $sleep));
usleep((int) ($sleep * 1000000));
}
$this->lastSent = microtime(true);
@@ -21,15 +21,11 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
*/
abstract class AbstractTransportFactory implements TransportFactoryInterface
{
protected ?EventDispatcherInterface $dispatcher;
protected ?HttpClientInterface $client;
protected ?LoggerInterface $logger;
public function __construct(?EventDispatcherInterface $dispatcher = null, ?HttpClientInterface $client = null, ?LoggerInterface $logger = null)
{
$this->dispatcher = $dispatcher;
$this->client = $client;
$this->logger = $logger;
public function __construct(
protected ?EventDispatcherInterface $dispatcher = null,
protected ?HttpClientInterface $client = null,
protected ?LoggerInterface $logger = null,
) {
}
public function supports(Dsn $dsn): bool
+8 -15
View File
@@ -18,21 +18,14 @@ use Symfony\Component\Mailer\Exception\InvalidArgumentException;
*/
final class Dsn
{
private string $scheme;
private string $host;
private ?string $user;
private ?string $password;
private ?int $port;
private array $options;
public function __construct(string $scheme, string $host, ?string $user = null, #[\SensitiveParameter] ?string $password = null, ?int $port = null, array $options = [])
{
$this->scheme = $scheme;
$this->host = $host;
$this->user = $user;
$this->password = $password;
$this->port = $port;
$this->options = $options;
public function __construct(
private string $scheme,
private string $host,
private ?string $user = null,
#[\SensitiveParameter] private ?string $password = null,
private ?int $port = null,
private array $options = [],
) {
}
public static function fromString(#[\SensitiveParameter] string $dsn): self
+6 -8
View File
@@ -28,22 +28,20 @@ class RoundRobinTransport implements TransportInterface
* @var \SplObjectStorage<TransportInterface, float>
*/
private \SplObjectStorage $deadTransports;
private array $transports = [];
private int $retryPeriod;
private int $cursor = -1;
/**
* @param TransportInterface[] $transports
*/
public function __construct(array $transports, int $retryPeriod = 60)
{
public function __construct(
private array $transports,
private int $retryPeriod = 60,
) {
if (!$transports) {
throw new TransportException(sprintf('"%s" must have at least one transport configured.', static::class));
throw new TransportException(\sprintf('"%s" must have at least one transport configured.', static::class));
}
$this->transports = $transports;
$this->deadTransports = new \SplObjectStorage();
$this->retryPeriod = $retryPeriod;
}
public function send(RawMessage $message, ?Envelope $envelope = null): ?SentMessage
@@ -55,7 +53,7 @@ class RoundRobinTransport implements TransportInterface
return $transport->send($message, $envelope);
} catch (TransportExceptionInterface $e) {
$exception ??= new TransportException('All transports failed.');
$exception->appendDebug(sprintf("Transport \"%s\": %s\n", $transport, $e->getDebug()));
$exception->appendDebug(\sprintf("Transport \"%s\": %s\n", $transport, $e->getDebug()));
$this->deadTransports[$transport] = microtime(true);
}
}
+3 -3
View File
@@ -55,7 +55,7 @@ class SendmailTransport extends AbstractTransport
if (null !== $command) {
if (!str_contains($command, ' -bs') && !str_contains($command, ' -t')) {
throw new \InvalidArgumentException(sprintf('Unsupported sendmail command flags "%s"; must be one of "-bs" or "-t" but can include additional flags.', $command));
throw new \InvalidArgumentException(\sprintf('Unsupported sendmail command flags "%s"; must be one of "-bs" or "-t" but can include additional flags.', $command));
}
$this->command = $command;
@@ -89,7 +89,7 @@ class SendmailTransport extends AbstractTransport
protected function doSend(SentMessage $message): void
{
$this->getLogger()->debug(sprintf('Email transport "%s" starting', __CLASS__));
$this->getLogger()->debug(\sprintf('Email transport "%s" starting', __CLASS__));
$command = $this->command;
@@ -119,6 +119,6 @@ class SendmailTransport extends AbstractTransport
$this->stream->flush();
$this->stream->terminate();
$this->getLogger()->debug(sprintf('Email transport "%s" stopped', __CLASS__));
$this->getLogger()->debug(\sprintf('Email transport "%s" stopped', __CLASS__));
}
}
@@ -34,7 +34,7 @@ class CramMd5Authenticator implements AuthenticatorInterface
$challenge = $client->executeCommand("AUTH CRAM-MD5\r\n", [334]);
$challenge = base64_decode(substr($challenge, 4));
$message = base64_encode($client->getUsername().' '.$this->getResponse($client->getPassword(), $challenge));
$client->executeCommand(sprintf("%s\r\n", $message), [235]);
$client->executeCommand(\sprintf("%s\r\n", $message), [235]);
}
/**
@@ -58,8 +58,7 @@ class CramMd5Authenticator implements AuthenticatorInterface
$kopad = substr($secret, 0, 64) ^ str_repeat(\chr(0x5C), 64);
$inner = pack('H32', md5($kipad.$challenge));
$digest = md5($kopad.$inner);
return $digest;
return md5($kopad.$inner);
}
}
@@ -31,7 +31,7 @@ class LoginAuthenticator implements AuthenticatorInterface
public function authenticate(EsmtpTransport $client): void
{
$client->executeCommand("AUTH LOGIN\r\n", [334]);
$client->executeCommand(sprintf("%s\r\n", base64_encode($client->getUsername())), [334]);
$client->executeCommand(sprintf("%s\r\n", base64_encode($client->getPassword())), [235]);
$client->executeCommand(\sprintf("%s\r\n", base64_encode($client->getUsername())), [334]);
$client->executeCommand(\sprintf("%s\r\n", base64_encode($client->getPassword())), [235]);
}
}
@@ -30,6 +30,6 @@ class PlainAuthenticator implements AuthenticatorInterface
*/
public function authenticate(EsmtpTransport $client): void
{
$client->executeCommand(sprintf("AUTH PLAIN %s\r\n", base64_encode($client->getUsername().\chr(0).$client->getUsername().\chr(0).$client->getPassword())), [235]);
$client->executeCommand(\sprintf("AUTH PLAIN %s\r\n", base64_encode($client->getUsername().\chr(0).$client->getUsername().\chr(0).$client->getPassword())), [235]);
}
}
+11 -6
View File
@@ -142,10 +142,10 @@ class EsmtpTransport extends SmtpTransport
private function doEhloCommand(): string
{
try {
$response = $this->executeCommand(sprintf("EHLO %s\r\n", $this->getLocalDomain()), [250]);
$response = $this->executeCommand(\sprintf("EHLO %s\r\n", $this->getLocalDomain()), [250]);
} catch (TransportExceptionInterface $e) {
try {
return parent::executeCommand(sprintf("HELO %s\r\n", $this->getLocalDomain()), [250]);
return parent::executeCommand(\sprintf("HELO %s\r\n", $this->getLocalDomain()), [250]);
} catch (TransportExceptionInterface $ex) {
if (!$ex->getCode()) {
throw $e;
@@ -169,7 +169,7 @@ class EsmtpTransport extends SmtpTransport
throw new TransportException('Unable to connect with STARTTLS.');
}
$response = $this->executeCommand(sprintf("EHLO %s\r\n", $this->getLocalDomain()), [250]);
$response = $this->executeCommand(\sprintf("EHLO %s\r\n", $this->getLocalDomain()), [250]);
$this->capabilities = $this->parseCapabilities($response);
}
@@ -195,6 +195,11 @@ class EsmtpTransport extends SmtpTransport
return $capabilities;
}
protected function serverSupportsSmtpUtf8(): bool
{
return \array_key_exists('SMTPUTF8', $this->capabilities);
}
private function handleAuth(array $modes): void
{
if (!$this->username) {
@@ -231,12 +236,12 @@ class EsmtpTransport extends SmtpTransport
}
if (!$authNames) {
throw new TransportException(sprintf('Failed to find an authenticator supported by the SMTP server, which currently supports: "%s".', implode('", "', $modes)), $code ?: 504);
throw new TransportException(\sprintf('Failed to find an authenticator supported by the SMTP server, which currently supports: "%s".', implode('", "', $modes)), $code ?: 504);
}
$message = sprintf('Failed to authenticate on SMTP server with username "%s" using the following authenticators: "%s".', $this->username, implode('", "', $authNames));
$message = \sprintf('Failed to authenticate on SMTP server with username "%s" using the following authenticators: "%s".', $this->username, implode('", "', $authNames));
foreach ($errors as $name => $error) {
$message .= sprintf(' Authenticator "%s" returned "%s".', $name, $error);
$message .= \sprintf(' Authenticator "%s" returned "%s".', $name, $error);
}
throw new TransportException($message, $code ?: 535);
@@ -11,6 +11,7 @@
namespace Symfony\Component\Mailer\Transport\Smtp;
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\Smtp\Stream\SocketStream;
@@ -23,6 +24,10 @@ final class EsmtpTransportFactory extends AbstractTransportFactory
{
public function create(Dsn $dsn): TransportInterface
{
if (!\in_array($dsn->getScheme(), $this->getSupportedSchemes(), true)) {
throw new UnsupportedSchemeException($dsn, 'smtp', $this->getSupportedSchemes());
}
$autoTls = '' === $dsn->getOption('auto_tls') || filter_var($dsn->getOption('auto_tls', true), \FILTER_VALIDATE_BOOL);
$tls = 'smtps' === $dsn->getScheme() ? true : ($autoTls ? null : false);
$port = $dsn->getPort(0);
+25 -16
View File
@@ -14,6 +14,7 @@ namespace Symfony\Component\Mailer\Transport\Smtp;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Mailer\Envelope;
use Symfony\Component\Mailer\Exception\InvalidArgumentException;
use Symfony\Component\Mailer\Exception\LogicException;
use Symfony\Component\Mailer\Exception\TransportException;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
@@ -171,7 +172,7 @@ class SmtpTransport extends AbstractTransport
public function __toString(): string
{
if ($this->stream instanceof SocketStream) {
$name = sprintf('smtp%s://%s', ($tls = $this->stream->isTLS()) ? 's' : '', $this->stream->getHost());
$name = \sprintf('smtp%s://%s', ($tls = $this->stream->isTLS()) ? 's' : '', $this->stream->getHost());
$port = $this->stream->getPort();
if (!(25 === $port || ($tls && 465 === $port))) {
$name .= ':'.$port;
@@ -211,7 +212,7 @@ class SmtpTransport extends AbstractTransport
try {
$envelope = $message->getEnvelope();
$this->doMailFromCommand($envelope->getSender()->getEncodedAddress());
$this->doMailFromCommand($envelope->getSender()->getEncodedAddress(), $envelope->anyAddressHasUnicodeLocalpart());
foreach ($envelope->getRecipients() as $recipient) {
$this->doRcptToCommand($recipient->getEncodedAddress());
}
@@ -227,7 +228,7 @@ class SmtpTransport extends AbstractTransport
} catch (\Exception $e) {
$this->stream->terminate();
$this->started = false;
$this->getLogger()->debug(sprintf('Email transport "%s" stopped', __CLASS__));
$this->getLogger()->debug(\sprintf('Email transport "%s" stopped', __CLASS__));
throw $e;
}
$mtaResult = $this->executeCommand("\r\n.\r\n", [250]);
@@ -244,19 +245,27 @@ class SmtpTransport extends AbstractTransport
}
}
private function doHeloCommand(): void
protected function serverSupportsSmtpUtf8(): bool
{
$this->executeCommand(sprintf("HELO %s\r\n", $this->domain), [250]);
return false;
}
private function doMailFromCommand(string $address): void
private function doHeloCommand(): void
{
$this->executeCommand(sprintf("MAIL FROM:<%s>\r\n", $address), [250]);
$this->executeCommand(\sprintf("HELO %s\r\n", $this->domain), [250]);
}
private function doMailFromCommand(string $address, bool $smtputf8): void
{
if ($smtputf8 && !$this->serverSupportsSmtpUtf8()) {
throw new InvalidArgumentException('Invalid addresses: non-ASCII characters not supported in local-part of email.');
}
$this->executeCommand(\sprintf("MAIL FROM:<%s>%s\r\n", $address, $smtputf8 ? ' SMTPUTF8' : ''), [250]);
}
private function doRcptToCommand(string $address): void
{
$this->executeCommand(sprintf("RCPT TO:<%s>\r\n", $address), [250, 251, 252]);
$this->executeCommand(\sprintf("RCPT TO:<%s>\r\n", $address), [250, 251, 252]);
}
public function start(): void
@@ -265,7 +274,7 @@ class SmtpTransport extends AbstractTransport
return;
}
$this->getLogger()->debug(sprintf('Email transport "%s" starting', __CLASS__));
$this->getLogger()->debug(\sprintf('Email transport "%s" starting', __CLASS__));
$this->stream->initialize();
$this->assertResponseCode($this->getFullResponse(), [220]);
@@ -273,7 +282,7 @@ class SmtpTransport extends AbstractTransport
$this->started = true;
$this->lastMessageTime = 0;
$this->getLogger()->debug(sprintf('Email transport "%s" started', __CLASS__));
$this->getLogger()->debug(\sprintf('Email transport "%s" started', __CLASS__));
}
/**
@@ -289,7 +298,7 @@ class SmtpTransport extends AbstractTransport
return;
}
$this->getLogger()->debug(sprintf('Email transport "%s" stopping', __CLASS__));
$this->getLogger()->debug(\sprintf('Email transport "%s" stopping', __CLASS__));
try {
$this->executeCommand("QUIT\r\n", [221]);
@@ -297,7 +306,7 @@ class SmtpTransport extends AbstractTransport
} finally {
$this->stream->terminate();
$this->started = false;
$this->getLogger()->debug(sprintf('Email transport "%s" stopped', __CLASS__));
$this->getLogger()->debug(\sprintf('Email transport "%s" stopped', __CLASS__));
}
}
@@ -327,10 +336,10 @@ class SmtpTransport extends AbstractTransport
$valid = \in_array($code, $codes);
if (!$valid || !$response) {
$codeStr = $code ? sprintf('code "%s"', $code) : 'empty code';
$responseStr = $response ? sprintf(', with message "%s"', trim($response)) : '';
$codeStr = $code ? \sprintf('code "%s"', $code) : 'empty code';
$responseStr = $response ? \sprintf(', with message "%s"', trim($response)) : '';
throw new UnexpectedResponseException(sprintf('Expected response code "%s" but got ', implode('/', $codes)).$codeStr.$responseStr.'.', $code ?: 0);
throw new UnexpectedResponseException(\sprintf('Expected response code "%s" but got ', implode('/', $codes)).$codeStr.$responseStr.'.', $code ?: 0);
}
}
@@ -359,7 +368,7 @@ class SmtpTransport extends AbstractTransport
$this->stop();
if (0 < $sleep = $this->restartThresholdSleep) {
$this->getLogger()->debug(sprintf('Email transport "%s" sleeps for %d seconds after stopping', __CLASS__, $sleep));
$this->getLogger()->debug(\sprintf('Email transport "%s" sleeps for %d seconds after stopping', __CLASS__, $sleep));
sleep($sleep);
}
@@ -37,9 +37,9 @@ abstract class AbstractStream
public function write(string $bytes, bool $debug = true): void
{
if ($debug) {
$timestamp = date('c');
$timestamp = (new \DateTimeImmutable())->format('Y-m-d\TH:i:s.up');
foreach (explode("\n", trim($bytes)) as $line) {
$this->debug .= sprintf("[%s] > %s\n", $timestamp, $line);
$this->debug .= \sprintf("[%s] > %s\n", $timestamp, $line);
}
}
@@ -83,17 +83,17 @@ abstract class AbstractStream
if ('' === $line || false === $line) {
$metas = stream_get_meta_data($this->out);
if ($metas['timed_out']) {
throw new TransportException(sprintf('Connection to "%s" timed out.', $this->getReadConnectionDescription()));
throw new TransportException(\sprintf('Connection to "%s" timed out.', $this->getReadConnectionDescription()));
}
if ($metas['eof']) {
throw new TransportException(sprintf('Connection to "%s" has been closed unexpectedly.', $this->getReadConnectionDescription()));
throw new TransportException(\sprintf('Connection to "%s" has been closed unexpectedly.', $this->getReadConnectionDescription()));
}
if (false === $line) {
throw new TransportException(sprintf('Unable to read from connection to "%s": ', $this->getReadConnectionDescription()).error_get_last()['message']);
throw new TransportException(\sprintf('Unable to read from connection to "%s": ', $this->getReadConnectionDescription()).error_get_last()['message']);
}
}
$this->debug .= sprintf('[%s] < %s', date('c'), $line);
$this->debug .= \sprintf('[%s] < %s', (new \DateTimeImmutable())->format('Y-m-d\TH:i:s.up'), $line);
return $line;
}
@@ -151,7 +151,7 @@ final class SocketStream extends AbstractStream
$timeout = $this->getTimeout();
set_error_handler(function ($type, $msg) {
throw new TransportException(sprintf('Connection could not be established with host "%s": ', $this->url).$msg);
throw new TransportException(\sprintf('Connection could not be established with host "%s": ', $this->url).$msg);
});
try {
$this->stream = stream_socket_client($this->url, $errno, $errstr, $timeout, \STREAM_CLIENT_CONNECT, $streamContext);
+2 -2
View File
@@ -40,7 +40,7 @@ final class Transports implements TransportInterface
}
if (!$this->transports) {
throw new LogicException(sprintf('"%s" must have at least one transport configured.', __CLASS__));
throw new LogicException(\sprintf('"%s" must have at least one transport configured.', __CLASS__));
}
}
@@ -56,7 +56,7 @@ final class Transports implements TransportInterface
$headers->remove('X-Transport');
if (!isset($this->transports[$transport])) {
throw new InvalidArgumentException(sprintf('The "%s" transport does not exist (available transports: "%s").', $transport, implode('", "', array_keys($this->transports))));
throw new InvalidArgumentException(\sprintf('The "%s" transport does not exist (available transports: "%s").', $transport, implode('", "', array_keys($this->transports))));
}
try {