Telegram bot que monitorea el dominio

Hola a los residentes de Habr.

En el proceso de aprendizaje de PHP, se me ocurrió la idea de practicar escribir algún bot en PHP, sin usar frameworks.

La elección recayó en el bot, que recibirá información sobre la vida del dominio (whois), luego obtendrá la fecha de registro desde allí y agregará este dominio a la base de datos (mysql), con el posterior enlace al usuario y notificación en telegrama.

El código fuente en mi repositorio en gita.

Quería usar la estructura MVC , que en mi opinión no era del todo cierto, ya que la vista no estaba involucrada y esto ya no se puede llamar mvc, pero bueno ...

Estructura de aplicación




Controladores : un enlace que conecta el modelo y la lógica de la aplicación.
Modelos : archivos de la "lógica de negocios" de la aplicación (intenté "meter" todo el sql aquí).
Core : archivos "core" de la aplicación.
Biblioteca : las bibliotecas utilizan la biblioteca para analizar la información del nombre de dominio.

Enrutamiento


El archivo de enrutamiento (routes.php) se encuentra en el directorio central .
Se agregan 2 direcciones en la aplicación:

/ bot : Telegramm va a esta dirección (debe configurar el webhook en esta dirección uri / bot).
/ check : en esta dirección, wget rompe con cron 1 por día (a las 12 en punto), más sobre eso más adelante.

Controlador de bot


Tras la transición a este controlador, obtenemos los valores del cuerpo de la solicitud POST y lo decodificamos como una matriz.

json_decode(file_get_contents('php://input'), JSON_OBJECT_AS_ARRAY); 

php: // input - obtiene el cuerpo de la solicitud POST

Checkercontroller


Tras la transición a este controlador, se activa un script que verifica la caducidad de todos los dominios y certificados SSL agregados, con el intervalo:

  • fecha actual
  • 2 dias
  • 7 dias
  • 30 dias

Y envía notificaciones si finaliza la fecha de vencimiento del dominio y el certificado SSL.

Agregar usuarios


Cuando el usuario escribe un mensaje en el bot de telegramas webhook, lo envía a nuestro sitio web, luego recibimos un mensaje en formato json, que necesitamos decodificar y convertir a una matriz para un trabajo posterior.



Trabajaremos con la matriz de mensajes.

Obtener del mensaje de matriz ['chat'] : id , first_name
donde:

id - id de chat
first_name - Nombre de usuario

Y de la matriz de mensaje ['texto'] , recibimos el comando enviado por el usuario.

Encontramos al usuario en la tabla de usuarios, si no está allí, crea

 //   $sql= "SELECT user_id FROM users WHERE chat_id=?"; $stmt = $db->prepare($sql); $stmt->execute([$chat_id]); $rows = $stmt->fetch(PDO::FETCH_ASSOC); return (int)$rows['user_id']; 

 //   $sql = 'INSERT INTO users (user_name, chat_id) VALUES (:user_name, :chat_id)'; $insert = $db->prepare($sql); $insert->execute([':user_name' => $name, ':chat_id' => $chat_id]); return true; 

Agregar dominios y SSL


Al enviar el comando / addDomain url al bot, obtenemos la url del dominio del comando y obtenemos los datos de registro del dominio utilizando esta biblioteca .

Obtén el dominio


Recibimos una respuesta en forma de texto:



Usando expresiones regulares , obtenemos la fecha de registro del dominio.

 preg_match('/Registry\sExpiry\sDate:\s(.*)\\r/', $date, $matches); if (!$matches[1]){ preg_match('/paid-till:\s*(.*)\\n/', $date, $matches); } $matches[1] = $this->formatDate($matches[1]); return $matches[1]; 

Obtén SSL


Decidí obtener un certificado SSL usando openssl para linux.

 $getDomainSSL = shell_exec("echo | openssl s_client -servername $url -connect $url:443 2>/dev/null | openssl x509 -noout -dates"); preg_match('~notAfter=(\w+)\s(\d+)\s.+\s(\d+)~', $getDomainSSL, $matches); $date = $matches[2].$matches[1].$matches[3]; $date = date("Ymd", strtotime($date)); $date = str_replace('.','-',$date); return $date; 

Así obtenemos:

 echo | openssl s_client -servername google.com -connect google.com:443 2>/dev/null | openssl x509 -noout -dates notBefore=Jan 7 15:47:12 2020 GMT notAfter=Mar 31 15:47:12 2020 GMT 

Analiza el resultado usando expresiones regulares

 preg_match('~notAfter=(\w+)\s(\d+)\s.+\s(\d+)~', $getDomainSSL, $matches); 



Solo queda agregar los datos a la tabla.

 $sql = 'INSERT INTO domains (domain_name, date_start, date_end, date_end_ssl) VALUES (:domain_name, :date_start, :date_end, :date_end_ssl)'; $insert = $db->prepare($sql); $insert->execute([':domain_name' => $url, ':date_end' => $exp, ':date_end_ssl' => $ssl_date]); 

Vinculamos el dominio y ssl al usuario


Los datos obtenidos simplemente deben registrarse en una tabla intermedia para no "multiplicar" los dominios.

 $sql = 'INSERT INTO domain_users (user_id, domain_id) VALUES (:user_id, :domain_id)'; $insert = $db->prepare($sql); $insert->execute([':user_id' => $user_id, ':domain_id' => $domain_id]); 

Comprobación de la fecha de finalización del dominio


Cuando wget va a la dirección / check, se seleccionan todos los dominios y certificados SSL con una fecha de vencimiento, y si los hay, envía un mensaje de chat al que está vinculado este dominio.

 $db = $this->db; $sql= " SELECT user_name, chat_id, domain_name, date_end FROM domain_users JOIN users USING (user_id) JOIN domains USING (domain_id) WHERE ( domains.date_end = CURDATE() OR domains.date_end = CURDATE() + INTERVAL 2 DAY OR domains.date_end = CURDATE() + INTERVAL 7 DAY OR domains.date_end = CURDATE() + INTERVAL 30 DAY ) "; $stmt = $db->prepare($sql); $stmt->execute(); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); 

CRON


La corona en este proyecto es necesaria para organizar la transición a la dirección '/ cheque', todos los días a las 12 en punto.

 crontab -e 0 12 * * * wget url/check 

Tor proxy


Algunas palabras sobre el envío de mensajes a telegram.

Desafortunadamente, en el territorio de mi país (Rusia), bloquean el telegrama, incluida su API.
Tengo que usar un proxy, mi elección recayó en el proxy tor (desde el último proyecto).

Solo necesita ser instalado.

 sudo apt-get install tor 

Entonces el proxy estará disponible en el puerto 9050.

 curl_setopt($myCurl, CURLOPT_PROXYTYPE, 7); curl_setopt($myCurl, CURLOPT_PROXY, "127.0.0.1:9050"); 

¡Gracias a todos por leer este artículo!

Este es mi primer artículo, así que no juzgues estrictamente :)

Comente esta publicación, aceptaré con gusto cualquier crítica.

El código fuente del proyecto en mi repositorio github :)

Source: https://habr.com/ru/post/485392/


All Articles