balfour/whatsapp-client

此包已废弃且不再维护。未建议替代包。

一个用于通过chat-api.com API处理WhatsApp通信的库

0.0.1-alpha 2020-02-24 10:57 UTC

This package is auto-updated.

Last update: 2022-05-24 16:04:39 UTC


README

一个用于通过非官方chat-api.com WhatsApp API处理WhatsApp通信的库。

此库处于早期发布阶段,正在等待单元测试。

法律声明

此代码与WhatsApp及其关联公司或子公司无关,未经授权、维护、赞助或认可。这是一个仅用于教育目的的独立非官方API,应自行承担风险使用。

目录

安装

composer require balfour/whatsapp-client

使用

有关chat-api的更多文档,请参阅https://chat-api.com/en/swagger.html

创建客户端

use Balfour\WhatsApp\WhatsApp;
use GuzzleHttp\Client;

$guzzle = new Client();
$client = new WhatsApp(
    $guzzle,
    'https://euXXXX.chat-api.com/instanceXXXXXX',
    'your-api-token'
);

发送消息

$client->sendMessage('+27111111111', 'This is a test message.');

发送文件

use Balfour\WhatsApp\File;

$file = new File('https://placehold.it/600x600', 'my_image.png');

$client->sendFile('+27111111111', $file);

检索消息

$messages = $client->getMessages();

foreach ($messages as $message) {
    var_dump($message->getChatId());
    var_dump($message->getMessageId());
    var_dump($message->getPhoneNumber());
    var_dump($message->getType());
    var_dump($message->getMessage());
    var_dump($message->getMediaUrl());
    var_dump($message->getDate());
    var_dump($message->isOutbound());
    var_dump($message->isInbound());
    var_dump($message->getMessageNumber());
}

// in order to only retrieve messages from a specific message number, you can pass a message number into
// the getMessages() call

$messages = $client->getMessages(12345);

重启虚拟机

$client->reboot();

构建机器人

以下提供了一个连接触发器、操作和中间件的完整使用示例。

操作

操作是在匹配触发器或菜单选项时执行的反应。

此包附带以下操作

SendMessageAction

此操作以消息作为响应。

use Balfour\WhatsApp\Bot\Actions\SendMessageAction;

$action = new SendMessageAction('The weather in Cape Town, South Africa is 14°C.');

// or

$callable = function ($message) {
    // retrieve weather conditions
    $city = 'Cape Town, South Africa';
    $temperature = $myWeatherService->getTemperature($city);
    return sprintf('The weather in %s is %s', $city, $temperature);
};

$action = new SendMessageAction($callable);

SendFileAction

此操作以附加文件(或图像)作为响应。

use Balfour\WhatsApp\Bot\Actions\SendFileAction;
use Balfour\WhatsApp\File;

$file = new File('https://placehold.it/600x600', 'my_image.png');

$action = new SendFileAction($file);

SendMenuAction

请参阅菜单

EscapeMenuAction

请参阅菜单

SendAndActivateMenuAction

请参阅菜单

自定义

您可以通过创建一个实现ActionInterface的自定义类来自定义操作。

use Balfour\WhatsApp\Message;
use Balfour\WhatsApp\WhatsApp;

interface ActionInterface
{
    /**
     * @param WhatsApp $client
     * @param Message $message
     */
    public function execute(WhatsApp $client, Message $message): void;

    /**
     * @param Message $message
     * @return string|null
     */
    public function emulate(Message $message): ?string;
}

以下是一个重复接收消息的示例操作。

use Balfour\WhatsApp\Bot\Actions\ActionInterface;
use Balfour\WhatsApp\Message;
use Balfour\WhatsApp\WhatsApp;

class RepeatAndSendMessageAction implements ActionInterface
{
    /**
     * @param Message $message
     * @return string
     */
    protected function getResponse(Message $message): string
    {
        return sprintf('You said: %s', $message->getMessage());
    }
    
    /**
     * @param WhatsApp $client
     * @param Message $message
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function execute(WhatsApp $client, Message $message): void
    {
        $client->sendMessage($message->getPhoneNumber(), $this->getResponse($message));
    }

    /**
     * @param Message $message
     * @return string|null
     */
    public function emulate(Message $message): ?string
    {
        return sprintf(
            "Sending message to <%s>:\n\n%s",
            $message->getPhoneNumber(),
            $this->getResponse($message)
        );
    }
}

触发器

触发器是指执行操作的入站关键词或短语。

以下触发器被支持

StringTrigger

入站消息必须是完全匹配的。

use Balfour\WhatsApp\Bot\Actions\SendMessageAction;
use Balfour\WhatsApp\Bot\Triggers\StringTrigger;

// when the bot sees "!weather", it will respond with the current temperature
// the default is a case insensitive string comparison
// eg: will match !WEATHER, !weather or !Weather
$trigger = new StringTrigger(
    '!weather',
    new SendMessageAction('The weather in Cape Town, South Africa is 14°C.')
);

// if you want to do a case sensitive match, you can pass in true as the 3rd parameter
$trigger = new StringTrigger(
    '!weather',
    new SendMessageAction('The weather in Cape Town, South Africa is 14°C.'),
    true
);

StartsWithTrigger

入站消息必须以指定的字符串开头。

use Balfour\WhatsApp\Bot\Actions\SendMessageAction;
use Balfour\WhatsApp\Bot\Triggers\StartsWithTrigger;

$trigger = new StartsWithTrigger(
    'call',
    new SendMessageAction("We'll give you a call shortly!")
);

// this will match any inbound message which starts with 'call', eg: 'call', or 'call me'
// just like the StringTrigger, the matching is case insensitive by default
// you can force a case sensitive match by passing true as the 3rd parameter

RegexTrigger

入站消息必须匹配给定的正则表达式模式。

use Balfour\WhatsApp\Bot\Actions\SendMessageAction;
use Balfour\WhatsApp\Bot\Triggers\RegexTrigger;

$trigger = new RegexTrigger(
    '/^(hi|hello|howzit)$/i',
    new SendMessageAction("Hi There!")
);

菜单

单个菜单

这是一个单个菜单的示例。

必须使用触发器来激活菜单。(完整示例见文末)

use Balfour\WhatsApp\Bot\Actions\SendMessageAction;
use Balfour\WhatsApp\Bot\Menu\Menu;
use Balfour\WhatsApp\Bot\Menu\Option;

$options = [
    new Option(
        '1',
        'Get a random cat fact',
        new SendMessageAction('Cats can rotate their ears 180 degrees.')
    ),
    new Option(
        '2',
        'Fetch my available balance',
        new SendMessageAction('Your available balance is $10.00.')
    ),
];

$menu = new Menu(
    "Hello! I'm your friendly WhatsApp bot.",
    "You can press # to return to the main menu, or 'quit' to exit the menu.",
    $options
);

// this example returns an error message when the user messages an invalid menu option

$menu = new Menu(
    "Hello! I'm your friendly WhatsApp bot.",
    "You can press # to return to the main menu, or 'quit' to exit the menu.",
    $options,
    null,
    true,
    "I don't understand what you mean"
);

嵌套菜单

这是一个包含多个嵌套菜单的更复杂示例。

为了保持用户当前所在的菜单状态,我们必须使用一个实现MenuStateStoreInterface的方案。出于测试目的,此包附带了一个InMemoryMenuStateStore;然而在现实世界中,你可能会想使用一个可以在多个PHP进程之间持久化的存储,例如Redis缓存。

use Balfour\WhatsApp\Bot\Actions\SendMessageAction;
use Balfour\WhatsApp\Bot\Actions\SendAndActivateMenuAction;
use Balfour\WhatsApp\Bot\Menu\InMemoryMenuStateStore;
use Balfour\WhatsApp\Bot\Menu\Menu;
use Balfour\WhatsApp\Bot\Menu\Option;

$menuStateStore = new InMemoryMenuStateStore();

// first, build parent menu without any options
$root = new Menu(
    "Hello! I'm your friendly WhatsApp bot.",
    "You can press # to return to the main menu, or 'quit' to exit the menu."
);

// now, create weather menu, linking it to parent menu
$weatherOptions = [
    new Option(
        '1',
        'Cape Town, South Africa',
        new SendMessageAction('The weather in Cape Town, South Africa is 14°C.')
    ),
    new Option(
        '2',
        'Johannesburg, South Africa',
        new SendMessageAction('The weather in Johannesburg, South Africa is 9°C.')
    ),
];

$weatherMenu = new Menu(
    "Please select your city.",
    "You can press # to return to the main menu, @ to return to the previous menu or 'quit' to exit the menu.",
    $weatherOptions,
    $root
);

// add options to parent menu
$root->addOptions([
    new Option(
        '1',
        'Check the weather',
        new SendAndActivateMenuAction($weatherMenu, $menuStateStore)
    ),
    new Option(
        '2',
        'Fetch my available balance',
        new SendMessageAction('Your available balance is $10.00.')
    ),
]);

中间件

机器人使用中间件将入站消息匹配到触发器或菜单选项。分别称为ProcessTriggerProcessMenuOption

您还可以通过创建一个实现了MiddlewareInterface的类来编写自己的中间件。

use Balfour\WhatsApp\Bot\Actions\ActionInterface;
use Balfour\WhatsApp\Message;

interface MiddlewareInterface
{
    /**
     * @param Message $message
     * @return ActionInterface|null
     */
    public function getAction(Message $message): ?ActionInterface;
}

完整示例

此示例是从emulate.php脚本中复制的,可以使用php emulate.php在本地上运行。

use Balfour\WhatsApp\Bot\Actions\SendMessageAction;
use Balfour\WhatsApp\Bot\Actions\SendAndActivateMenuAction;
use Balfour\WhatsApp\Bot\Bot;
use Balfour\WhatsApp\Bot\Emulator;
use Balfour\WhatsApp\Bot\Menu\InMemoryMenuStateStore;
use Balfour\WhatsApp\Bot\Menu\Menu;
use Balfour\WhatsApp\Bot\Menu\Option;
use Balfour\WhatsApp\Bot\Middleware\ProcessMenuOption;
use Balfour\WhatsApp\Bot\Middleware\ProcessTrigger;
use Balfour\WhatsApp\Bot\Triggers\StringTrigger;
use Balfour\WhatsApp\Bot\Triggers\TriggerRegistry;

// create menus
$menuStateStore = new InMemoryMenuStateStore();

// first, build parent menu without any options
$root = new Menu(
    "Hello! I'm your friendly WhatsApp bot.",
    "You can press # to return to the main menu, or 'quit' to exit the menu."
);

// now, create weather menu, linking it to parent menu
$weatherOptions = [
    new Option(
        '1',
        'Cape Town, South Africa',
        new SendMessageAction('The weather in Cape Town, South Africa is 14°C.')
    ),
    new Option(
        '2',
        'Johannesburg, South Africa',
        new SendMessageAction('The weather in Johannesburg, South Africa is 9°C.')
    ),
];

$weatherMenu = new Menu(
    "Please select your city.",
    "You can press # to return to the main menu, @ to return to the previous menu or 'quit' to exit the menu.",
    $weatherOptions,
    $root
);

// add options to parent menu
$root->addOptions([
    new Option(
        '1',
        'Check the weather',
        new SendAndActivateMenuAction($weatherMenu, $menuStateStore)
    ),
    new Option(
        '2',
        'Fetch my available balance',
        new SendMessageAction('Your available balance is $10.00.')
    ),
]);


// create triggers
$triggers = new TriggerRegistry();

// when we get 'ping', we'll respond 'pong'
$triggers->register(new StringTrigger('ping', new SendMessageAction('pong!')));

// we'll want to bring up our root menu when the user types "menu"
$triggers->register(new StringTrigger('menu', new SendAndActivateMenuAction($root, $menuStateStore)));

// create bot with middleware loaded
$middleware = [
    new ProcessTrigger($triggers),
    new ProcessMenuOption($root, $menuStateStore)
];
$bot = new Bot($middleware);

// create & run emulator
$emulator = new Emulator($bot);
$emulator->run();

// if we were running this in the real world, we'll want to process any inbound message through the bot
// eg: when a message is received (via polling or web hook)
// $bot->process($message);

模拟器

此包包括一个模拟器脚本,允许您在不发送真实世界消息的情况下测试菜单选项和触发器。

您可以使用php emulate.php运行模拟器。