How to Build Your First Slack Bot in 5 Minutes using PHP

February 14, 2017
Written by

PHPSlackbot

So you want to build a Slack bot using PHP? You’re in the right place. This blog post will walk you through building your first Slack bot using PHP in 5 minutes. The clock is ticking, let’s get started.

Creating Our Bot

Before we write any code, we need to configure our Slack bot within our Slack team. Head over to https://[yourslackteam].slack.com/apps/build/custom-integration and then click “Bots”.

Give your bot a clever name. Or if you’re lacking inspiration feel free to use something simple like ‘php_bot’ and then click “Add Integration”.

The next page will give you an API token which you’ll want to keep handy. We’ll be making use of it shortly.

Using RTM with PHP using slack-client

Our bot will use Slack’s Real Time Messaging (RTM) API. In order to use RTM with PHP we will use Stephen Coakley’s very handy slack-client library. Hop into your terminal and create a new folder for our code. We’re going to load up slack-client Composer but it relies on some unstable dependencies. Before we install it create a composer.json file that tells Composer we’re cool with “dev” snapshots as the minimum stability level.

{
    "minimum-stability": "dev",
    "prefer-stable": true
}

With that done we can install the library:

composer require coderstephen/slack-client

Now that our dependencies are installed, open a new file called bots.php in your favorite IDE. First step to writing our bot’s code is connecting to it using the API token Slack gave us when we created our bot:

<?php
require_once('vendor/autoload.php');

$loop = ReactEventLoopFactory::create();

$client = new SlackRealTimeClient($loop);
$client->setToken('YOUR SLACK API TOKEN');
$client->connect();

$loop->run();

Connect your bot to your Slack team by running:

php bot.php

You connected your bot to your Slack team! Ok, this isn’t that interesting because it we’re yet reading or writing any messages with our bot. Add a callback to our code that lets our bot read any messages coming into a channel that our bot is part of:


$client->connect();

$client->on('message', function ($data) use ($client) {
    echo "Incoming message: ".$data['text']."\n";
});

$loop->run();

Run our code again, invite your bot to any channel or send it a DM and you’ll see all incoming messages:

php bot.php

Our bot is reading messages, but we can’t really call this a bot until it responds to messages. The first version of our bot is going to be a “parrot bot” that just repeats back any message it sees. We’ll make this happen within the message callback we just wrote:


$client->on('message', function ($data) use ($client) {
    $client->getChannelGroupOrDMByID($data['channel'])->then(function ($channel) use ($client, $data) {
        $message = $client->getMessageBuilder()
                    ->setText($data['text'])
                    ->setChannel($channel)
                    ->create();
        $client->postMessage($message);
    });
});

This code looks up the channel, group or DM object based on the id of the incoming message and creates a new message that we post back into the conversation. Run your code again and give it a try.

We just built the world’s most annoying Slack bot! And we did it in 5 minutes. :fire: :fire: :fire:

A Bot to Figure Out Who is Calling You

Your friends and coworkers may not be super excited if you deploy your parrot bot into production. Luckily, we can turn this bot into something more useful by spending just a few more minutes on it. Allow me to quickly set the stage with a short poem:

Phone rings.
Screen flashes.
Terror.
Who is calling me?

It is time to update our bot to use the Twilio Lookup API to allow anyone in our Slack team to quickly find out who is calling them and save them from this terror. You’ll need a Twilio account to build this part, if you don’t already have one you can sign up for free.

We’ll be using the Twilio PHP helper library to interact with the Lookup API. We can install it using Composer:

composer require twilio/sdk

Once we have it installed with Composer we can instantiate it in our bot.php file using the Account SID and Auth token in our Twilio Console:


$client->connect();

$twilio_client = new TwilioRestClient("YOUR TWILIO ACCOUNT SID", "YOUR TWILIO AUTH TOKEN");

Our bot is currently parroting every message that comes into the conversations it is part of, but we only want to lookup a number when someone explicitly asks. We’ll tell our team that our bot will respond to any message that starts with “!lookup”:


    if(stripos($data['text'], '!lookup') === 0) {
        $client->getChannelGroupOrDMByID($data['channel'])->then(function ($channel) use ($client, $data) {
            $message = $client->getMessageBuilder()
                        ->setText($data['text'])
                        ->setChannel($channel)
                        ->create();
            $client->postMessage($message);
        });
    }

Now that we’re only looking at text that starts with !lookup we can parse out the phone number from that text. We’ll also do some cleanup in response to some magic Slack does with creating phone number links:

    if(stripos($data['text'], '!lookup') === 0) {
        $client->getChannelGroupOrDMByID($data['channel'])->then(function ($channel) use ($client, $data) {
            // remove command and Slack tel link
            $phone_number = str_ireplace('!lookup ', '', $data['text']);
            $phone_number = preg_replace('/<tel:[^|]*/', '', $phone_number);

With our phone number handy, we can use the the Twilio library to lookup the caller details and send it back to the channel.


$client->on('message', function ($data) use ($client, $twilio_client) {
    if(stripos($data['text'], '!lookup') === 0) {
      
        $client->getChannelGroupOrDMByID($data['channel'])->then(function ($channel) use ($client, $data, $twilio_client) {
        // remove command and Slack tel link
        $phone_number = str_ireplace('!lookup ', '', $data['text']);
        $phone_number = preg_replace('/<tel:[^|]*/', '', $phone_number);

            $number = $twilio_client->lookups
                ->phoneNumbers($phone_number)
                ->fetch(
                    array("type" => "caller-name")
                );
            $message = $client->getMessageBuilder()
                        ->setText("Oh, don't worry this is " . $number->callerName['caller_name'])
                        ->setChannel($channel)
                        ->create();
            $client->postMessage($message);
        });

Run your bot and give this a try: !lookup 415-701-2311. W00t W00t!

There are two last bits of cleanup that we need to finish. What if our bot can’t find the caller’s name or someone passes in something to our command that isn’t a phone number? We can fix the first issue by adding a quick check before we send our message:


$client->getChannelGroupOrDMByID($data['channel'])->then(function ($channel) use ($client, $data, $twliio_client) {
       // remove command and Slack tel link
        $phone_number = str_ireplace('!lookup ', '', $data['text']);
        $phone_number = preg_replace('/<tel:[^|]*/', '', $phone_number);

          $number = $twilio_client->lookups
                      ->phoneNumbers($phone_number)
                      ->fetch(
                          array("type" => "caller-name")
                      );

            if($number->callerName['caller_name'] === null) {
                $txt = "Run! The call is coming from inside the house! Just kidding, I just couldn't find info about this caller";
            } else {
                $txt = "Oh, don't worry this is " . $number->callerName['caller_name'];
            }
            $message = $client->getMessageBuilder()
                        ->setText($txt)
                        ->setChannel($channel)
                        ->create();
            $client->postMessage($message);
        });

To catch any !lookups that may not contain phone numbers we’ll add error handling around our request to the Lookup API. This has the added benefit of catching any other errors that may occur here:


        try { 
            $number = $twilio_client->lookups
                  ->phoneNumbers($phone_number)
                  ->fetch(
                      array("type" => "caller-name")
                  );
        } catch (Exception $e) {
            $message = $client->getMessageBuilder()
                  ->setText(":panda_face: Something went wrong :panda_face:")
                  ->setChannel($channel)
                  ->create();
            $client->postMessage($message);
            return;
        }

Bots. Bots. Bots.
Surprise! You came to the blog post expecting you would build your first Slack bot with PHP but you’ve now just finished your second Slack bot. Run the code and bask in the glory of your accomplishments.

What will your third bot be? Catch me on twitter and let me know how your bot journey is going. I can’t wait to see what you build.