A criação de um bot Whatsapp no PHP. O guia completo

Vamos contar como escrever um bot simples em PHP, usando a API do WhatsApp.

O bot de demonstração responderá aos comandos que entram como mensagens regulares no WhatsApp e respondem a eles. Agora, no nosso bot de bate-papo de demonstração, tem a seguinte funcionalidade:

  • Exibição da lista de comandos
  • Exibição do ID de bate-papo atual
  • Exibição da hora actual do servidor que está a executar o bot.
  • Exibição do seu nome
  • Envio de arquivos de diferentes formatos (pdf, jpg, doc, mp3, etc.)
  • Envio de mensagens de voz pré-gravadas
  • Envio de coordenadas geográficas (locais)
  • Criação da conferência (grupos)

Para testar e verificar o nosso bot, enviar qualquer mensagem para o número +1 (585) 572-1187 ou no link

Atenção: para que o bot funcione, o telefone deve estar sempre conectado à Internet e não deve ser usado para o Whatsapp Web. Para esses fins, é mais prático ter um dispositivo separado.

Trabalho preparatório

A autorização Whatsapp através de um código QR

No início, associamos imediatamente o whatsapp ao nosso script(roteiro), de modo que, à medida que escrevemos o código, verificamos sua operação. Para fazer isso, vá para sua conta pessoal e obtenha um código QR lá. Em seguida, abra o WhatsApp no seu celular, vá para Configurações -> WhatsApp Web -> Digitalize um código QR.

Agora, para que o servidor execute o nosso script(roteiro) com novas mensagens, você precisa especificar o URL do WebHook. Coloque lá um link direto para o seu script(roteiro), por exemplo, https://domain.com/PHP/whatsappbot.php. Você não pode apenas especificar o endereço IP do servidor. Você pode especificar a porta.

Obtenha acesso de demonstração gratuito à API do WhatsApp

Agora vamos criar o arquivo whatsappbot.php e criar nele a class: class whatsAppBot { }

Vamos criar as variáveis que são colocados na API Url e token. Eles podem ser encontrados em sua conta.

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

Agora iniciamos a escrever a função __construct() função que será executado automaticamente cada vez que você executar o script(roteiro). O servidor ChatAPI acessará o bot quando novas mensagens chegarem (mais sobre isso abaixo), enviando informações sobre a nova mensagem no formato JSON. Nós imediatamente pegamos esses dados no início da função e os colocamos em variáveis.

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

Continuamos a escrever o código de função. Opcionalmente, podemos salvar os dados recebidos em um arquivo para análise adicional e depuração, se necessário. Para isso, usamos o buffer de saída.

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

Agora escrevemos o processamento de mensagens recebidas e execução das funções correspondentes. Haverá muitos códigos aninhados, mas vamos classificá-lo linha por linha.

{ 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;}
                            }}}}}

Explicação:

  • if(isset($decoded['messages']))
    Notificações do tipo "o usuário deixou o bate-papo" também são enviados pelo servidor, mas eles não terão uma matriz(arranjo) de mensagens. Esta verificação previne o erro "Undefined index".

  • foreach($decoded['messages'] as $message)
    As mensagens estão em uma matriz(arranjo) e várias mensagens podem chegar ao mesmo tempo. O bot deve reagir a cada um deles.

  • $text = explode(' ',trim($message['body']));
    Dividimos o corpo da mensagem em palavras separadas. A primeira palavra é o comando, os outros serão os parâmetros do comando.

  • if(!$message['fromMe'])
    Essa verificação é necessária para que o bot não entre em recursão. Marca "fromMe" significa que a mensagem foi enviada pelo próprio bot. Portanto, continuamos a execução apenas para mensagens recebidas.

  • switch(mb_strtolower($text[0],'UTF-8'))
    Um bloco switch que determina qual comando está contido na primeira palavra. O comando é dado em letras minúsculas, para que o bot responda, independentemente de estar escrito em letras maiúsculas ou maiúscula. Ex: aBcDe

  • case 'hi': {$this->welcome($message['chatId'],false)}
    A implementação de um comando apropriado com base na primeira palavra. Transferimos o chatId da mensagem para a função chamada, para que o envio ocorra no chat correspondente. Em princípio, todas as linhas seguintes são as mesmas, mas preste atenção em:

    case 'file': {$this->file($message['chatId'],$text[1])}
    Aqui nós passamos outro parâmetro, ou seja a segunda palavra da mensagem, assim como é um parâmetro de comando. Sobre isso mais abaixo. Também preste atenção em:

    case 'me': {$this->me($message['chatId'],$message['senderName'])}
    Aqui como o segundo parâmetro é o nome do interlocutor, também retirado dos dados da mensagem. E no default executamos uma função que exibe uma lista de comandos, mas com o parâmetro true, o que significa obter o comando errado.

Terminamos de escrever a função __construct(). Agora nós passamos para as funções executadas pelos comandos do bloco de switch acima mencionado. Na parte das funções é executada a função sendMessage(), na outra parte - a função sendRequest(). No script(roteiro), essas funções são colocadas abaixo, mas falaremos sobre elas imediatamente:

A função sendRequest() realiza diretamente a solicitação para o servidor ChatAPI para o envio de mensagens e de mídia diferente. Ela aceita 2 parâmetro - $method e $data.

  • $method determina qual método chatAPI deve ser executado.
  • $data contém os dados necessários para a transferência.
{ 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 explicar com mais detalhes: Em $ url, formamos um URL válido contendo o APIUrl, o método e o token. Em seguida, verificamos os dados recebidos. Se for uma matriz(arranjo), convertê-lo em JSON. Caso contrário, a conversão para JSON já foi implementada na função executada. $options - define cabeçalhos HTTP. Então, através de file_get_contents, executamos a solicitação para o URL gerado, transmitindo os dados.A última linha não é necessária, ela simplesmente grava a resposta do servidor ChatAPI para um arquivo para depuração e registro.

A função sendMessage() na realidade é apenas um simples invólucro de mensagens de texto. Ele forma a matriz(arranjo) de dados correto e a transmite para a função sendRequest() acima mencionado com o método "message".

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

Agora vamos criar uma função de controle a partir de um bloco switch. As funções que enviam uma mensagem de texto simples, na maioria das vezes, apenas executam o sendMessage() com um determinado texto. Funções que enviam mídias diferentes formam suas matrizes(arranjo) de dados, e executam sendRequest() com outros métodos.

A função welcome() - exibe a lista de comandos disponíveis.

{ 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");}}

Se o parâmetro $noWelcome for igual false, a primeira linha da mensagem será a saudação exibida pelo comando "hi". Se true - saudação será substituído por uma mensagem de comando inválido.

A função showChatId () exibe o ID de bate-papo atual usando o comando "chatid".

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

A função time () - exibe a hora atual do servidor usando o comando "time".

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

A função me() - exibe o nome do interlocutor usando o comando "me".

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

A função file() - envia um arquivo usando o comando "file". Essa função é mais interessante, já que funciona com o parâmetro. Como o parâmetro é transferido o formato de arquivo que você deseja enviar.

{ 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);}}}

Vamos explicar com mais detalhes:

  • $availableFiles é uma matriz na qual as chaves são os parâmetros da função e os valores são os nomes dos arquivos. Naturalmente, os arquivos com nomes da matriz devem estar presentes no servidor. Neste exemplo, eles estão no mesmo lugar que o script(roteiro) bot de bate-papo, mas você pode colocá-los em outra pasta.
  • if(isset($availableFiles[$format])) - verifica a existência de uma chave de matriz(arranjo) com o parâmetro recebido. Se existir, então formamos uma matriz(arranjo) de dados e a transferimos para sendRequest() com o método "sendFile". Os dados a seguir devem estar na matriz(arranjo) de dados:
  • chatId - como de costume, o ID de bate-papo para o qual a resposta é enviada.
  • body - um link direto para o arquivo no seu servidor. Por favor, note que o SSL deve estar conectado no servidor!
  • filename - nome do arquivo, você pode especificar qualquer
  • caption - a mensagem que acompanha este arquivo.

A função ptt() - enviando uma mensagem de voz usando o comando "ptt". A mensagem de voz deve ser um arquivo .OGG no seu servidor.

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

Aqui, como na função anterior, formamos uma matriz(arranjo) de dados: chatId - ID bate-papo audio - um link direto para o arquivo .ogg, novamente, o SSL é necessário. E passá-lo para a função sendRequest com o método "sendAudio".

Função geo() - envio de coordenadas geográficas usando o comando "geo"

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

A mesma coisa que nas duas funções anteriores. A matriz(arranjo) deve conter os seguintes dados: lat e lng - coordenadas; address é um endereço, mas você pode escrever qualquer string; chatld – é evidente.

A função group() cria uma conferência na qual você e o bot estarão, usando o 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);}}

Aqui, precisamos especificar os números de telefone dos usuários que serão adicionados à conferência. Na primeira linha, extraímos o número de telefone do usuário da sua ID pessoal, que se parece com 79991234567@c.us Então, formamos uma matriz(arranjo):

  • groupName - o nome da conferência;
  • phones - um conjunto de números de telefone;
  • messageText - o texto da primeira mensagem no grupo;

Preparou um manual sobre como escrever um simples bot whatsapp em php Por favor, note que esta é a única função onde NÃO se transfere o chatId. E nós transferimos a matriz(arranjo) para sendRequest().

Agora que terminamos de trabalhar com funções, depois de parênteses que fecha o class escreva uma linha: new whatsAppBot();

Para que o class execute automaticamente ao acessar o script(roteiro).

O código final irá aparecer da seguinte forma

{
                        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'=>'Your 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();}


Você só precisará substituir seu token de sua conta pessoal pela variável $token e número da instância.

Obter chave de API