Integrar el API de Telegram con PHP

Hoy voy a contar mi experiencia integrando el API de Telegram con una aplicación PHP real de uno de mis clientes, los problemas que teníamos y como la integración con Telegram nos ayudó a solucionarlos. Esta integración la realizaremos a través de la librería MadelineProto.

Antes de comenzar, unas aclaraciones.

  • 1) Cuando hablo del API de Telegram no me estoy refiriendo a la creación de Bot’s, sino al uso del API ‘real’ que ofrece y que te da la oportunidad de crear tu propio cliente de mensajería.
  • 2) El objetivo de este artículo es intentar ofrecer al menos un punto de partida inicial para saber más o menos cómo empezar a usar el API de Telegram con PHP. Lo que se suele conocer como ‘saber por dónde van los tiros’…o el post que a mi me hubiera gustado leer cuando empecé.
  • 3) Por lo tanto…‘disclaimer’: lo que vas a leer a continuación es parte de mi experiencia con este API. Aún hay partes (muchas) que desconozco y a día de hoy todavía sigo aprendiendo y pegándome (mucho…muchísimo) con él para seguir integrando parte de la aplicación PHP.

¿Para qué usar el API de Telegram? Problema a resolver

Contexto inicial

Uno de los clientes para los que trabajo desde hace años como profesional autónomo es una academia de formación que prepara oposiciones, principalmente de Educación. Actualmente, estudian en ella algo más de 600 alumnos divididos en 65 grupos. Por un lado, antes de la integración con Telegram, la forma natural de comunicarse con los alumnos y los grupos era vía Whatsapp. Por otro lado, llevo desarrollándoles desde hace más de cinco años una aplicación PHP (Laravel) con la que prácticamente gestionan todo el negocio: alumnos, grupos, profesores, clases, exámenes, documentación, facturación, contabilidad, mensajería interna, calendarios…etc, etc.

Problema

La tarea de comunicación a través de Whatsapp era totalmente manual y resultaba muy tediosa, complicada y daba lugar a muchos errores. Imaginad tener que crear y/o gestionar casi de forma manual cientos y cientos de contactos, crear los grupos, meter a cada contacto en cada grupo…y luego, conforme pasa el curso, eliminar a los que se dan de baja, gestionar los cambios de grupo, nuevas altas, envíos de mensajes a los alumnos casi personalizados…etc., y esto, además, con cada nuevo curso académico. En definitiva, se dedicaba muchísimo tiempo en la gestión de las comunicaciones con sus alumnos tanto que, podríamos decir, había una persona dedicada casi en exclusiva a esta tarea.

Misión

La misión era simple, que no sencilla. Se trataba de poder gestionar y automatizar toda la comunicación con los grupos y alumnos de forma directa y transparente desde la aplicación PHP a través de una aplicación móvil de mensajería (la que fuera). Dicha automatización debería incluir, por ejemplo:

  • Grupo nuevo en PHP -> canal de difusión privado nuevo en app mensajería.
  • Alumno nuevo en PHP -> contacto nuevo en app mensajería.
  • Alumno entra en un grupo -> contacto entra al canal privado del grupo.
  • Alumno sale de un grupo -> contacto sale del canal privado del grupo.
  • Alumno cambia de grupo -> contacto sale del canal privado del primer grupo y entra al segundo.
  • …etc, etc.

En resumen, toda la gestión de contactos y de grupos/canales, envío de mensajes de texto, envío de mensajes con archivos adjuntos, lectura de los mismos, notificaciones…etc., todo, se debería poder hacer desde la aplicación PHP.

Búsqueda de soluciones

Whatsapp

Al ser Whatsapp la aplicación de mensajería que se estaba utilizando en la academia fue la primera que valoramos. A ver, es cierto que Whatsapp tiene un API para desarrolladores pero no es abierto. Tienes que solicitar permiso para usarlo (lo hicimos en su día) y ni nos contestaron. Whatsapp tiene sus partners y son empresas muy potentes y son con ellos con los que tienes que ‘negociar’ y ni si quiera en el caso de llegar a un acuerdo te dan acceso completo al API. Whatsapp, de forma sencilla pero totalmente insuficiente para nuestro objetivo permite el envío de mensajes de texto simples.

Otras aplicaciones de mensajería

Valoramos las posibilidades de usar otras aplicaciones como Line pero las descartamos también por el bajo uso de esta aplicación en nuestro país y por el API que proporcionaban que, honestamente, por algún motivo que no recuerdo descartamos en su momento.

Aplicación propia

Contactamos con un desarrollador que tenía experiencia en este tipo de aplicaciones de mensajería con academias de formación. Nos comentó que por un lado tenían cierto grado de complejidad y, además, su experiencia fue ‘mala’ porque los alumnos no se instalaban estas aplicaciones, no les generaban mucha confianza, deshabilitaban notificaciones…etc. Así que la descartamos

Telegram

Telegram, no sólo cumple con todas nuestras necesidades de comunicación, sino que además tiene muchísimas más posibilidades de integración gracias a su API totalmente abierta. Tal es así que, si quisieras, podrías programarte tu propio cliente de mensajería completo usando su infraestructura. Una maravilla, la verdad. Además, su uso está relativamente extendido, es conocida y el funcionamiento básico es similar a Whatsapp.

Como comenté, no se trata de usar los Bots de Telegram ya que estos ofrecen una funcionalidad útil, aunque limitada, para unos casos que no resolvían nuestros problemas. Usar el API directamente es bastante más avanzado, potente…y complicado, la verdad. Ya aviso, e insisto, al menos para mi, ha sido y está complicado integrar dicho API con la aplicación PHP y sobre todo entender (a nivel de programación) como funciona Telegram y el flujo que usa en sus operaciones.

Primeros pasos

Crear aplicación en Telegram

Lo primero de todo, claro está, es tener una cuenta de Telegram y para ello nos descargaremos la aplicación en un teléfono.

Después iniciaremos sesión como desarrolladores a través del siguiente enlace https://my.telegram.org/auth. El acceso será mediante un número de teléfono con Telegram al que llegará un código de inicio de sesión.

Después haremos click en el enlace API development tools y crearemos nuestra aplicación. Los datos que tendremos de la misma serán el ‘api_id’, el ‘api_hash’, ‘title’ y ‘short name’.

Instalar MadelineProto

Para integrarnos con el API de Telegram necesitamos implementar su protocolo de comunicación segura llamado MTProto. Por fortuna, salvo que queramos hacerlo y probablemente morir en el intento, no tenemos que implementar dicho protocolo desde cero en nuestra aplicación ya que hay una librería para PHP que ya lo hace. Esta librería se llama MadelineProto y es básicamente otro API que hace transparente (o casi) la comunicación de nuestra aplicación PHP con Telegram. Una maravilla, la verdad. Tiene una documentación bastante buena, el proyecto está actualizado e incluso tienen un canal en Telegram en el que se resuelven muchas dudas.

Antes de instalarlo, echa un vistazo a sus requerimientos. Una vez cumplidos, para instalar MadelineProto en nuestro proyecto PHP con composer basta ejecutar el siguiente comando:

composer require danog/madelineproto

Recomiendo encarecidamente la lectura de su documentación para conocer como utilizarla porque tampoco es que sea sencilla. A partir de aquí voy a suponer que le has echado un vistazo y que sabes más o menos como funciona o al menos te suena.

Nota

En mi caso tengo integrado MadelineProto en un proyecto con Laravel, lo digo por todo el código que sigue a continuación en el artículo. Habrá cosas específicas de Laravel pero bueno, en el fondo, esto sería lo de menos.

Iniciar sesión en Telegram con PHP y MadelineProto

Una vez instalado MadelineProto, supongamos que tenemos nuestra aplicación PHP y una ruta hacia un código similar al siguiente con el cual podremos iniciar sesión en Telegram.

Al ejecutar el código nos saldrá un ‘wizard’ que nos guiará paso a paso en el proceso. Debería ser algo similar a lo que sigue:

  • Paso 1: En primer lugar deberemos indicar api_id y el api_hash que obtuvimos al crear la aplicación. Podemos hacerlo de forma manual o automática. Si elegimos ‘Automatically’, únicamente tendremos que poner el número de teléfono con el que creamos la aplicación…así que esta será nuestra opción:
  • Paso 2: Indicamos el número de teléfono con el que creamos la aplicación.
  • Paso 3: Nos llegará un mensaje de aviso a nuestro Telegram con un código de inicio de sesión
  • Paso 4: Introduciremos el código recibido.
  • Paso 5: A continuación nos preguntará si queremos iniciar sesión como ‘user’ o como ‘bot’. En nuestro caso, como ‘User’.
  • Paso 6: Volvemos a introducir el número de teléfono.
  • Paso 7: Y recibiremos ahora otro mensaje con el código de inicio de sesión.
  • Paso 8: A continuación indicamos el código recibido
  • Paso 9: …y si todo ha ido bien, veremos que en la carpeta de nuestro proyecto tenemos creados los archivos de sesión de MadelineProto.

Primera solicitud al API de Telegram con PHP

La primera petición que podemos hacer, por ejemplo, para probar el correcto de la conexión con Telegram es solicitar nuestros datos. Para este cometido vamos a utilizar la funcion getSelf(). El código es el siguiente:

Este va a ser el formato general de uso del API de Telegram. Instanciar MadelineProto, configurar la petición y procesar la respuesta.

MadelineProto puede configurarse de forma que las peticiones se realicen de forma asíncrona lo cual mejora el rendimiento y el procesamiento de peticiones en paralelo. Al instanciar MadelineProto podemos pasar un array de configuración. Existen decenas de configuraciones distintas para que cada uno use el API de la forma que más le convenga. Los distintos valores de configuración están descritos en esta página. Probablemente te habrá llamado la atención el uso de la palabra reservada yield, te recomiendo leer la documentación oficial sobre generadores en PHP.

La respuesta que nos retorna esta llamada es la siguiente:

Como podemos observar, contiene toda la información referente a mi perfil. La inmensa mayoría de respuestas de peticiones al API son en formato json y contienen gran cantidad de información.

Otras llamadas al API de Telegram desde PHP

A continuación, indicaré de forma resumida algunos ejemplos de otros tipos de peticiones que he conseguido realizar para implementar una gestión más completa de la comunicación con Telegram. Teniendo en cuenta el código anterior los ejemplos irían dentro de la llamada al método loop:

return $this->madelineProto->loop(function () { 
...
ejemplos de código
...
});

Crear un canal

Crear un canal en Telegram es sencillo. Basta con indicar un título y la descripción del mismo al utilizar el método createChannel. También podríamos especificar otra configuración como crear un supergrupo, la geolocalización…etc.

$response = yield $this->madelineProto->channels->createChannel([
'title' => 'título del canal',
'about' => 'texto con alguna descripción'
]);

En la respuesta, Telegram nos retorna muchos datos, para mi el dato más importante en el channel_id que es el que me guardo para usar más tarde en otras operaciones con el canal creado.

Invitar a participantes a un canal

Usaremos la función inviteToChannel. Aunque la llamada sea sencilla, en función de nuestras necesidades la podemos complicar un poco. La definición de la llamada es como sigue:

$response = yield $this->madelineProto->channels->inviteToChannel( ['channel' => InputChannel, 'users' => [InputUser, InputUser], ]);

Debemos especificar el canal y un array de participantes a incluir. La especificación del canal se puede hacer de múltiples formas tal y como indica la documentación de InputChannel. En nuestro caso la forma más sencilla sería especificarlo de la forma ‘channel#ID’ siendo ID el valor que nos hubiera devuelto, por ejemplo, la llamada a crear un canal en el anterior ejemplo.

De forma similar, los participantes tienen que estar especificados según el tipo InputUser. Aquí nos podríamos encontrar con dos variantes:

  • La primera es que fueran contactos conocidos y ya hubiéramos obtenido anteriormente sus ‘userId’ de Telegram en alguna otra operación. En este caso no tendríamos más que especificar un array de usuarios del tipo ‘user#ID’, de la forma:
$inputUsers = ['user#123', 'user#456', 'user#789', ...]
  • La segunda es que sean contactos ‘anónimos’, es decir, no los tengamos aún en nuestra ‘agenda’ y desde Telegram no hubiéramos interactuado nunca con ellos. En este caso tendremos que importarlos previamente usando la llamada a importContacts. Para esto, deberíamos hacer algo parecido a lo siguiente:
//supongamos que hemos recibido una petición POST la siguiente información:
$_POST['channel_id'] = 123456;
$_POST['participants = [
['phone'=>'6123','first_name'=>'Manu','second_name'=>'Pijierro'
['phone'=>'6456','first_name'=>'Leo','second_name'=>'Messi'],
['phone'=>'6789','first_name'=>'Cris','second_name'=>'Ronaldo'],
];
//obtenemos nuestro propio ID
$me = yield $this->madelineProto->getSelf();
//configuramos la identificación del canal al que vamos a invitar
$channelKey = 'channel#'.$_POST['channel_id'];
//configuramos el array para la llamada a importContacts
$inputContacts = [];
foreach ($POST['participants] as $participant){
$inputContacts[] = [
'_' => 'inputPhoneContact',
'client_id' => $me['id'],
'phone' => $participant['phone'],
'first_name' => $participant['first_name'],
'second_name' => $participant['second_name']
];
}
//importamos los contactos a nuestra 'agenda'
$contacts = yield $this->madelineProto->contacts->importContacts(['contacts' => $inputContacts]);
//...y con la información recibida, construímos el array con los userId
$keyUsers = [];
foreach ($contacts['users'] as $contact) {
$keyUsers[] = 'user#'.$contact['id'];
}
//Finalmente, invitamos a los contactos al canal
return yield $this->madelineProto->channels->inviteToChannel(['channel' => $channelKey, 'users' => $keyUsers]);

Advertencia importante. Con esta operación podríamos invitar a cualquier número de teléfono aunque sea anónimo. Hay que tener en cuenta que los contactos podrían tener configurado su Telegram para no ser invitados de forma anónima a ningún canal o configuraciones de privacidad similares por lo que no podríamos obtener el resultado esperado.

Expulsar a un contacto de un canal

No hay un método de expulsión como tal, si no que lo que hay que hacer es configurar que puede y que no puede hacer un usuario en nuestro canal. Para expulsarlo, haremos uso del método editBanned especificando el ‘channelId’, ‘userId’ y configurando un atributo llamado ‘banned_rights’ con todo a true.

Enviar un mensaje a un contacto

Para enviar un mensaje haremos uso del método sendMessage. Tiene multitud de posibilidades de configuración pero básicamente y simplificando podríamos enviarlo de la siguiente forma:

$response = yield $this->madelineProto->messages->sendMessage([
'peer' => $peer,
'message' => 'mensaje a enviar',
'parse_mode' => 'Markdown'
]);

Como en casos anteriores, ‘peer’ (el destinatario) es de tipo InputPeer de forma que si tenemos el userId del contacto podremos utilizarlo y si no habría que importarlo. ‘parse_mode’ indicaría si el marcado del texto es HTML o Markdown. En la respuesta de sendMessage vienen decenas de campos con información del mensaje, el emisor y el receptor. Ahí ya utilizaríamos los que sean útiles para nuestra tarea (yo suelo guardar, como mínimo, el message[‘id’] para posteriores operaciones sobre el mismo.

Enviar un mensaje a un canal

De igual forma que en el caso anterior solo que el InputPeer debe hacer referencia a un canal, es decir, si antes era ‘user#123456’ en este caso podría ser un ‘channel#98765’.

Obtener información de todos los contactos

Esta es una operación bastante útil para obtener todos los contactos de tu Telegram. Con getContacts puedes saber que información guardas de cada uno de ellos.

$response =  yield $this->madelineProto->contacts->getContacts();

Obtener información de un contacto

Si lo que quieres es toda la información de un solo contacto hay que llamar a getFullInfo. $inputPeer es del tipo InputPeer y deberás configurarlo con el userId o bien obtener previamente su información de contacto si fuera alguien anónimo para ti, como hemos visto anteriormente.

$responseContact =  yield $this->madelineProto->getFullInfo($inputPeer);

Otras operaciones…

Los ejemplos anteriores creo que ya son suficientes para hacerse una idea de como funciona el API de Telegram y como interactuar con él desde MadelineProto. En mi caso tengo implementada bastante más funcionalidad como enviar mensajes con archivos, mostrar el contenido de los archivos y/o descargarlos, mostrar información completa de los canales, obtener el historial de mensajes de un contacto…en definitiva, cualquier operación que vaya siendo necesaria para que la comunicación sea completa.

Obtener actualizaciones desde Telegram

Todas las operaciones anteriores tiene una única dirección, es decir, son realizadas desde nuestra aplicación PHP con destino a Telegram pero, ¿qué ocurre cuando ocurre algo en Telegram? ¿cómo nos enteramos en nuestra aplicación PHP que alguien nos ha contestado a un mensaje? ¿cómo obtenemos todas las actualizaciones que se han producido?

Ahora mismo estoy desarrollando esta funcionalidad por lo que lamentablemente no tengo muy claro como lo haré finalmente. Cuando la termine escribiré otro artículo para compartir la solución. MadelineProto tiene documentada toda esta ‘movida’ a las que llamada Updates.

Como he comentado anteriormente, aunque he conseguido resolver muchas cuestiones, todavía me encuentro desarrollando muchas partes de la comunicación entre PHP y Telegram. No obstante, si necesitas ayuda y crees que puedo ayudarte de alguna forma en tu proyecto no tienes más que contactar conmigo y a ver si podemos solucionar algo :)

Como siempre, cualquier sugerencia, corrección, comentario…etc., será enormemente agradecido y bienvenido.

¡Chimpún!

Dad and developer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store