blob: 41a953d9fcc8099b45c936cc7585f656298d5adb [file] [log] [blame]
<?php
declare(strict_types=1);
namespace Ddeboer\Imap;
use Ddeboer\Imap\Exception\AuthenticationFailedException;
use Ddeboer\Imap\Exception\ResourceCheckFailureException;
/**
* An IMAP server.
*/
final class Server implements ServerInterface
{
private string $hostname;
private string $port;
private string $flags;
/**
* @var mixed[]
*/
private array $parameters;
private int $options;
private int $retries;
/**
* Constructor.
*
* @param string $hostname Internet domain name or bracketed IP address
* of server
* @param string $port TCP port number
* @param string $flags Optional flags
* @param mixed[] $parameters Connection parameters
* @param int $options Connection options
* @param int $retries Retries number
*/
public function __construct(
string $hostname,
string $port = '993',
string $flags = '/imap/ssl/validate-cert',
array $parameters = [],
int $options = 0,
int $retries = 1
) {
if (!\function_exists('imap_open')) {
throw new \RuntimeException('IMAP extension must be enabled');
}
$this->hostname = $hostname;
$this->port = $port;
$this->flags = '' !== $flags ? '/' . \ltrim($flags, '/') : '';
$this->parameters = $parameters;
$this->options = $options;
$this->retries = $retries;
}
/**
* Authenticate connection.
*
* @param string $username Username
* @param string $password Password
*
* @throws AuthenticationFailedException
*/
public function authenticate(string $username, string $password): ConnectionInterface
{
$errorMessage = null;
$errorNumber = 0;
\set_error_handler(static function ($nr, $message) use (&$errorMessage, &$errorNumber): bool {
$errorMessage = $message;
$errorNumber = $nr;
return true;
});
$resource = \imap_open(
$this->getServerString(),
$username,
$password,
$this->options,
$this->retries,
$this->parameters
);
\restore_error_handler();
if (false === $resource || null !== $errorMessage) {
throw new AuthenticationFailedException(\sprintf(
'Authentication failed for user "%s"%s',
$username,
null !== $errorMessage ? ': ' . $errorMessage : ''
), $errorNumber);
}
$check = \imap_check($resource);
if (false === $check) {
throw new ResourceCheckFailureException('Resource check failure');
}
$mailbox = $check->Mailbox;
$connection = $mailbox;
$curlyPosition = \strpos($mailbox, '}');
if (false !== $curlyPosition) {
$connection = \substr($mailbox, 0, $curlyPosition + 1);
}
// These are necessary to get rid of PHP throwing IMAP errors
\imap_errors();
\imap_alerts();
return new Connection(new ImapResource($resource), $connection);
}
/**
* Glues hostname, port and flags and returns result.
*/
private function getServerString(): string
{
return \sprintf(
'{%s%s%s}',
$this->hostname,
'' !== $this->port ? ':' . $this->port : '',
$this->flags
);
}
}