|
<?php |
|
/** |
|
* Servicio para realizar consultas WHOIS de dominios. |
|
* |
|
* Esta clase implementa el patrón Singleton para garantizar que solo exista |
|
* una instancia del servicio, evitando consultas innecesarias y reduciendo el |
|
* consumo de recursos. |
|
* |
|
* @author Luis Cortés |
|
*/ |
|
class WhoisService { |
|
private static ?WhoisService $instance = null; |
|
private array $whoisServers; |
|
|
|
/** |
|
* Constructor privado para inicializar servidores WHOIS. |
|
* Se utiliza para cargar una lista de servidores para diferentes extensiones de dominio. |
|
*/ |
|
private function __construct() { |
|
$this->whoisServers = [ |
|
'.com' => ['whois.crsnic.net', 'No match for'], |
|
'.net' => ['whois.crsnic.net', 'No match for'], |
|
'.bo' => ['whois.nic.bo', 'solo acepta consultas con dominios .bo'], |
|
'.mx' => ['whois.nic.mx', 'No_Se_Encontro_El_Objeto'], |
|
'.pe' => ['whois.nic.pe', 'No Object Found'], |
|
'.co' => ['whois.nic.co', 'Not found'], |
|
'.es' => ['whois.nic.es', 'Not found'], |
|
'.uk' => ['whois.nic.uk', 'No match for'], |
|
'.org' => ['whois.pir.org', 'NOT FOUND'], |
|
'.info'=> ['whois.afilias.net', 'NOT FOUND'], |
|
'.io' => ['whois.nic.io', 'NOT FOUND'], |
|
'.ai' => ['whois.ai', 'No Object Found'], |
|
'.us' => ['whois.nic.us', 'Not found'], |
|
'.ca' => ['whois.cira.ca', 'Domain status: available'], |
|
'.fr' => ['whois.nic.fr', 'No entries found'], |
|
'.it' => ['whois.nic.it', 'AVAILABLE'], |
|
'.au' => ['whois.auda.org.au', 'No Data Found'] |
|
]; |
|
} |
|
|
|
/** |
|
* Devuelve la instancia única del servicio WHOIS (Singleton). |
|
* |
|
* Se utiliza el patrón Singleton para evitar instancias duplicadas, |
|
* asegurando que haya una única fuente de verdad para las consultas WHOIS. |
|
* |
|
* @return WhoisService |
|
*/ |
|
public static function getInstance(): WhoisService { |
|
return self::$instance ??= new WhoisService(); |
|
} |
|
|
|
/** |
|
* Realiza una consulta WHOIS a un servidor especificado. |
|
* |
|
* @param string $domain Nombre de dominio sin extensión. |
|
* @param string $extension Extensión de dominio (e.g. .com, .net). |
|
* @return string Mensaje HTML con el resultado de la consulta. |
|
* @throws InvalidArgumentException Si la extensión del dominio no está soportada. |
|
*/ |
|
public function performWhoisQuery(string $domain, string $extension): string { |
|
$serverInfo = $this->whoisServers[$extension] ?? null; |
|
if (!$serverInfo) { |
|
throw new InvalidArgumentException("Unsupported domain extension: $extension"); |
|
} |
|
[$whoisServer, $notFoundMsg] = $serverInfo; |
|
|
|
$response = $this->queryWhoisServer($whoisServer, $domain . $extension); |
|
return $this->generateResponse($domain . $extension, $response, $notFoundMsg); |
|
} |
|
|
|
/** |
|
* Realiza la consulta al servidor WHOIS. |
|
* |
|
* Este método establece una conexión socket al servidor WHOIS especificado |
|
* y realiza la consulta de disponibilidad del dominio. Devuelve el resultado |
|
* completo de la consulta. |
|
* |
|
* @param string $whoisServer Servidor WHOIS a consultar. |
|
* @param string $domain Nombre de dominio completo (con extensión). |
|
* @return array Estado de la consulta y datos recibidos. |
|
*/ |
|
private function queryWhoisServer(string $whoisServer, string $domain): array { |
|
$response = ['status' => false, 'data' => '']; |
|
|
|
try { |
|
$sock = @fsockopen($whoisServer, 43, $errno, $errstr, 10); |
|
if ($sock) { |
|
fwrite($sock, $domain . "\r\n"); |
|
while (!feof($sock)) { |
|
$response['data'] .= fgets($sock, 128); |
|
} |
|
fclose($sock); |
|
$response['status'] = true; |
|
} |
|
} catch (Throwable $e) { |
|
error_log("WHOIS error: " . $e->getMessage()); |
|
} |
|
|
|
return $response; |
|
} |
|
|
|
/** |
|
* Genera el mensaje de respuesta basado en el resultado de la consulta. |
|
* |
|
* Determina si el dominio está disponible comparando el resultado de la |
|
* consulta con el mensaje que indica que no se encontró el dominio. |
|
* |
|
* @param string $domain Nombre de dominio consultado. |
|
* @param array $result Resultado de la consulta (estado y datos). |
|
* @param string $notFoundMsg Mensaje que indica que el dominio está disponible. |
|
* @return string HTML con la respuesta de dominio disponible o no. |
|
*/ |
|
private function generateResponse(string $domain, array $result, string $notFoundMsg): string { |
|
$available = $result['status'] && str_contains($result['data'], $notFoundMsg); |
|
$whoisData = htmlspecialchars($result['data'] ?? ''); |
|
|
|
return $available |
|
? $this->successTemplate($domain) |
|
: $this->errorTemplate($domain, $whoisData); |
|
} |
|
|
|
/** |
|
* Plantilla de mensaje para dominios disponibles. |
|
* |
|
* @param string $domain |
|
* @return string HTML con mensaje de dominio disponible. |
|
*/ |
|
private function successTemplate(string $domain): string { |
|
return '<div class="alert alert-success alert-dismissible" role="alert">' |
|
. '<button type="button" class="close" data-dismiss="alert">×</button>' |
|
. '<span>Yes! Your domain <strong>' . htmlspecialchars($domain) . '</strong> is available. Buy it now!</span>' |
|
. '<button class="btn btn-success ml-3" type="button">Buy this domain</button></div>'; |
|
} |
|
|
|
/** |
|
* Plantilla de mensaje para dominios no disponibles. |
|
* |
|
* @param string $domain |
|
* @param string $whoisData |
|
* @return string HTML con mensaje de dominio no disponible. |
|
*/ |
|
private function errorTemplate(string $domain, string $whoisData): string { |
|
return '<div class="alert alert-light alert-dismissible" role="alert">' |
|
. '<button type="button" class="close" data-dismiss="alert">×</button>' |
|
. '<span>Sorry, <strong>' . htmlspecialchars($domain) . '</strong> is taken.</span>' |
|
. '<a class="btn btn-danger ml-3" data-toggle="collapse" href="#collapseDetails">View details</a>' |
|
. '<div class="collapse" id="collapseDetails"><pre>' . $whoisData . '</pre></div></div>'; |
|
} |
|
} |
|
|
|
// Uso del servicio para manejar la entrada de usuario y ejecutar consultas WHOIS. |
|
try { |
|
$domainName = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING) ?? ''; |
|
$domainExt = filter_input(INPUT_POST, 'Ext', FILTER_SANITIZE_STRING) ?? ''; |
|
if ($domainName && $domainExt) { |
|
$cleanDomain = preg_replace('/^(www\\.|http:\/\/|\/)/', '', $domainName); |
|
echo WhoisService::getInstance()->performWhoisQuery($cleanDomain, $domainExt); |
|
} |
|
} catch (Exception $e) { |
|
echo '<div class="alert alert-danger">Error: ' . htmlspecialchars($e->getMessage()) . '</div>'; |
|
} |