V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
myrual
V2EX  ›  推广

使用 PHP7 的 Mixin Network 教程写好了,欢迎试用

  •  
  •   myrual · 2019-01-18 15:17:45 +08:00 · 2862 次点击
    这是一个创建于 2171 天前的主题,其中的信息可能已经有所发展或是发生改变。

    上一篇 Node.js https://www.v2ex.com/t/527999 之后,我们又写了 PHP 的教程如下 https://github.com/wenewzhang/mixin_labs-php-bot

    希望 PHP 程序员喜欢

    Mixin Messenger application development tutorial in 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.

    Index

    1. Create bot and receive message from user
    2. Receive coin and pay coin

    Create bot and receive message from user

    You will create a bot in Mixin Messenger to receive user message after read the chapter.

    PHP enviroment setup:

    This tutorial is written in PHP 7. So you need to install PHP, composer before writing code.

    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;"
    //install composer to /usr/local/opt/[email protected]/bin and give a brief name '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;"
    //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
    

    Create the project

    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 <[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
    

    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 you first app in developer dashboard

    Create an app by following tutorial.

    Generate parameter for your app

    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.

    Hello world

    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

    Source code explanation

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

    End

    Now your bot is running. You can try your idea now,enjoy!

    A full code is here

    第 1 条附言  ·  2019-01-18 20:11:33 +08:00
    第 2 条附言  ·  2019-01-23 12:08:02 +08:00
    可以收发比特币哦
    10 条回复    2019-01-21 13:44:23 +08:00
    ranwu
        1
    ranwu  
       2019-01-18 17:11:30 +08:00
    这是聊天机器人吗?
    myrual
        2
    myrual  
    OP
       2019-01-18 20:07:53 +08:00
    @ranwu 聊天,收款,付款都可以。
    myrual
        3
    myrual  
    OP
       2019-01-18 20:11:14 +08:00
    JimmyZhang
        4
    JimmyZhang  
       2019-01-18 21:35:45 +08:00
    用 php 写异步通迅,也是一个很好的尝试
    ericgui
        5
    ericgui  
       2019-01-19 00:37:59 +08:00
    @myrual 老铁,恕我孤陋寡闻哈,这个 MIXIN 是干啥的?
    Yien
        6
    Yien  
       2019-01-19 01:18:11 +08:00 via Android
    厉害,感谢分享。
    xiaotuzi
        7
    xiaotuzi  
       2019-01-19 09:13:35 +08:00 via iPhone
    如果是微信的机器人,我感觉迟早会被封。毕竟微信一直严打机器人。
    JimmyZhang
        8
    JimmyZhang  
       2019-01-19 10:32:42 +08:00
    Mixin Messenger 的机器人,你可以理解为小程序啊!如果你有一个想法,开发一个工具,但还需要 appstore 去审核,是不是太麻烦了?如果用 Mixin Messenger,就直接实现了。 @xiaotuzi @Yien @ericgui 当然,具体可以看看 mixin.one 的介绍。
    myrual
        9
    myrual  
    OP
       2019-01-21 13:43:45 +08:00
    @ericgui 为其他区块链服务的区块链项目,是一个专注实时转账的闪电网络。
    myrual
        10
    myrual  
    OP
       2019-01-21 13:44:22 +08:00
    @xiaotuzi 恰恰不是微信机器人。而是 Mixin messenger 机器人
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2570 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 44ms · UTC 10:39 · PVG 18:39 · LAX 02:39 · JFK 05:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.