public function connect($host, $port = null, $timeout = 30, $options = [])
{
static $streamok;
//This is enabled by default since 5.0.0 but some providers disable it
//Check this once and cache the result
if (is_null($streamok)) {
$streamok = function_exists('stream_socket_client');
}
// Clear errors to avoid confusion
$this->setError('');
// Make sure we are __not__ connected
if ($this->connected()) {
// Already connected, generate error
$this->setError('Already connected to a server');
return false;
}
if (empty($port)) {
$port = self::DEFAULT_SMTP_PORT;
}
// Connect to the SMTP server
$this->edebug("Connection: opening to {$host}:{$port}, timeout={$timeout}, options=" . var_export($options, true), self::DEBUG_CONNECTION);
$errno = 0;
$errstr = '';
if ($streamok) {
$socket_context = stream_context_create($options);
//Suppress errors; connection failures are handled at a higher level
$this->smtp_conn = @stream_socket_client($host . ":" . $port, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $socket_context);
} else {
//Fall back to fsockopen which should work in more places, but is missing some features
$this->edebug("Connection: stream_socket_client not available, falling back to fsockopen", self::DEBUG_CONNECTION);
$this->smtp_conn = fsockopen($host, $port, $errno, $errstr, $timeout);
}
// Verify we connected properly
if (!is_resource($this->smtp_conn)) {
$this->setError('Failed to connect to server', $errno, $errstr);
$this->edebug('SMTP ERROR: ' . $this->error['error'] . ": {$errstr} ({$errno})", self::DEBUG_CLIENT);
return false;
}
$this->edebug('Connection: opened', self::DEBUG_CONNECTION);
// SMTP server can take longer to respond, give longer timeout for first read
// Windows does not have support for this timeout function
if (substr(PHP_OS, 0, 3) != 'WIN') {
$max = ini_get('max_execution_time');
// Don't bother if unlimited
if (0 != $max and $timeout > $max) {
@set_time_limit($timeout);
}
stream_set_timeout($this->smtp_conn, $timeout, 0);
}
// Get any announcement
$announce = $this->get_lines();
$this->edebug('SERVER -> CLIENT: ' . $announce, self::DEBUG_SERVER);
return true;
}