Статьи

Как создать слабый интерфейс для вашего PHP-приложения

Если вы следили за развитием инструментов офисной коммуникации в прошлом году или около того, я уверен, что вы много слышали о Slack . На первый взгляд, Slack — это просто еще одно чат-приложение, разработанное для бизнеса, но из-за его внимания к деталям и расширяемости многие комментаторы уже говорят, что этот инструмент кардинально изменит то, как мы работаем в будущем.

Как разработчики, мы в состоянии перейти к этой тенденции и подумать, как использовать Slack в качестве пользовательского интерфейса на основе чата для наших приложений.

Вот почему в этом руководстве вы узнаете, как начать интеграцию PHP-приложения со Slack, отправляя сообщения в канал Slack и отвечая на команды слэша.

Вы можете скачать исходный код для учебника из связанного репозитория GitHub или создать его самостоятельно во время прохождения учебника.

Код учебника состоит из двух частей:

  • простой, но полный интерфейс для общения со Slack
  • простой пример сценария, который использует класс Slack для отправки уведомлений и ответа на команду слэша

Давайте начнем.

Быстрый поиск в Google по термину «Slack PHP» приводит к появлению нескольких различных интерфейсов Slack, созданных другими разработчиками, так что вы также можете перейти к существующему проекту и подключить его к своему приложению.

Но API совсем не сложен, поэтому нет причин не повеселиться и подойти к проекту с самого начала. Таким образом, вы будете знать, что в API (и ваша интеграция). Всегда хорошо немного демистифицировать вещи.

В основе этого руководства лежит построение интерфейса Slack, но для его использования и тестирования нам также потребуется приложение. Для этого я решил использовать простое PHP-приложение, которое не использует никаких фреймворков.

Вот как будет работать пример приложения:

  1. При первом запуске приложения вы увидите кнопку «Добавить в Slack» для подключения приложения к каналу Slack.
  2. Нажатие на кнопку проведет вас через аутентификацию Slack на основе OAuth. Когда приложение получает токен доступа от Slack, оно сохраняет его в текстовом файле, чтобы позднее оно могло использовать его для общения со Slack.
  3. Когда аутентификация на основе OAuth будет завершена, приложение покажет простое текстовое поле, которое можно использовать для отправки забавных уведомлений («О да, я робот!») На ваш канал Slack.
  4. Наконец, за кулисами приложение будет реагировать на команды слэша, которые вы или ваши товарищи по команде набираете на связанном канале Slack.
Пример приложения

Вы можете запустить приложение на сервере с поддержкой PHP в Интернете или следовать инструкциям в этом руководстве и запустить его на своем локальном компьютере для разработки.

Демонстрационное приложение предназначено только для демонстрационных целей, поэтому, в конце концов, вы, вероятно, возьмете интерфейс Slack и подключите его к существующему проекту WordPress, Laravel или другому PHP. В этом уроке я поделюсь некоторыми идеями о том, как вы можете использовать интерфейсный класс в реальном приложении вместо нашего простого демонстрационного приложения.

Во-первых, давайте начнем с создания базовой архитектуры проекта и размещения всех файлов на месте.

Если вы загрузили исходный код с GitHub, вы можете просто быстро просмотреть этот шаг, чтобы убедиться, что вы понимаете, как организован код, а затем перейти к следующему шагу.

Внутри каталога проекта создайте следующую файловую структуру:

  1. index.php : файл для примера приложения, описанного выше.
  2. slack-interface : каталог, который будет содержать интерфейс Slack, который мы создадим в этом уроке. Каталог будет содержать три файла:
    1. slack-interface/class-slack.php : интерфейсный класс Slack.
    2. slack-interface/class-slack-access.php : класс для хранения информации о доступе Slack и передачи ее приложению с помощью интерфейса.
    3. slack-interface/class-slack-api-exception.php : класс исключений для передачи ошибок из интерфейса в код, использующий его.

Затем, с файлами на месте, давайте добавим некоторый контент к каждому из них, чтобы у нас была основа для разработки реальной функциональности.

Начните с добавления основной HTML-формы и некоторого заполнителя в index.php :

001
002
003
004
005
006
007
008
009
010
011
012
013
014
+015
016
+017
018
019
020
021
022
023
024
025
026
027
028
029
+030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
+055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
<?php
/**
 * A lightweight example script for demonstrating how to
 * work with the Slack API.
 */
  
// Include our Slack interface classes
require_once ‘slack-interface/class-slack.php’;
require_once ‘slack-interface/class-slack-access.php’;
require_once ‘slack-interface/class-slack-api-exception.php’;
 
use Slack_Interface\Slack;
use Slack_Interface\Slack_API_Exception;
 
//
// HELPER FUNCTIONS
//
 
/**
 * Initializes the Slack object.
 *
 * @return Slack The Slack interface object
 */
function initialize_slack_interface() {
    return null;
}
 
/**
 * Executes an application action (eg ‘send_notification’).
 *
 * @param Slack $slack The Slack interface object
 * @param string $action The id of the action to execute
 *
 * @return string A result message to show to the user
 */
function do_action( $slack, $action ) {
    $result_message = »;
 
    switch ( $action ) {
        default:
            break;
    }
 
    return $result_message;
}
 
//
// MAIN FUNCTIONALITY
//
 
// Setup the Slack interface
$slack = initialize_slack_interface();
 
// If an action was passed, execute it before rendering the page
$result_message = »;
if ( isset( $_REQUEST[‘action’] ) ) {
    $action = $_REQUEST[‘action’];
    $result_message = do_action( $slack, $action );
}
 
//
// PAGE LAYOUT
//
 
?>
<html>
    <head>
        <title>Slack Integration Example</title>
         
        <style>
            body {
                font-family: Helvetica, sans-serif;
                padding: 20px;
            }
             
            .notification {
                padding: 20px;
                background-color: #fafad2;
            }
 
            input {
                padding: 10px;
                font-size: 1.2em;
                width: 100%;
            }
        </style>
    </head>
     
    <body>
        <h1>Slack Integration Example</h1>
 
        <?php if ( $result_message ) : ?>
            <p class=»notice»>
                <?php echo $result_message;
            </p>
        <?php endif;
 
        <form action=»» method=»post»>
            <input type=»hidden» name=»action» value=»send_notification»/>
            <p>
                <input type=»text» name=»text» placeholder=»Type your notification here and press enter to send.»
            </p>
        </form>
    </body>
</html>

Давайте посмотрим на содержание скрипта и что там на данный момент:

  • В строках 7-13 мы сначала включаем файлы библиотеки, а затем уведомляем PHP о том, что будем использовать классы Slack и Slack_API_Exception из пространства имен Slack_Interface . Файлы и класс еще не существуют, но мы скоро к ним вернемся.
  • Далее, есть два заполнителя для вспомогательных функций. Первая вспомогательная функция initialize_slack_interface ( строки 19-26 ) устанавливает класс Slack для текущего сеанса.
  • Вторая вспомогательная функция, do_action ( строки 28-45 ) будет использоваться для обработки других действий, кроме отображения страницы — например, отправки отправленного сообщения на ваш канал Slack, но также получения входящих команд слеша от Slack.
  • Следуя вспомогательным функциям, есть «основная» функциональность нашего маленького приложения. Сначала приложение инициализирует объект Slack ( строка 52 ). Затем в строках 54-59 он проверяет, было ли запрошено action параметр action . Если да, приложение выполняет действие, используя нашу вспомогательную функцию do_action .
  • Остальная часть сценария — это основной HTML (и немного CSS, который я написал в том же файле, чтобы упростить задачу), который отображает форму, которую вы видели на изображении выше.

Затем добавьте некоторый контент в файлы классов, которые составляют наш интерфейс Slack.

В class-slack.php добавьте следующий код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
<?php
namespace Slack_Interface;
 
/**
 * A basic Slack interface you can use as a starting point
 * for your own Slack projects.
 */
class Slack {
 
    private static $api_root = ‘https://slack.com/api/’;
 
    public function __construct() {
         
    }
 
}

Класс пока не содержит никаких функций, за исключением конструктора-заполнителя и определения корневого URL-адреса для Slack API. В строке 2 вы также заметите, что класс находится в пространстве имен Slack_Interface .

Аналогично, в class-slack-access.php добавьте следующий код:

01
02
03
04
05
06
07
08
09
10
11
12
13
<?php
namespace Slack_Interface;
 
/**
 * A class for holding Slack authentication data.
 */
class Slack_Access {
 
    public function __construct( $data ) {
 
    }
 
}

Наконец, добавьте следующее содержимое в class-slack-api-exception.php :

01
02
03
04
05
06
07
08
09
10
11
<?php
namespace Slack_Interface;
 
use Exception;
 
/**
 * A simple exception class for throwing Slack API errors.
 */
class Slack_API_Exception extends Exception {
 
}

Теперь мы создали фреймворк для нашего приложения Slack и готовы начать добавлять некоторые функции.

Но сначала нам нужно сделать приложение доступным в Интернете, чтобы Slack мог с ним общаться.

Прежде чем вы сможете зарегистрировать свое приложение в Slack и сделать так, чтобы оно получало входящие звонки от Slack, вам сначала нужно сделать его доступным из Интернета.

Команды слеша также требуют, чтобы приложение использовало HTTPS. Если вам не нужны команды и вы просто хотите, чтобы ваше приложение могло отправлять уведомления, вы можете пропустить эту часть. Однако для этого руководства, поскольку входящие слеш-команды являются большой частью того, что мы хотим сделать, нам нужно решение, которое дает нам поддержку HTTPS.

Если на вашем веб-сервере уже настроен HTTPS, это естественный путь.

Другой вариант на этапе разработки заключается в использовании службы туннелирования, такой как localtunnel . Localtunnel предоставляет вашему серверу защищенный URL-адрес в Интернете, который можно указать на ваш веб-сервер, работающий на вашем локальном компьютере. Хотя это и не решение для живых приложений, при тестировании функциональности оно одновременно упрощает рабочий процесс (нет необходимости загружать файлы на сервер) и обеспечивает поддержку HTTPS из коробки.

Для начала установите localtunnel в соответствии с инструкциями на веб-сайте инструмента .

Затем запустите ваш веб-сервер, отметив порт, который слушает ваш сервер.

И наконец, когда ваш сервер запущен, запустите localtunnel в терминале, используя следующую команду. Замените your_subdomain на предпочитаемый вами поддомен, а your_port на порт вашего веб-сервера:

1
lt -s your_subdomain -p your_port

Если запрошенный субдомен доступен, запускается localtunnel, и вы можете получить доступ к вашему серверу по адресу https://your_subdomain.localtunnel.me .

Туннелирование началось

Как только ваш сервер будет доступен из интернета, пришло время зарегистрировать новое приложение Slack.

Чтобы создать приложение Slack, войдите в свою учетную запись Slack и посетите страницу « Новое приложение» . Вы также можете найти ссылку на эту страницу, нажав Мои приложения в правом верхнем углу панели инструментов Slack API при входе.

На странице «Мои приложения» вы найдете ссылку «Добавить новое приложение».

Страница нового приложения выглядит следующим образом:

Страница нового приложения

На этой странице введите информацию о вашем приложении и нажмите « Создать приложение», чтобы сохранить его:

  • Имя приложения : имя для идентификации вашего приложения в списке приложений, а также в любых сообщениях, которые вы отправляете обратно в Slack. Я пошел с » Slack Tutorial «.
  • Команда : команда, для которой будет доступно приложение. Когда ваше приложение готово, вы можете отправить его в каталог приложений. На этом этапе команда Slack проверит его и, если все пойдет хорошо, сделает ваше приложение доступным для всех.
  • Краткое описание : описание, которое будет отображаться пользователям, когда они подключают ваше приложение к своим каналам Slack. Если вы просто тестируете, вы можете оставить это поле пустым. То же самое касается ссылки на инструкции по установке и информационного поля поддержки приложения .
  • Значок : значок, который будет показан вашим пользователям, когда они подключают ваше приложение к своим каналам Slack, а также в каждом сообщении, опубликованном вашим приложением.
  • URI перенаправления : URL-адрес, на который Slack будет перенаправлять пользователей после завершения процесса аутентификации. Мы рассмотрим это более подробно на шагах 5 и 6 ниже, но теперь просто установите в поле значение index.php?action=oauth в вашем приложении, например, https://your_subdomain.localtunnel.me/ slack -gration / index.php? action = oauth .

После создания определения приложения Slack оно будет отображаться в списке на странице « Мои приложения» . Там вы можете при необходимости отредактировать информацию о приложении и скопировать его учетные данные API (перечисленные в разделе с пометкой OAuth Information ) в свою интеграцию:

OAuth Информация

Затем, поскольку вы сохраните учетные данные API в своем PHP-приложении, полезно потратить некоторое время на то, чтобы подумать о том, как сделать это максимально безопасно.

В целом, не рекомендуется использовать такую ​​конфиденциальную информацию для контроля версий. Вместо этого вы можете выбрать один из следующих вариантов:

  • Хранение учетных данных в вашей базе данных может быть хорошей идеей, например, в плагине WordPress, где каждый пользователь будет иметь свой собственный набор учетных данных API, и вы хотите, чтобы они могли устанавливать свои учетные данные непосредственно из панели администратора .
  • Другой вариант (немного более безопасный, чем первый) — определить учетные данные в виде констант в файле конфигурации непосредственно на сервере (опять же, при работе с WordPress естественным выбором будет wp-config.php ). Просто убедитесь, что файл конфигурации не открыт внешнему миру (или не настроен на контроль версий).
  • Наконец, вы можете установить идентификатор клиента и секрет в качестве переменных среды на сервере. Таким образом, информация не сохраняется в файле, который может случайно просочиться за пределы приложения.

В нашей реализации мы будем использовать комбинацию двух последних методов. Чтобы интерфейс Slack знал об учетных данных API, добавьте две новые функции в класс Slack :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
 * Returns the Slack client ID.
 *
 * @return string The client ID or empty string if not configured
 */
public function get_client_id() {
    // First, check if client ID is defined in a constant
    if ( defined( ‘SLACK_CLIENT_ID’ ) ) {
        return SLACK_CLIENT_ID;
    }
 
    // If no constant found, look for environment variable
    if ( getenv( ‘SLACK_CLIENT_ID’ ) ) {
        return getenv( ‘SLACK_CLIENT_ID’ );
    }
         
    // Not configured, return empty string
    return »;
}
 
/**
 * Returns the Slack client secret.
 *
 * @return string The client secret or empty string if not configured
 */
private function get_client_secret() {
    // First, check if client secret is defined in a constant
    if ( defined( ‘SLACK_CLIENT_SECRET’ ) ) {
        return SLACK_CLIENT_SECRET;
    }
 
    // If no constant found, look for environment variable
    if ( getenv( ‘SLACK_CLIENT_SECRET’ ) ) {
        return getenv( ‘SLACK_CLIENT_SECRET’ );
    }
 
    // Not configured, return empty string
    return »;
}

Эти две функции являются почти точными копиями друг друга, поэтому давайте просто рассмотрим первую, get_client_id , чтобы понять, что они делают:

  • Сначала в строках 7-10 функция проверяет, сохранен ли идентификатор клиента в константе с именем SLACK_CLIENT_ID . Если эта константа определена, функция возвращает свое значение.
  • Если константа не была определена, функция продолжает поиск переменной окружения с тем же именем ( строки 12-15 ).
  • Наконец, если идентификатор клиента не найден, функция возвращает пустую строку.

Чтобы использовать этот подход, добавьте свои учетные данные для доступа в начале index.php или, что еще лучше, в отдельный файл PHP, который вы включаете в index.php но никогда не фиксируете контроль версий:

1
2
3
4
5
// Define Slack application identifiers
// Even better is to put these in environment variables so you don’t risk exposing
// them to the outer world (eg by committing to version control)
define( ‘SLACK_CLIENT_ID’, ‘Paste your client ID here’ );
define( ‘SLACK_CLIENT_SECRET’, ‘Paste your client secret here’ );

Теперь, когда мы сохранили учетные данные приложения, пришло время перейти на следующий уровень аутентификации: позволить вашим пользователям добавлять приложение в свои учетные записи Slack.

Процесс аутентификации состоит из трех этапов:

  1. Если пользователь еще не добавил приложение в Slack, в приложении отображается кнопка « Добавить в Slack ».
  2. После нажатия на кнопку пользователю предлагается авторизовать приложение для публикации уведомлений и ответа на команды на канале Slack.
  3. Когда пользователь авторизует приложение, ваше приложение получает временный код, который затем обменивается с набором данных постоянной аутентификации с использованием Slack API.

Мы скоро начнем реализовывать поток, но сначала нам понадобится метод для хранения и использования информации аутентификации, как только мы получим ее от Slack.

Для этого мы будем использовать класс Slack_Access , который мы создали ранее в руководстве.

В верхней части класса сначала определите переменные для хранения данных авторизации:

1
2
3
4
5
6
7
// Slack OAuth data
 
private $access_token;
private $scope;
private $team_name;
private $team_id;
private $incoming_webhook;

Затем реализуйте конструктор для чтения значений этих переменных из массива, переданного в качестве параметра:

01
02
03
04
05
06
07
08
09
10
11
12
13
/**
 * Sets up the Slack_Access object with authentication data.
 *
 * @param array $data The Slack OAuth authentication data.
 * hasn’t been authenticated, pass an empty array.
 */
public function __construct( $data ) {
    $this->access_token = isset( $data[‘access_token’] ) ?
    $this->scope = isset( $data[‘scope’] ) ?
    $this->team_name = isset( $data[‘team_name’] ) ?
    $this->team_id = isset( $data[‘team_id’] ) ?
    $this->incoming_webhook = isset( $data[‘incoming_webhook’] ) ?
}

Конструктор инициализирует переменные значениями, переданными в массиве $data , или пустыми значениями, если часть информации отсутствует в массиве атрибутов.

Сразу после конструктора добавьте функцию для проверки, был ли объект инициализирован с допустимыми данными:

1
2
3
4
5
6
7
8
/**
 * Checks if the object has been initialized with access data.
 *
 * @return bool True if authentication data has been stored in the object.
 */
public function is_configured() {
    return $this->access_token != »;
}

Затем для хранения данных аутентификации добавьте следующую функцию:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
/**
 * Returns the authorization data as a JSON formatted string.
 *
 * @return string The data in JSON format
 */
public function to_json() {
    $data = array(
        ‘access_token’ => $this->access_token,
        ‘scope’ => $this->scope,
        ‘team_name’ => $this->team_name,
        ‘team_id’ => $this->team_id,
        ‘incoming_webhook’ => $this->incoming_webhook
    );
 
    return json_encode( $data );
}

Функция возвращает строку в формате JSON, содержащую данные авторизации.

В реальном приложении вы, скорее всего, захотите связать информацию авторизации с учетными записями пользователей и сохранить данные JSON вместе с информацией о пользователях. Однако в нашем примере приложения — еще раз — мы будем использовать простой подход: мы предполагаем, что только один пользователь (вы) будет когда-либо использовать приложение, и поэтому нам нужно будет хранить только один набор учетных данных OAuth ,

Но сначала давайте перейдем к классу Slack и заставим его использовать функциональность, которую мы только что добавили в Slack_Access .

Реализуйте конструктор, чтобы настроить объект доступа для текущего экземпляра Slack :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
/**
 * @var Slack_Access Slack authorization data
 */
private $access;
 
/**
 * Sets up the Slack interface object.
 *
 * @param array $access_data An associative array containing OAuth
 * authentication information.
 * is not yet authenticated, pass an empty array.
 */
public function __construct( $access_data ) {
    if ( $access_data ) {
        $this->access = new Slack_Access( $access_data );
    }
}

Сразу после конструктора добавьте функцию для проверки, установлены ли данные авторизации в объекте Slack :

1
2
3
4
5
6
7
8
/**
 * Checks if the Slack interface was initialized with authorization data.
 *
 * @return bool True if authentication data is present.
 */
public function is_authenticated() {
    return isset( $this->access ) && $this->access->is_configured();
}

Имея структуру данных, мы можем начать использовать проверки авторизации в нашем основном приложении и показать кнопку «Добавить в Slack».

Обратите внимание, что хотя Slack_Access класс Slack_Access может использоваться в большинстве приложений практически как есть, решение, используемое в index.php , предназначено только для демонстрационных целей: поскольку у нас нет управления пользователями или базы данных, мы просто сохраним JSON- отформатированные учетные данные доступа из to_json в текстовом файле.

На данный момент файл еще не существует, что означает, что приложение еще не было добавлено в учетную запись Slack, и вместо текстового поля должна отображаться кнопка «Добавить в Slack».

Чтобы реализовать простую систему хранения, начните с замены функции initialize_slack_interface index.php следующим текстом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
 * Initializes the Slack handler object, loading the authentication
 * information from a text file.
 * the Slack handler is initialized in a non-authenticated state.
 *
 * @return Slack The Slack interface object
 */
function initialize_slack_interface() {
    // Read the access data from a text file
    if ( file_exists( ‘access.txt’ ) ) {
        $access_string = file_get_contents( ‘access.txt’ );
    } else {
        $access_string = ‘{}’;
    }
 
    // Decode the access data into a parameter array
    $access_data = json_decode( $access_string, true );
 
    $slack = new Slack( $access_data );
     
    return $slack;
}

В строках 9-14 функция считывает данные авторизации в виде строки из текстового файла с именем access.txt если файл существует. Если файл не существует, строка JSON инициализируется пустым хешем.

Затем в строке 17 данные анализируются в массив для передачи в интерфейс Slack (в строке 19 ).

Теперь мы готовы собрать все вместе и заставить наше маленькое приложение показывать кнопку «Добавить в Slack», если данные авторизации не найдены.

В конце index.php замените форму следующим фрагментом кода:

01
02
03
04
05
06
07
08
09
10
11
12
<?php if ( $slack->is_authenticated() ) : ?>
    <form action=»» method=»post»>
        <input type=»hidden» name=»action» value=»send_notification»/>
        <p>
            <input type=»text» name=»text» placeholder=»Type your notification here and press enter to send.»
        </p>
    </form>
<?php else : ?>
    <p>
        <a href=»https://slack.com/oauth/authorize?scope=incoming-webhook,commands&client_id=<?php echo $slack->get_client_id(); ?>»><img alt=»Add to Slack» height=»40″ width=»139″ src=»https://platform.slack-edge.com/img/add_to_slack.png» srcset=»https://platform.slack-edge.com/img/add_to_slack.png 1x, https://platform.slack-edge.com/img/[email protected] 2x»></a>
    </p>
<?php endif;

Во фрагменте кода в строке 1 вы заметите, что форма теперь окружена is_authenticated так что пользователь не может увидеть ее до авторизации приложения.

Затем в ветке else , в строках 8-12 , код теперь отображает кнопку «Добавить в Slack».

Давайте посмотрим на тег внутри кнопки:

  • Прежде всего, кнопка направляет пользователя в поток авторизации OAuth Slack ( oauth/authorize ).
  • Используя параметр scope , приложение может определить разрешения, которые ему необходимы для пользователя: в нашем случае нам нужны входящие веб incoming-webhook ( incoming-webhook ) для отправки уведомлений и возможность добавлять новые команды ( commands ) слеша. Полный список доступных разрешений можно найти в документации по API .
  • Наконец, ссылка должна содержать открытый ключ приложения ( client_id ), который мы сохранили в нашем приложении ранее в руководстве.

Остальное — просто основной HTML для отображения изображения кнопки.

Теперь, когда вы открываете приложение в своем веб-браузере, вот что вы должны увидеть:

Кнопка Добавить в Slack

Теперь кнопка «Добавить в Slack» на месте. Но что происходит, когда пользователь нажимает на него?

Сначала пользователь увидит страницу аутентификации приложения Slack, которая выглядит следующим образом:

Предоставить приложению Slack

Затем, если все выглядит хорошо для пользователя, он или она нажмет кнопку « Авторизовать» , после чего выполнение вернется в ваше приложение.

Вы помните, что когда мы определили приложение в Slack, мы установили URL обратного вызова ( YOUR_URL/index.php?action=oauth ).

Для обработки этого обратного вызова мы будем использовать систему действий, которую мы создали ранее в руководстве. В вашем реальном приложении вам нужно будет реализовать URL-адреса обратного вызова таким образом, чтобы это хорошо работало для используемой вами платформы. Например, в WordPress вы могли бы очень хорошо создать пользовательскую постоянную ссылку, используя механизм перезаписи.

Однако, хотя способ получения обратного вызова будет различаться в зависимости от приложения, то, что мы делаем с данными, полученными из Slack, остается прежним.

Замените все еще пустую функцию do_action следующим:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
 * Executes an application action (eg ‘send_notification’).
 *
 * @param Slack $slack The Slack interface object
 * @param string $action The id of the action to execute
 *
 * @return string A result message to show to the user
 */
function do_action( $slack, $action ) {
    $result_message = »;
 
    switch ( $action ) {
 
        // Handles the OAuth callback by exchanging the access code to
        // a valid token and saving it in a file
        case ‘oauth’:
            $code = $_GET[‘code’];
 
            // Exchange code to valid access token
            try {
                $access = $slack->do_oauth( $code );
                if ( $access ) {
                    file_put_contents( ‘access.txt’, $access->to_json() );
                    $result_message = ‘The application was successfully added to your Slack channel’;
                }
            } catch ( Slack_API_Exception $e ) {
                $result_message = $e->getMessage();
            }
            break;
 
        default:
            break;
 
    }
 
    return $result_message;
}

Когда пользователь возвращается из потока авторизации, эта функция 'oauth' с $action установленным в 'oauth' . Вместе с запросом приложение получает одноразовый токен, который он читает в строке 17 .

Затем в строке 21 для завершения авторизации функция вызывает функцию в нашем классе Slack , do_oauth .

Как вы помните ранее, при инициализации интерфейса Slack мы пытались загрузить данные аутентификации из текстового файла access.txt . Когда файл не был найден, приложение решило, что пользователь еще не аутентифицировал приложение, и показало кнопку «Добавить в Slack».

Теперь, после успешного завершения аутентификации OAuth, в строке 23 функция сохраняет данные в этот файл.

Но прежде чем мы доберемся туда, чтобы завершить процесс аутентификации, нам все же нужно реализовать функцию do_oauth в классе Slack .

Эта функция будет вызывать Slack API для обмена кодом, который был передан в функцию обратного вызова OAuth, с данными аутентификации, которые можно постоянно хранить и использовать для связи со Slack, пока пользователь не отменит авторизацию.

Для этого нам потребуется способ сделать HTTP-запрос к серверу Slack. Есть много способов сделать HTTP-запросы в PHP, и то, что здесь представлено, не единственный способ. Например, если вы разрабатываете для WordPress, вы можете использовать wp_remote_get и wp_remote_post .

Однако на этот раз, чтобы сохранить независимость от какой-либо конкретной среды разработки приложений, я решил использовать бесплатную библиотеку с красивым и чистым синтаксисом, Requests .

Установите библиотеку в соответствии с инструкциями на ее сайте. В исходном коде репозитория Tuts + GitHub вы найдете готовую конфигурацию Composer для включения библиотеки в наше приложение.

После установки запросов (или выбора библиотеки HTTP) добавьте функцию do_oauth в класс Slack :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
 * Completes the OAuth authentication flow by exchanging the received
 * authentication code to actual authentication data.
 *
 * @param string $code Authentication code sent to the OAuth callback function
 *
 * @return bool|Slack_Access An access object with the authentication data in place
 * if the authentication flow was completed successfully.
 * Otherwise false.
 *
 * @throws Slack_API_Exception
 */
public function do_oauth( $code ) {
    // Set up the request headers
    $headers = array( ‘Accept’ => ‘application/json’ );
         
    // Add the application id and secret to authenticate the request
    $options = array( ‘auth’ => array( $this->get_client_id(), $this->get_client_secret() ) );
 
    // Add the one-time token to request parameters
    $data = array( ‘code’ => $code );
 
    $response = Requests::post( self::$api_root . ‘oauth.access’, $headers, $data, $options );
         
    // Handle the JSON response
    $json_response = json_decode( $response->body );
 
    if ( ! $json_response->ok ) {
        // There was an error in the request
        throw new Slack_API_Exception( $json_response->error );
    }
 
    // The action was completed successfully, store and return access data
    $this->access = new Slack_Access(
        array(
            ‘access_token’ => $json_response->access_token,
            ‘scope’ => explode( ‘,’, $json_response->scope ),
            ‘team_name’ => $json_response->team_name,
            ‘team_id’ => $json_response->team_id,
            ‘incoming_webhook’ => $json_response->incoming_webhook
        )
    );
 
    return $this->access;
}

Давайте пройдемся по функции строка за строкой:

В строках 14-18 функция инициализирует параметры для HTTP-запроса. Стоит отметить, что идентификатор клиента и секрет передаются в качестве параметров запроса для использования базового механизма аутентификации HTTP.

В строке 21 вы заметите, что мы отправляем одноразовый токен, полученный в функции обратного вызова, обратно в Slack API для идентификации запроса.

Запрос POST отправляется в строке 23 . Затем функция выполняет синтаксический анализ ответа и либо устанавливает и возвращает данные авторизации ( строки 33-44 ), если все прошло успешно, либо выдает исключение ( строки 28-31 ), если в запросе произошла ошибка.

Теперь поток «Добавить в Slack» готов. Когда вы попробуете, вы должны увидеть следующее:

Поток аутентификации был успешно завершен

Кроме того, если вы загляните в каталог вашего проекта, вы должны найти текстовый файл с именем access.txt , в котором хранятся данные аутентификации.

Теперь мы готовы к забавной части: разместим приложение на вашем канале Slack.

Публикация уведомлений на канале Slack — это эффективный способ держать команду в курсе важных для них событий. Интернет-магазин может отправлять уведомления о новых покупках, программное обеспечение для отслеживания ошибок может автоматически уведомлять разработчиков, и этот список можно продолжить.

В нашем примере, как вы уже видели в пользовательском интерфейсе ранее, мы отправим любое уведомление, отправленное пользователем, с помощью текстового поля.

Но функциональность для отправки любых других типов уведомлений та же самая, поэтому, когда она будет готова, вы можете использовать тот же код для отправки собственных, более сложных уведомлений.

В классе Slack добавьте следующую функцию:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
 * Sends a notification to the Slack channel defined in the
 * authorization (Add to Slack) flow.
 *
 * @param string $text The message to post to Slack
 * @param array $attachments Optional list of attachments to send
 * with the notification
 *
 * @throws Slack_API_Exception
 */
public function send_notification( $text, $attachments = array() ) {
    if ( ! $this->is_authenticated() ) {
        throw new Slack_API_Exception( ‘Access token not specified’ );
    }
 
    // Post to webhook stored in access object
    $headers = array( ‘Accept’ => ‘application/json’ );
 
    $url = $this->access->get_incoming_webhook();
    $data = json_encode(
        array(
            ‘text’ => $text,
            ‘attachments’ => $attachments,
            ‘channel’ => $this->access->get_incoming_webhook_channel(),
        )
    );
 
    $response = Requests::post( $url, $headers, $data );
         
    if ( $response->body != ‘ok’ ) {
        throw new Slack_API_Exception( ‘There was an error when posting to Slack’ );
    }
}

Публикация уведомления на канале Slack осуществляется с помощью веб-крюка , URL-адреса для авторизации, который Slack предоставляет приложению для публикации на канале.

Ранее мы не обращали на это особого внимания в потоке «Добавить в Slack», но если вы снова посмотрите на данные в Slack_Access , вы заметите, что Slack возвращает поле с Slack_Access . Это поле представляет собой массив с двумя полями внутри: URL-адрес, на который мы должны публиковать наши уведомления, и канал, выбранный пользователем для сообщений приложения.

Чтобы получить доступ к этим данным, добавьте следующие две функции в класс Slack_Access :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
 * Returns the webhook URL for posting notifications.
 *
 * @return string The incoming webhook URL
 */
public function get_incoming_webhook() {
    if ( is_array( $this->incoming_webhook ) && isset( $this->incoming_webhook[‘url’] ) ) {
        return $this->incoming_webhook[‘url’];
    }
 
    return »;
}
 
/**
 * Returns the channel to which the user has authorized the application
 * to post notifications.
 *
 * @return string The selected Slack channel’s ID
 */
public function get_incoming_webhook_channel() {
    if ( is_array( $this->incoming_webhook ) && isset( $this->incoming_webhook[‘channel’] ) ) {
        return $this->incoming_webhook[‘channel’];
    }
 
    return »;
}

Теперь давайте вернемся к функции send_notification выше и посмотрим, как эти функции используются для отправки уведомления.

В строке 19 вы заметите, что HTTP-запрос отправляется на входящий URL-адрес веб-крюка, сохраненный в данных авторизации.

И позже, в строке 24 , канал передается в параметрах запроса вместе с текстом и любыми вложениями, которые мы хотим опубликовать.

Теперь, когда мы реализовали функцию отправки уведомлений, давайте прикрепим функциональность к нашему пользовательскому интерфейсу и протестируем ее.

Добавьте следующую новую ветвь do_action функцию do_action в index.php :

01
02
03
04
05
06
07
08
09
10
11
// Sends a notification to a Slack channel
case ‘send_notification’:
    $message = isset( $_REQUEST[‘text’] ) ?
 
    try {
        $slack->send_notification( $message );
        $result_message = ‘Notification sent to Slack channel.’;
    } catch ( Slack_API_Exception $e ) {
        $result_message = $e->getMessage();
    }
    break;

Этот фрагмент кода читает сообщение из параметров запроса ( строка 3 ) и использует функцию send_notification мы только что создали, чтобы опубликовать его в Slack ( строка 6 ).

Поскольку форма была создана уже в начале урока, теперь вы готовы отправить свое первое сообщение на свой канал Slack. Введите что-то в текстовое поле и нажмите Enter, чтобы отправить форму.

Затем посмотрите свой канал Slack, чтобы увидеть ваше сообщение:

Бот только что отправил свое первое сообщение

В функции send_notification вы, вероятно, заметили параметр под названием attachments . Я еще не упомянул об этом, так как это не очень хорошо вписывается в пример приложения. Однако вложения являются мощным способом передачи более интересной информации о событиях вашего приложения на канал Slack, и вы, вероятно, захотите использовать их в своих приложениях.

Итак, давайте немного поэкспериментируем с вложениями, немного изменив вызов send_notification из шага 2 . Замените вызов $slack->send_notification() следующим фрагментом кода:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$attachments = array(
    array(
        ‘fallback’ => ‘Jarkko just posted a new bread recipe.’,
 
        ‘title’ => ‘Sprouted Wheat Bread’,
        ‘title_link’ => ‘https://bread-magazine.com/sprouted-wheat-flour/’,
 
        ‘text’ => ‘Jarkko just posted a new bread recipe.
 
        ‘color’ => ‘#7CD197’,
 
        ‘fields’ => array(
            array(
                ‘title’ => ‘Preparation time’,
                ‘value’ => ‘:hourglass: 24 hours’,
                ‘short’ => true
            ),
            array(
                ‘title’ => ‘Difficulty’,
                ‘value’ => ‘Medium’,
                ‘short’ => true
            ),
        ),
        ‘image_url’ => ‘https://s3.amazonaws.com/interested/wordpress/wp-content/uploads/2015/02/12093547/sprouted-bread.jpg’
    )
);
 
$slack->send_notification( $message, $attachments );

Вложение, указанное в приведенном выше коде, является воображаемым уведомлением о добавлении нового рецепта хлеба в базу данных рецептов. Это просто в качестве примера, поэтому давайте изменим его, чтобы увидеть, как изменения, которые вы вносите в него, влияют на вывод на канале Slack.

  • fallback : обязательное текстовое сообщение, которое отображается, если вложение не может быть отображено.
  • title : Заголовок вложения, стилизованный с использованием более крупного шрифта.
  • title_link: URL, который будет открыт, когда пользователь нажимает на ссылку. В нашем примере это покажет рецепт.
  • text : Текст, который будет показан внутри вложения.
  • color : Цвет линии на левой стороне вложения.
  • fields: Список полей данных для отображения во вложениях. В примере они используются для отображения некоторой информации о рецепте.
  • image_url : URL-адрес изображения, отображаемого во вложении.

Вот что вы увидите, когда разместите уведомление с приложением, указанным выше:

Slack уведомление с приложением

Поиграйте с параметрами и посмотрите, как их изменение влияет на сообщения, публикуемые на вашем канале Slack: измените атрибуты, отправьте новое уведомление и посмотрите, что изменилось.

Для получения дополнительной информации о вложениях, посмотрите документацию Slack .

Ваше приложение теперь может общаться со Slack. Далее, мы сделаем взаимодействие также другим способом: добавив команды слеша, мы можем заставить Slack работать как интерфейс для нашего приложения.

В реальном приложении это имеет много вариантов использования. Пометка ошибки как исправленной, пометка заказа как отправленного или просьба пошутить — вот лишь некоторые из них, которые приходят на ум.

Давайте продолжим и реализуем запрос на шутку, чтобы опубликовать шутку, когда кто- /jokeто печатает на канале Slack.

Сначала зайдите на страницу настроек вашего Slack Application, чтобы определить новую команду слеша.

Прокрутите вниз до раздела с заголовком Slash Commands и нажмите Create new command .

Слэш Команды

На следующем экране введите необходимую информацию для указания новой команды и нажмите Сохранить .

Создать новую команду

Вот краткое описание полей на этой странице:

  • Команда : команда косой черты, включая символ косой черты. Например, /joke.
  • URL-адрес запроса : URL-адрес на вашем сервере, который следует вызывать, когда кто-то вводит эту команду косой черты на канале Slack. Здесь вам пригодится localtunnel: URL-адрес должен быть HTTPS и доступен для подключения через Интернет. Используйте следующий формат URL , чтобы сделать запрос URL совместим с функциональностью мы будем строить в шаге 2 ниже: YOUR_SERVER/index.php?action=command.
  • Краткое описание : описание, которое отображается во всплывающем окне автозаполнения, когда кто-то печатает команду.
  • Подсказка по использованию : если команда принимает параметры, вы можете описать их здесь. Этот текст также виден в диалоге автозаполнения.

После сохранения команды вы увидите вашу новую команду, показанную в разделе Slash Commands . Вы можете использовать кнопки для редактирования или удаления.

Команды слеша теперь включают команду шутки

Ниже списка команд вы найдете строку с меткой верификации .

Вы можете использовать этот токен, чтобы убедиться, что команды действительно поступают из Slack перед их выполнением. Сохраните токен в своем приложении так же, как вы делали для идентификатора клиента и секрета ранее в учебнике, например, добавив константу в начале index.php:

1
define( 'SLACK_COMMAND_TOKEN', 'Paste your command verification token here' );

Теперь Slack определит команду, когда кто-то наберет ее в окне чата Slack (вы можете попробовать ее сейчас, чтобы увидеть всплывающее окно автозаполнения).

Когда пользователь отправит команду, Slack вызовет наш сервер по URL-адресу запроса, указанному на предыдущем шаге. Теперь нам нужно реализовать функциональность, чтобы приложение правильно реагировало на него.

Поскольку вы можете добавить более одной команды слеша в свое приложение Slack, хорошо поддерживать переменное количество команд слеша. Вот почему мы начнем с создания системы для отслеживания команд слеша в приложении.

Сначала в Slackклассе добавьте следующую переменную для хранения команд:

1
2
3
4
5
/**
 * @var array $slash_commands An associative array of slash commands
 * attached to this Slack interface
 */
private $slash_commands;

В конструкторе класса добавьте строку для инициализации массива:

1
$this->slash_commands = array();

Затем создайте функцию для добавления новой команды слеша в массив:

01
02
03
04
05
06
07
08
09
10
/**
 * Registers a new slash command to be available through this
 * Slack interface.
 *
 * @param string $command The slash command
 * @param callback $callback The function to call to execute the command
 */
public function register_slash_command( $command, $callback ) {
    $this->slash_commands[$command] = $callback;
}

Теперь, когда у вас есть список команд слеша, добавьте функцию для выполнения команды:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
 * Runs a slash command passed in the $_POST data if the
 * command is valid and has been registered using register_slash_command.
 *
 * The response written by the function will be read by Slack.
 */
public function do_slash_command() {
    // Collect request parameters
    $token = isset( $_POST['token'] ) ? $_POST['token'] : '';
    $command = isset( $_POST['command'] ) ? $_POST['command'] : '';
    $text = isset( $_POST['text'] ) ? $_POST['text'] : '';
    $user_name = isset( $_POST['user_name'] ) ? $_POST['user_name'] : '';
 
    // Use the command verification token to verify the request
    if ( ! empty( $token ) && $this->get_command_token() == $_POST['token'] ) {
        header( 'Content-Type: application/json' );
 
        if ( isset( $this->slash_commands[$command] ) ) {
            // This slash command exists, call the callback function to handle the command
            $response = call_user_func( $this->slash_commands[$command], $text, $user_name );
            echo json_encode( $response );
        } else {
            // Unknown slash command
            echo json_encode( array(
                'text' => "Sorry, I don't know how to respond to the command."
            ) );
        }
    } else {
        echo json_encode( array(
            'text' => 'Oops... Something went wrong.'
        ) );
    }
 
    // Don't print anything after the response
    exit;
}

Давайте рассмотрим функцию, чтобы увидеть, что она делает:

Сначала в строках 8-12 функция собирает данные из параметров запроса:

  • token используется для проверки того, что запрос является действительным запросом команды Slack.
  • command содержит команду слеш, которая должна быть выполнена
  • textстрока текста, набранная после команды Это может быть использовано для передачи параметров в вашу команду слеш.
  • user_name имя пользователя, отправившего команду слэша

В строке 15 функция выполняет проверку, сравнивая токен, который был передан в параметрах запроса, с тем, который мы сохранили на предыдущем шаге.

Если токен действителен, функция продолжает выполнять команду, если в Slackклассе был зарегистрирован токен с данным именем команды . Выполнение команды выполняется в строке 20 , где функция выполняет вызов функции обратного вызова, указанной для команды.

Затем в строке 21 ответ кодируется в строку JSON и распечатывается. Обратите внимание, что функция заканчивается exitвызовом, чтобы убедиться, что после ответа больше ничего не печатается.

Чтобы завершить работу, добавьте функцию get_command_tokenдля получения токена проверки команды для приложения:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
/**
 * Returns the command verification token.
 *
 * @return string The command verification token or empty string if not configured
 */
private function get_command_token() {
    // First, check if command token is defined in a constant
    if ( defined( 'SLACK_COMMAND_TOKEN' ) ) {
        return SLACK_COMMAND_TOKEN;
    }
 
    // If no constant found, look for environment variable
    if ( getenv( 'SLACK_COMMAND_TOKEN' ) ) {
        return getenv( 'SLACK_COMMAND_TOKEN' );
    }
 
    // Not configured, return empty string
    return »;
}

Функциональность команды slash в классе Slack теперь завершена, и все, что осталось сделать, прежде чем мы сможем реализовать нашу первую команду, — это подключить URL обратного вызова к этому коду.

Для этого добавьте новую caseветку в do_actionфункцию в index.php:

1
2
3
4
5
// Responds to a Slack slash command. Notice that commands are
// registered at Slack initialization.
case 'command':
    $slack->do_slash_command();
    break;

Теперь, когда мы создали систему для обработки команд слеша в нашем приложении, давайте использовать ее для реализации функциональных возможностей /jokeкоманды.

Сначала, в конце функции initialize_slack_interface, добавьте следующие строки кода для регистрации команды и введите имя функции, которая будет обрабатывать команду:

1
2
// Register slash commands
$slack->register_slash_command( '/joke', 'slack_command_joke' );

Затем создайте функцию:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
 * A simple slash command that returns a random joke to the Slack channel.
 *
 * @return array A data array to return to Slack
 */
function slack_command_joke() {
    $jokes = array(
        "The box said 'Requires Windows Vista or better.' So I installed LINUX.",
        "Bugs come in through open Windows.",
        "Unix is user friendly. It's just selective about who its friends are.",
        "Computers are like air conditioners: they stop working when you open Windows.",
        "I would love to change the world, but they won't give me the source code.",
        "Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning."
    );
 
    $joke_number = rand( 0, count( $jokes ) - 1 );
 
    return array(
        'response_type' => 'in_channel',
        'text' => $jokes[$joke_number],
    );
}

Поскольку эта функция была создана просто как демонстрационная версия, она ничего не делает: она случайным образом выбирает одну из (довольно плохих) шуток и возвращает ее в формате, ожидаемом Slack.

Обратите внимание, что хотя эта командная функция не принимает никаких параметров, для более сложного примера вы можете добавить два параметра: $textполучить доступ к любым данным, которые пользователь ввел после команды, и $user_nameполучить имя пользователя, отправившего команду.

Чтобы проверить команду, наберитесь /jokeна канале Slack.

Приложение рассказывает анекдот

Вы уже прошли обучение и знаете, как интегрировать свое PHP-приложение со Slack. В ходе обучения вы также создали инструменты для отправки уведомлений на канал Slack, а также для ответов на команды, которые ваши пользователи вводят непосредственно в Slack.

Следующим шагом является воплощение этих идей в жизнь.

Подумайте о своем приложении и поищите места, где общение со Slack и прослушивание команд, поступающих из Slack, может сделать этот опыт более полезным и приятным для ваших пользователей, и реализовать их.

Платформа быстро развивается, как и API. Следите за тем, куда он идет, и постройте что-нибудь удивительное!