上一篇 Node.js https://www.v2ex.com/t/527999 之后,我们又写了 PHP 的教程如下 https://github.com/wenewzhang/mixin_labs-php-bot
希望 PHP 程序员喜欢
This tutorial will let you know how to write a Mixin Messenger bot in PHP. The bot can receive and response to user's message. User can pay token to bot and bot can transfer token to user.
You will create a bot in Mixin Messenger to receive user message after read the chapter.
This tutorial is written in PHP 7. So you need to install PHP, composer before writing code.
on macOS
brew update
brew install php@7.2
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === '93b54496392c062774670ac18b134c3b3a95e5a5e5c8f1a9f115f203b75bf9a129d5daa8ba6a13e2cc8a1da0806388a8') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
//install composer to /usr/local/opt/php@7.2/bin and give a brief name 'composer'
php composer-setup.php --install-dir=/usr/local/opt/php@7.2/bin --filename=composer
php -r "unlink('composer-setup.php');"
on Ubuntu
apt update
apt upgrade
//install php 7.2
apt-get install software-properties-common python-software-properties
add-apt-repository -y ppa:ondrej/php
apt-get update
apt-get install php7.2 php7.2-cli php7.2-common
//install composer
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === '93b54496392c062774670ac18b134c3b3a95e5a5e5c8f1a9f115f203b75bf9a129d5daa8ba6a13e2cc8a1da0806388a8') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
//install composer to /usr/local/bin and give a brief name 'composer'
php composer-setup.php --install-dir=/usr/local/bin --filename=composer
php -r "unlink('composer-setup.php');"
Make sure the install directory be include in the $PATH variable, run php -v and composer -V can check the installation, if console output like below, that's mean it's works!
wenewzha:minecraft wenewzhang$ php -v
PHP 7.2.13 (cli) (built: Dec 7 2018 10:41:23) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.2.13, Copyright (c) 1999-2018, by Zend Technologies
wenewzha:minecraft wenewzhang$ composer -V
Composer version 1.8.0 2018-12-03 10:31:16
Go to your documents then make a directory and name it, for example: mixin_labs-php-bot
mkdir mixin_labs-php-bot
mixin_labs-php-bot
Execute composer init in your project directory, according the prompt to create the composer.json,
root@iZj6cbmqen2lqp7l48nfgkZ:~/mixin_labs-php-bot# composer init
Welcome to the Composer config generator
This command will guide you through creating your composer.json config.
Package name (<vendor>/<name>) [user/mixin_labs-php-bot]:
Description []: PHP 7 bot for Mixin Messenger
Author [, n to skip]: JimmyZhang <zhangjingping@mixin.one>
Minimum Stability []:
Package Type (e.g. library, project, metapackage, composer-plugin) []:
License []:
Define your dependencies.
Would you like to define your dependencies (require) interactively [yes]? no
Would you like to define your dev dependencies (require-dev) interactively [yes]? no
{
"name": "user/mixin_labs-php-bot",
"description": "PHP 7 bot for Mixin Messenger",
"authors": [
{
"name": "JimmyZhang",
"email": "zhangjingping@mixin.one"
}
],
"require": {}
}
Do you confirm generation [yes]? yes
This tutorial need a library mixin-sdk-php and Ratchet pawl, mixin-sdk-php is a PHP SDK for Mixin Network, the Ratchet pawl is a asynchronous websocket client. So, add them in the "require" block.
"require": {
"exinone/mixin-sdk-php": "^1.1",
"ratchet/pawl": "^0.3.3",
},
Save the composer.json, then execute composer install to download the packages.
composer install
After the downloading finished, you can find a vendor under the project directory.
root@iZj6cbmqen2lqp7l48nfgkZ:~/mixin_labs-php-bot# ls
composer.json composer.lock vendor
If you clone this repository, just execute composer install to download all dependency packages.
Create an app by following tutorial.
Remember to generate parameter and write down required information, they are required in config.php file soon.
https://github.com/wenewzhang/mixin_labs-php-bot/blob/master/mixin_network-keys.jpg In the folder, create a file: config.php. Copy the following content into it.
config.php
return [
'mixin_id' => '7000101716',
'client_id' => 'a1ce2967-a534-417d-bf12-c86571e4eefa',
'client_secret' => '7339866727d24eeec1c4ebb6c634fd25a7b9057ee6d5939cca9b6b9fc15f4d1f',
'pin' => '512772',
'pin_token' => 'abRdNq6soRALRG434IgR7WS/qP7LOcpfviqSfWfABdIKyZGLnWXFMrVCHpChIkBRGRAcsUguni0OoNsShddPVL3qoD5fxbF5dRUiRv14urH1Pmdl6zIZdCH159QMr5wLmmSHSGu2AihNkUHUo3bAJsrvOW0nke5y6R5YE/pNNfo=',
'session_id' => '51faabbf-48ff-4df2-898d-e9b318afae35',
'private_key' => <<<EOF
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCuKI65sJR9lQ1+kyKouWu3CpmkPdJKaFqKVMEWk9RRH1Wgju9n
z/y5MiBVZKUeeIYtwrCNKbbdkSPqMoj1kLh5XUk4HaV9DUt+s9USBHOgU8m5Pxov
Km+HQ+Pam62lHWn6ClYaNrDihpcdDg9i7Y8hY1cgKiUcdkFQmDQ9lz2VHwIDAQAB
AoGANHJSSOk8TnVMkwmMLnNoVL8EdcmIQpAac/4CB+KM1cEx8CAbSJAB82N9CTo9
32c8QRuYP2qIf0DuJ+EADbN/Wc3o9zRY3dkbnLo144g3YaKwDccSgUMux03ANHlP
MEPDxOUbxJTRPXmKgUZmGJrkAClGbr3pPyQDDHDWRQc9JUECQQDT7pUYcXtu+hSc
nAlZllzqkBG2gZrDYpPJ0JirpfNhaApBo+CGZYKQ1961o6+HcI9gZmZA8hPEhT6p
PlubjqxbAkEA0l89du8TIUGrY9/sxyfZif6aeEztXPwBHZ9r8dm0L8Mlu5zTrOX2
SUgu3znM6djmuRMS45iPHJbPkvw9ilaljQJBAJRN323Ec/D79ZKGKpDThN/rw0lo
tolFoU/Xtg5fycl/CbZXXFYQEOcU+Nc43Ss1HFAEOEf4Xtbluyyp42ce1wMCQElv
P4htyhK41rglaYTXr0NRYeCOkej8evM5PDgPU6u8hkZoZyeamo9YKCx6A8K5mUiP
lO9nyMUlC852SJEqz90CQQDBguGg5GGcfehpIZwERlMJgKGg1+13/9GfnEPdAW2v
px7DZoMG/pQ/SEa53tJHmGGD9+qyp93z/fEPXsD5RSwx
-----END RSA PRIVATE KEY-----
EOF
, //import your private_key
];
Replace the value with YOUR APP mixin_id, client_id, client_secret, and the pin, pin token, session_id, private key you have already generated them in dashboard.
Fill the following content in app.php, create it if it is missing in your folder
<?php
require __DIR__ . '/vendor/autoload.php';
use ExinOne\MixinSDK\Traits\MixinSDKTrait;
use ExinOne\MixinSDK\MixinSDK;
use Ramsey\Uuid\Uuid;
use Ratchet\RFC6455\Messaging\Frame;
$loop = \React\EventLoop\Factory::create();
$reactConnector = new \React\Socket\Connector($loop, [
'timeout' => 15
]);
$connector = new \Ratchet\Client\Connector($loop,$reactConnector);
class callTraitClass {
use MixinSDKTrait;
public $config;
public function __construct()
{
$config = require(__DIR__.'/config.php');
$this->config = $config;
}
}
$callTrait = new callTraitClass();
$Token = $callTrait->getToken('GET', '/', '');
// $connector('ws://127.0.0.1:9000', ['protocol' => 'Mixin-Blaze-1'], ['Origin' => 'http://localhost',
$connector('wss://blaze.mixin.one', ['protocol' => 'Mixin-Blaze-1'],[
'Authorization' => 'Bearer '.$Token
])
->then(function(Ratchet\Client\WebSocket $conn) {
$conn->on('message', function(\Ratchet\RFC6455\Messaging\MessageInterface $msg) use ($conn) {
$jsMsg = json_decode(gzdecode($msg));
print_r($jsMsg);
if ($jsMsg->action === 'CREATE_MESSAGE' and property_exists($jsMsg,'data')) {
echo "\nNeed reply server a receipt!\n";
$RspMsg = generateReceipt($jsMsg->data->message_id);
$msg = new Frame(gzencode(json_encode($RspMsg)),true,Frame::OP_BINARY);
$conn->send($msg);
if ($jsMsg->data->category === 'PLAIN_TEXT') {
$msgData = sendPlainText($jsMsg->data->conversation_id,
base64_decode($jsMsg->data->data));
$msg = new Frame(gzencode(json_encode($msgData)),true,Frame::OP_BINARY);
$conn->send($msg);
} //end of PLAIN_TEXT
} //end of CREATE_MESSAGE
});
$conn->on('close', function($code = null, $reason = null) {
echo "Connection closed ({$code} - {$reason})\n";
});
/* start listen for the incoming message */
$message = [
'id' => Uuid::uuid4()->toString(),
'action' => 'LIST_PENDING_MESSAGES',
];
print_r(json_encode($message));
$msg = new Frame(gzencode(json_encode($message)),true,Frame::OP_BINARY);
$conn->send($msg);
// $conn->send(gzencode($msg,1,FORCE_DEFLATE));
}, function(\Exception $e) use ($loop) {
echo "Could not connect: {$e->getMessage()}\n";
$loop->stop();
});
$loop->run();
function sendPlainText($conversation_id,$msgContent):Array {
$msgParams = [
'conversation_id' => $conversation_id,
'category' => 'PLAIN_TEXT',
'status' => 'SENT',
'message_id' => Uuid::uuid4()->toString(),
'data' => base64_encode($msgContent),//base64_encode("hello!"),
];
$msgPayButton = [
'id' => Uuid::uuid4()->toString(),
'action' => 'CREATE_MESSAGE',
'params' => $msgParams,
];
return $msgPayButton;
}
function generateReceipt($msgID):Array {
$IncomingMsg = ["message_id" => $msgID, "status" => "READ"];
$RspMsg = ["id" => Uuid::uuid4()->toString(), "action" => "ACKNOWLEDGE_MESSAGE_RECEIPT",
"params" => $IncomingMsg];
return $RspMsg;
}
Run the app.php
php app.php
If everything is ok, the following content will be display
wenewzha:mixin_labs-php-bot wenewzhang$ php helloworld.php
a1ce2967-a534-417d-bf12-c86571e4eefa{"id":"4454b6c5-4a89-440c-bd22-7a79cf4954ca","action":"LIST_PENDING_MESSAGES"}stdClass Object
(
[id] => 4454b6c5-4a89-440c-bd22-7a79cf4954ca
[action] => LIST_PENDING_MESSAGES
)
In Mixin Messenger,add the bot as your friend,(for example, this bot id is 7000101639) and then send any text!
https://github.com/wenewzhang/mixin_labs-php-bot/blob/master/helloworld.jpeg
The WebSocket providing full-duplex communication channels over a single TCP connection, It is a persistence connection, so create loop for the connection.
$loop = \React\EventLoop\Factory::create();
$reactConnector = new \React\Socket\Connector($loop, [
'timeout' => 15
]);
$connector = new \Ratchet\Client\Connector($loop,$reactConnector);
To receive message from Mixin messenger user, the application need to create a connection to Mixin Messenger server. The application also need to create a token which is used in later communication.
API of the operation, Guide of the operation
The mixin-sdk-php implements the getToken function, call it and generate token here.
class callTraitClass {
use MixinSDKTrait;
public $config;
public function __construct()
{
$config = require(__DIR__.'/config.php');
$this->config = $config;
}
}
$callTrait = new callTraitClass();
$Token = $callTrait->getToken('GET', '/', '');
Connect to the mixin.one server.
$connector('wss://blaze.mixin.one', ['protocol' => 'Mixin-Blaze-1'],[
'Authorization' => 'Bearer '.$Token
])
Then add onMessage to receive and analyze the incoming messages
->then(function(Ratchet\Client\WebSocket $conn) {
$conn->on('message', function(\Ratchet\RFC6455\Messaging\MessageInterface $msg) use ($conn) {
$jsMsg = json_decode(gzdecode($msg));
print_r($jsMsg);
if ($jsMsg->action === 'CREATE_MESSAGE' and property_exists($jsMsg,'data')) {
echo "\nNeed reply server a receipt!\n";
$RspMsg = generateReceipt($jsMsg->data->message_id);
$msg = new Frame(gzencode(json_encode($RspMsg)),true,Frame::OP_BINARY);
$conn->send($msg);
if ($jsMsg->data->category === 'PLAIN_TEXT') {
$msgData = sendPlainText($jsMsg->data->conversation_id,
base64_decode($jsMsg->data->data));
$msg = new Frame(gzencode(json_encode($msgData)),true,Frame::OP_BINARY);
$conn->send($msg);
} //end of PLAIN_TEXT
} //end of CREATE_MESSAGE
});
$conn->on('close', function($code = null, $reason = null) {
echo "Connection closed ({$code} - {$reason})\n";
});
Not only text messages, images and other type message can be received. You can find message details in Here.
Send the READ message to the server let it knows this message has already been read. If you don't send it, the bot will receive the duplicated message again after the bot connect to server again!
echo "\nNeed reply server a receipt!\n";
$RspMsg = generateReceipt($jsMsg->data->message_id);
$msg = new Frame(gzencode(json_encode($RspMsg)),true,Frame::OP_BINARY);
$conn->send($msg);
function generateReceipt($msgID):Array {
$IncomingMsg = ["message_id" => $msgID, "status" => "READ"];
$RspMsg = ["id" => Uuid::uuid4()->toString(), "action" => "ACKNOWLEDGE_MESSAGE_RECEIPT",
"params" => $IncomingMsg];
return $RspMsg;
}
Now your bot is running. You can try your idea now,enjoy!
A full code is here
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.