This commit is contained in:
Javier Casares 2025-11-26 08:24:18 +00:00
commit c98dcb7b50
9 changed files with 5952 additions and 0 deletions

View file

@ -0,0 +1,107 @@
<?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;
}
}