Cómo construir un sencillo bot de Whatsapp.

Contaremos cómo escribir un bot simple en PHP usando la API de WhatsApp

El bot de demostración responderá a las órdenes que entran como mensajes regulares en WhatsApp y responden a ellas. Ahora, en nuestro bot de chat de demostración, tiene la siguiente funcionalidad:

  • Visualización de la lista de comandos
  • Visualización del ID de chat actual
  • Visualización de la hora actual del servidor que ejecuta el bot.
  • Visualización de su nombre
  • Envío de archivos de diferentes formatos (pdf, jpg, doc, mp3, etc.)
  • Envío de mensajes de voz pregrabados
  • Envío de coordenadas geográficas (geo-locales)
  • Creación de conferencias (grupos)

Envíe un mensaje al +1 (585) 572-1187 a través de WhatsApp y pruebe la API.

Atención: para que el bot funcione, el teléfono debe estar siempre conectado a Internet y no debe ser usado para el Whatsapp Web. Para estos fines, es más práctico tener un dispositivo separado.

Trabajo preparatorio

Autorización mediante código QR.

Al principio, asociamos inmediatamente el whatsapp a nuestro script (guión), de modo que, a medida que escribimos el código, verificamos su operación. Para hacerlo, vaya a su cuenta personal y obtenga un código QR allí. A continuación, abra el WhatsApp en su teléfono, vaya a Configuración -> WhatsApp Web -> Escanea un código QR.

Ahora, para que el servidor ejecute nuestro script (guión) con nuevos mensajes, es necesario especificar la URL de WebHook. Coloque un enlace directo a su script (guión), por ejemplo, https://domain.com/PHP/whatsappbot.php. No sólo se puede especificar la dirección IP del servidor. Se puede especificar el puerto.

Obtén demo gratis, pruébalo hoy

Ahora vamos a crear el archivo whatsappbot.php y crear en él la clase: class whatsAppBot { }

Vamos a crear las variables que se colocan en la API de Url y token. Pueden ser encontrados en su cuenta.

{var $APIurl = 'https://api.chat-api.com/instanceYYYYY/';
                            var $token = 'abcdefgh12345678';}

Ahora empezamos a escribir la función__construct() función que se ejecutará automáticamente cada vez que ejecute la secuencia de comandos (guión). El servidor ChatAPI accede al bot cuando nuevos mensajes lleguen (más sobre eso abajo), enviando información sobre el nuevo mensaje en el formato JSON. Nosotros inmediatamente tomamos estos datos al principio de la función y los colocamos en variables.

{public function __construct(){ $json = file_get_contents('php://input');
                            $decoded = json_decode($json,true);}}

Continuamos escribiendo el código de función. Opcionalmente, podemos guardar los datos recibidos en un archivo para análisis adicional y depuración, si es necesario. Para ello, usamos el buffer de salida.

{ ob_start();
                        var_dump($decoded);
                        $input = ob_get_contents();
                        ob_end_clean();
                        file_put_contents('input_requests.log',$input.PHP_EOL,FILE_APPEND);}

Ahora escribimos el procesamiento de mensajes recibidos y la ejecución de las funciones correspondientes. Habrá muchos códigos anidados, pero vamos a clasificarlo línea por línea.

{ if(isset($decoded['messages'])){
                        foreach($decoded['messages'] as $message){
                        $text = explode(' ',trim($message['body']));
                        if(!$message['fromMe']){
                        switch(mb_strtolower($text[0],'UTF-8')){
                        case 'hi':  {$this->welcome($message['chatId'],false); break;}
                            case 'chatid': {$this->showChatId($message['chatId']); break;}
                            case 'time':   {$this->time($message['chatId']); break;}
                            case 'me':     {$this->me($message['chatId'],$message['senderName']); break;}
                            case 'file':   {$this->file($message['chatId'],$text[1]); break;}
                            case 'ptt':     {$this->ptt($message['chatId']); break;}
                            case 'geo':    {$this->geo($message['chatId']); break;}
                            case 'group':  {$this->group($message['author']); break;}
                            default:        {$this->welcome($message['chatId'],true); break;}
                            }}}}}

Explicación:

  • if(isset($decoded['messages']))
    Las notificaciones del tipo "el usuario dejó la charla" también son enviadas por el servidor, pero no tendrán una matriz (arreglo) de mensajes. Esta comprobación evita el error "undefined index".

  • foreach($decoded['messages'] as $message)
    Los mensajes están en una matriz (arreglo) y varios mensajes pueden llegar al mismo tiempo. El bot debe reaccionar a cada uno de ellos.

  • $text = explode(' ',trim($message['body']));
    Dividimos el cuerpo del mensaje en palabras separadas. La primera palabra es el comando, los demás serán los parámetros del comando.

  • if(!$message['fromMe'])
    Esta comprobación es necesaria para que el bot no entre en recursión. La marca "fromMe" significa que el mensaje fue enviado por el propio bot. Por lo tanto, continuamos la ejecución sólo para los mensajes recibidos.

  • switch(mb_strtolower($text[0],'UTF-8'))
    Un bloque switch que determina qué comando está contenido en la primera palabra. El comando se da en letras minúsculas, para que el bot responda, independientemente de que esté escrito entre letras minúsculas y mayúsculas. Ex: aBcDe.

  • case 'hi': {$this->welcome($message['chatId'],false)}
    La implementación de un comando apropiado basado en la primera palabra. Transferimos el chatId del mensaje a la función llamada, para que el envío ocurra en el chat correspondiente. En principio, todas las líneas siguientes son las mismas, pero preste atención a:

    case 'file': {$this->file($message['chatId'],$text[1])}
    Aquí pasamos otro parámetro, es decir la segunda palabra del mensaje, así como es un parámetro de comando. Sobre eso más abajo. También preste atención en:

    case 'me': {$this->me($message['chatId'],$message['senderName'])}
    Aquí, como en el segundo parámetro es el nombre de la persona que llama también tomado de los datos del mensaje. Y en el default ejecuta una función que muestra una lista de comandos, pero con el parámetro true, lo que significa obtener el comando equivocado.

Terminamos de escribir la función __construct(). Ahora pasamos a las funciones ejecutadas por los comandos del bloque de switch arriba mencionado. En la parte de las funciones se ejecuta la función sendMessage(), en la otra parte - la función sendRequest(). En el script (guión), estas funciones se colocan abajo, pero hablaremos de ellas inmediatamente:

La función sendRequest() realiza directamente la solicitud al servidor ChatAPI para el envío de mensajes y de medios diferentes. Acepta 2 parámetros - $method y $data.

  • $método determina qué método chatAPI debe ejecutarse.
  • $data contiene los datos necesarios para la transferencia.
{ public function sendRequest($method,$data){
                        $url = $this->APIurl.$method.'?token='.$this->token;
                        if(is_array($data)){ $data = json_encode($data);}
                        $options = stream_context_create(['http' => [
                        'method'  => 'POST',
                        'header'  => 'Content-type: application/json',
                        'content' => $data
                        ]]);
                        $response = file_get_contents($url,false,$options);
                        file_put_contents('requests.log',$response.PHP_EOL,FILE_APPEND);}

Vamos a explicar con más detalle: En $url, formamos una URL válida que contiene el APIUrl, el método y el token. A continuación, verificamos los datos recibidos. Si es una matriz (arreglo), convertirlo en JSON. En caso contrario, la conversión a JSON ya se ha implementado en la función ejecutada. $options - define encabezados HTTP. Entonces, a través de file_get_contents, ejecuta la solicitud para la URL generada, transmitiendo los datos. La última línea no es necesaria, simplemente guarda la respuesta del servidor ChatAPI para un archivo de depuración y registro.

La función sendMessage() en realidad es sólo una simple envoltura de mensajes de texto. Se forma la matriz (arreglo) de datos correcta y la transmite a la función sendRequest() anteriormente mencionado con el método "message".

{ public function sendMessage($chatId, $text){
                        $data = array('chatId'=>$chatId,'body'=>$text);
                        $this->sendRequest('message',$data);}}

Ahora vamos a crear una función de control desde un bloque switch. Las funciones que envían un mensaje de texto simple, la mayoría de las veces, sólo ejecutan sendMessage() con un determinado texto. Las funciones que envían medios diferentes forman sus matrices (arreglo) de datos, y ejecuta sendRequest() con otros métodos.

La función welcome(): muestra la lista de comandos disponibles.

{ public function welcome($chatId, $noWelcome = false){
                        $welcomeString = ($noWelcome) ? "Incorrect command\n" : "WhatsApp Demo Bot PHP\n";
                        $this->sendMessage($chatId,
                        $welcomeString.
                        "Commands:\n".
                        "1. chatid - show ID of the current chat\n".
                        "2. time - show server time\n".
                        "3. me - show your nickname\n".
                        "4. file [format] - get a file. Available formats: doc/gif/jpg/png/pdf/mp3/mp4\n".
                        "5. ptt - get a voice message\n".
                        "6. geo - get a location\n".
                        "7. group - create a group with the bot");}}

Si el parámetro $noWelcome es igual false, la primera línea del mensaje será el saludo mostrado por el comando "hi". Si true - saludo será reemplazado por un mensaje de comando no válido.

La función showChatId() muestra el ID de chat actual mediante el comando "chatid".

{ public function showChatId($chatId){
                        $this->sendMessage($chatId,'ChatID: '.$chatId);}}

La función time () - muestra la hora actual del servidor mediante el comando "time".

{ public function time($chatId){
                        $this->sendMessage($chatId,date('d.m.Y H:i:s'));}}

La función me() - muestra el nombre del interlocutor usando el comando "me".

{
                        public function me($chatId,$name){
                        $this->sendMessage($chatId,$name);
                        }}

La función file() - envía un archivo usando el comando "file". Esta función es más interesante, ya que funciona con el parámetro. Como el parámetro se transfiere el formato de archivo que desea enviar.

{ public function file($chatId,$format){
                        $availableFiles = array(
                        'doc' => 'document.doc',
                        'gif' => 'gifk.gif',
                        'jpg' => 'jpgfile.jpg',
                        'png' => 'pngfile.png',
                        'pdf' => 'presentation.pdf',
                        'mp4' => 'video.mp4',
                        'mp3' => 'mp3file.mp3'
                        );
                        if(isset($availableFiles[$format])){
                        $data = array(
                        'chatId'=>$chatId,
                        'body'=>'https://domain.com/PHP/'.$availableFiles[$format],
                        'filename'=>$availableFiles[$format],
                        'caption'=>'Get your file '.$availableFiles[$format]
                        );
                        $this->sendRequest('sendFile',$data);}}}

Vamos a explicar con más detalle:

  • $availableFiles es una matriz en la que las claves son los parámetros de la función y los valores son los nombres de los archivos. Naturalmente, los archivos con nombres de la matriz deben estar presentes en el servidor. En este ejemplo, están en el mismo lugar que el script (guión) bot de charla, pero se puede poner en otra carpeta.
  • if (isset ($availableFiles [$format])) - comprueba la existencia de una clave de matriz (arreglo) con el parámetro recibido. Si existe, entonces formamos una matriz (arreglo) de datos y la transferimos a sendRequest() con el método "sendFile". Los datos siguientes deben estar en la matriz (arreglo) de datos:
  • chatId - como de costumbre, el ID de chat al que se envía la respuesta.
  • body - un enlace directo al archivo en el servidor. Por favor, tenga en cuenta que SSL debe estar conectado al servidor!
  • filename - nombre de archivo, puede especificar cualquier
  • caption - el mensaje que se incluye con este archivo.

La función ptt() - enviando un mensaje de voz usando el comando "ptt". El mensaje de voz debe ser un archivo .OGG en el servidor.

{ public function ptt($chatId){
                        $data = array(
                        'audio'=>'https://domain.com/PHP/ptt.ogg',
                        'chatId'=>$chatId
                        );
                        $this->sendRequest('sendAudio',$data);}}

Aquí, como en la función anterior, formamos una matriz (arreglo) de datos: chatId - ID chat audio - un enlace directo al archivo .ogg, de nuevo, el SSL es necesario. Y pasar a la función sendRequest con el método "sendAudio".

Función geo() - envío de coordenadas geográficas usando el comando "geo"

{ public function geo($chatId){
                        $data = array(
                        'lat'=>51.51916,
                        'lng'=>-0.139214,
                        'address'=>'Your address',
                        'chatId'=>$chatId
                        );
                        $this->sendRequest('sendLocation',$data);
                        }}

La misma cosa que en las dos funciones anteriores. La matriz (arreglo) debe contener los siguientes datos: lat y lng - coordenadas; address es una dirección, pero usted puede escribir cualquier cadena; - chatld - es evidente.

La función group() crea una conferencia en la que usted y el bot estarán utilizando el comando "group".

{ public function group($author){
                        $phone = str_replace('@c.us','',$author);
                        $data = array(
                        'groupName'=>'Group with the bot PHP',
                        'phones'=>array($phone),
                        'messageText'=>'It is your group. Enjoy'
                        );
                        $this->sendRequest('group',$data);}}

Aquí, necesitamos especificar los números de teléfono de los usuarios que se agregarán a la conferencia. En la primera línea, extraemos el número de teléfono del usuario de su ID personal, que se parece a 79991234567@c.us Entonces, formamos una matriz (arreglo):

  • groupName - el nombre de la conferencia
  • phones - un conjunto de números de teléfono;
  • messageText - el texto del primer mensaje en el grupo;

Preparé un manual sobre cómo escribir un bot de WhatsApp simple en PHP Por favor, tenga en cuenta que esta es la única función donde NO se transfiere el chatId. Y transferimos la matriz (arreglo) a sendRequest().

Ahora que terminamos de trabajar con funciones, después de paréntesis que cierra la class escribe una línea: new whatsAppBot();

Para que la class se ejecute automáticamente al acceder al script (guión).

El código final aparecerá de la siguiente manera.

{
                        class whatsAppBot{
                        //specify instance URL and token
                        var $APIurl = 'https://api.chat-api.com/instanceYYYYY/';
                        var $token = '**************************';

                        public function __construct(){
                        //get the JSON body from the instance
                        $json = file_get_contents('php://input');
                        $decoded = json_decode($json,true);

                        //write parsed JSON-body to the file for debugging
                        ob_start();
                        var_dump($decoded);
                        $input = ob_get_contents();
                        ob_end_clean();
                        file_put_contents('input_requests.log',$input.PHP_EOL,FILE_APPEND);

                        if(isset($decoded['messages'])){
                        //check every new message
                        foreach($decoded['messages'] as $message){
                        //delete excess spaces and split the message on spaces. The first word in the message is a command, other words are parameters
                        $text = explode(' ',trim($message['body']));
                        //current message shouldn't be send from your bot, because it calls recursion
                        if(!$message['fromMe']){
                        //check what command contains the first word and call the function
                        switch(mb_strtolower($text[0],'UTF-8')){
                        case 'hi':  {$this->welcome($message['chatId'],false); break;}
                            case 'chatid': {$this->showChatId($message['chatId']); break;}
                            case 'time':   {$this->time($message['chatId']); break;}
                            case 'me':     {$this->me($message['chatId'],$message['senderName']); break;}
                            case 'file':   {$this->file($message['chatId'],$text[1]); break;}
                            case 'ptt':     {$this->ptt($message['chatId']); break;}
                            case 'geo':    {$this->geo($message['chatId']); break;}
                            case 'group':  {$this->group($message['author']); break;}
                            default:        {$this->welcome($message['chatId'],true); break;}
                            }}}}}

                        //this function calls function sendRequest to send a simple message
                        //@param $chatId [string] [required] - the ID of chat where we send a message
                        //@param $text [string] [required] - text of the message
                        public function welcome($chatId, $noWelcome = false){
                        $welcomeString = ($noWelcome) ? "Incorrect command\n" : "WhatsApp Demo Bot PHP\n";
                        $this->sendMessage($chatId,
                        $welcomeString.
                        "Commands:\n".
                        "1. chatid - show ID of the current chat\n".
                        "2. time - show server time\n".
                        "3. me - show your nickname\n".
                        "4. file [format] - get a file. Available formats: doc/gif/jpg/png/pdf/mp3/mp4\n".
                        "5. ptt - get a voice message\n".
                        "6. geo - get a location\n".
                        "7. group - create a group with the bot"
                        );
                        }

                        //sends Id of the current chat. it is called when the bot gets the command "chatId"
                        //@param $chatId [string] [required] - the ID of chat where we send a message
                        public function showChatId($chatId){
                        $this->sendMessage($chatId,'ChatID: '.$chatId);
                        }
                        //sends current server time. it is called when the bot gets the command "time"
                        //@param $chatId [string] [required] - the ID of chat where we send a message
                        public function time($chatId){
                        $this->sendMessage($chatId,date('d.m.Y H:i:s'));
                        }
                        //sends your nickname. it is called when the bot gets the command "me"
                        //@param $chatId [string] [required] - the ID of chat where we send a message
                        //@param $name [string] [required] - the "senderName" property of the message
                        public function me($chatId,$name){
                        $this->sendMessage($chatId,$name);
                        }
                        //sends a file. it is called when the bot gets the command "file"
                        //@param $chatId [string] [required] - the ID of chat where we send a message
                        //@param $format [string] [required] - file format, from the params in the message body (text[1], etc)
                        public function file($chatId,$format){
                        $availableFiles = array(
                        'doc' => 'document.doc',
                        'gif' => 'gifka.gif',
                        'jpg' => 'jpgfile.jpg',
                        'png' => 'pngfile.png',
                        'pdf' => 'presentation.pdf',
                        'mp4' => 'video.mp4',
                        'mp3' => 'mp3file.mp3'
                        );

                        if(isset($availableFiles[$format])){
                        $data = array(
                        'chatId'=>$chatId,
                        'body'=>'https://domain.com/PHP/'.$availableFiles[$format],
                        'filename'=>$availableFiles[$format],
                        'caption'=>'Get your file '.$availableFiles[$format]
                        );
                        $this->sendRequest('sendFile',$data);}}

                        //sends a voice message. it is called when the bot gets the command "ptt"
                        //@param $chatId [string] [required] - the ID of chat where we send a message
                        public function ptt($chatId){
                        $data = array(
                        'audio'=>'https://domain.com/PHP/ptt.ogg',
                        'chatId'=>$chatId
                        );
                        $this->sendRequest('sendAudio',$data);}

                        //sends a location. it is called when the bot gets the command "geo"
                        //@param $chatId [string] [required] - the ID of chat where we send a message
                        public function geo($chatId){
                        $data = array(
                        'lat'=>51.51916,
                        'lng'=>-0.139214,
                        'address'=>'Ваш адрес',
                        'chatId'=>$chatId
                        );
                        $this->sendRequest('sendLocation',$data);}

                        //creates a group. it is called when the bot gets the command "group"
                        //@param chatId [string] [required] - the ID of chat where we send a message
                        //@param author [string] [required] - "author" property of the message
                        public function group($author){
                        $phone = str_replace('@c.us','',$author);
                        $data = array(
                        'groupName'=>'Group with the bot PHP',
                        'phones'=>array($phone),
                        'messageText'=>'It is your group. Enjoy'
                        );
                        $this->sendRequest('group',$data);}

                        public function sendMessage($chatId, $text){
                        $data = array('chatId'=>$chatId,'body'=>$text);
                        $this->sendRequest('message',$data);}

                        public function sendRequest($method,$data){
                        $url = $this->APIurl.$method.'?token='.$this->token;
                        if(is_array($data)){ $data = json_encode($data);}
                        $options = stream_context_create(['http' => [
                        'method'  => 'POST',
                        'header'  => 'Content-type: application/json',
                        'content' => $data]]);
                        $response = file_get_contents($url,false,$options);
                        file_put_contents('requests.log',$response.PHP_EOL,FILE_APPEND);}}
                        //execute the class when this file is requested by the instance
                        new whatsAppBot();}


Usted sólo tendrá que reemplazar su token de su cuenta personal por la variable $token y el número de instancia.

Obtener su clave de API