PHP 收发比特币教程第一课:创建机器人 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
myrual
V2EX    推广

PHP 收发比特币教程第一课:创建机器人

  •  
  •   myrual 2019-02-18 10:23:22 +08:00 2234 次点击
    这是一个创建于 2472 天前的主题,其中的信息可能已经有所发展或是发生改变。
    <>Mixin Network 是一个免费的 极速的端对端加密数字货币交易系统. 在本章中,你可以按教程在 Mixin Messenger 中创建一个 bot 来接收用户消息, 学到如何给机器人转比特币 或者 让机器人给你转比特币. 英文原文

    创建一个接受消息的机器人

    通过本教程,你将学会如何用 PHP 创建一个机器人 APP,让它能接受消息.

    PHP 环境安装:

    本教程的程序基于 PHP 7 开发,所以你需要先安装 PHP7.2/PHP7.3 与 composer, 其中,composer 是 PHP 的包管理系统! on macOS

    brew update brew install [email protected] 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;" //将 PHP 安装到 /usr/local/opt/[email protected]/bin 目录,并取一个简单的各字:composer php composer-setup.php --install-dir=/usr/local/opt/[email protected]/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;" //将 PHP 安装到 /usr/local/opt/[email protected]/bin 目录,并取一个简单的各字:composer php composer-setup.php --install-dir=/usr/local/bin --filename=composer php -r "unlink('composer-setup.php');" 

    请确保 PHP 与 composer 安装在$PATH 包含的目录之内,直接运行php -vcomposer -V 就可以检查出来,如果提示如下,表示安装正确!

    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 

    如果提示 command not found,表示 bash 没有在$PATH 下找到 php,请重复以上的安装步骤!

    wenewzha:mixin_network-nodejs-bot2 wenewzhang$ php -v -bash: php: command not found 

    创建你的项目

    到你的工作文档中,创建一个目录,并取一个名字,比如:mixin_labs-php-bot

    mkdir mixin_labs-php-bot cd mixin_labs-php-bot 

    转到新创建的项目目录下, 执行 composer init, 依提示完成 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 <[email protected]> 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": "[email protected]" } ], "require": {} } Do you confirm generation [yes]? yes 

    本教程引用了 mixin-sdk-phpRatchet pawl, mixin-sdk-php 是一个 Mixin Network PHP SDK , Ratchet pawl 是一个 WebSocket 客户端. 打开 composer.json, 在"require"增加两行引用:

    "require": { "exinone/mixin-sdk-php": "^1.1", "ratchet/pawl": "^0.3.3", }, 

    保存 composer.json 后,执行 composer install 来下载:

    composer install 

    下载完成后,目录下会出现一个 vendor 的子目录。

    root@iZj6cbmqen2lqp7l48nfgkZ:~/mixin_labs-php-bot# ls composer.json composer.lock vendor 

    如果你是 git 克隆的源代码,直接执行 composer install 来下载依赖包。

    创建第一个机器人 APP

    按下面的提示,到 mixin.one 创建一个 APP

    生成相应的参数

    记下这些生成的参数 它们将用于 config.php 中.

    在项目目录下,创建 config.php,将生成的参数,替换成你的!

    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 ]; 

    需要替换的参数包括:mixin_id, client_id, client_secret, and the pin, pin token, session_id, private key.

    经典的 Hello world

    在项目目录下创建一个 app.php 文件,将下面的代码拷进去:

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

    保存,并在终端里执行 app.php

    php app.php 

    如果一切正常,提示如下:

    wenewzha:mixin_labs-php-bot wenewzhang$ php app.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 ) 

    在手机安装 Mixin Messenger,增加机器人为好友,(比如这个机器人是 7000101639) 然后发送消息给它,效果如下!

    源代码解释

    WebSocket 是建立在 TCP 基础之上的全双工通讯方式,我们需要建立一个 loop 循环来维持通迅。

    $loop = \React\EventLoop\Factory::create(); $reactCOnnector= new \React\Socket\Connector($loop, [ 'timeout' => 15 ]); $cOnnector= new \Ratchet\Client\Connector($loop,$reactConnector); 

    机器人 APP 通过 Mixin Messenger 服务器来接收用户发过来的消息,连接服务器,需要 Token 来验证用户的身份, 详细资料可参考如下链接: Token 认证, 接收服务器消息

    mixin-sdk-php 实现了令牌 Token 的生成(getToken), 调用代码如下:

    class callTraitClass { use MixinSDKTrait; public $config; public function __construct() { $cOnfig= require(__DIR__.'/config.php'); $this->cOnfig= $config; } } $callTrait = new callTraitClass(); $Token = $callTrait->getToken('GET', '/', ''); 

    连接到服务器,注意协议类型与 Token:

    $connector('wss://blaze.mixin.one', ['protocol' => 'Mixin-Blaze-1'],[ 'Authorization' => 'Bearer '.$Token ]) 

    向服务器发送"LIST_PENDING_MESSAGES",这样服务器才会将收到的消息发送给机器人 APP.

    /* 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); 

    增加侦听 onMessage 接收并分析消息:

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

    Mixin Messenger 支持的消息类型很多,具体可到下面链接查看: WebSocket 消息类型.

    每接收到一个消息,需要按消息编号(message_id)给服务器回复一个"已读"的消息,避免服务器在机器人重新登入后,再次发送处理过的消息!

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

    完成

    现在你的机器人 APP 运行起来了,你打算如何改造你的机器人呢?

    完整的代码在这儿

    2 条回复    2019-02-18 10:31:32 +08:00
    suktyo
        1
    suktyo  
       2019-02-18 10:27:01 +08:00
    好担心这玩意被注入一下


    那真是损失几个亿
    myrual
        2
    myrual  
    OP
       2019-02-18 10:31:32 +08:00
    可以来注入一下试试。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3899 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 00:07 PVG 08:07 LAX 16:07 JFK 19:07
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86