107 lines
2.5 KiB
PHP
107 lines
2.5 KiB
PHP
<?php
|
|
/**
|
|
* SMTP diagnostics client.
|
|
*
|
|
* @package Robotstxt_SMTP
|
|
*/
|
|
|
|
namespace Robotstxt_SMTP\Admin;
|
|
|
|
use PHPMailer\PHPMailer\SMTP;
|
|
|
|
/**
|
|
* SMTP client wrapper used for diagnostics.
|
|
*/
|
|
class SMTP_Diagnostics_Client extends SMTP {
|
|
/**
|
|
* Tracks whether the most recent command timed out.
|
|
*
|
|
* @var bool
|
|
*/
|
|
private bool $last_command_timed_out = false;
|
|
|
|
/**
|
|
* Executes an SMTP command and returns the raw reply.
|
|
*
|
|
* @param string $name Command name.
|
|
* @param string $command_string Full command string.
|
|
* @param array<int,int> $expected_codes Expected success codes.
|
|
*
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function execute_command( string $name, string $command_string, array $expected_codes = array( 250 ) ): array {
|
|
$this->last_command_timed_out = false;
|
|
$this->reset_error_state();
|
|
|
|
$expected = ! empty( $expected_codes ) ? array_map( 'intval', $expected_codes ) : array( 250 );
|
|
|
|
$success = parent::sendCommand( $name, $command_string, $expected );
|
|
|
|
if ( ! $success ) {
|
|
$this->last_command_timed_out = $this->error_indicates_timeout( parent::getError() );
|
|
}
|
|
|
|
return array(
|
|
'success' => $success,
|
|
'reply' => $this->getLastReply(),
|
|
'timed_out' => $this->last_command_timed_out,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Indicates whether the last command timed out.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function did_last_command_timeout(): bool {
|
|
return $this->last_command_timed_out;
|
|
}
|
|
|
|
/**
|
|
* Initiates STARTTLS while tracking timeout state.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function startTLS(): bool {
|
|
$this->last_command_timed_out = false;
|
|
$this->reset_error_state();
|
|
|
|
$result = parent::startTLS();
|
|
|
|
if ( ! $result ) {
|
|
$this->last_command_timed_out = $this->error_indicates_timeout( parent::getError() );
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Clears the stored error state.
|
|
*/
|
|
private function reset_error_state(): void {
|
|
parent::setError( '' );
|
|
}
|
|
|
|
/**
|
|
* Determines whether an error array represents a timeout.
|
|
*
|
|
* @param array<string, mixed> $error Error details.
|
|
*
|
|
* @return bool
|
|
*/
|
|
private function error_indicates_timeout( array $error ): bool {
|
|
foreach ( array( 'error', 'detail', 'smtp_code_ex' ) as $key ) {
|
|
if ( empty( $error[ $key ] ) ) {
|
|
continue;
|
|
}
|
|
|
|
$value = (string) $error[ $key ];
|
|
|
|
if ( false !== stripos( $value, 'timed out' ) || false !== stripos( $value, 'timed-out' ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|