Hướng dẫn dùng generatetoken trong PHP

Hôm nay mình sẽ hướng dẫn các bạn generate token agora phục vụ cho video call

Xây dựng thư viện Agora

Tạo lớp AccessToken

Tạo file app/Libs/Agora/AccessToken.php


 1,
        "kPublishAudioStream" => 2,
        "kPublishVideoStream" => 3,
        "kPublishDataStream" => 4,
        "kPublishAudioCdn" => 5,
        "kPublishVideoCdn" => 6,
        "kRequestPublishAudioStream" => 7,
        "kRequestPublishVideoStream" => 8,
        "kRequestPublishDataStream" => 9,
        "kInvitePublishAudioStream" => 10,
        "kInvitePublishVideoStream" => 11,
        "kInvitePublishDataStream" => 12,
        "kAdministrateChannel" => 101,
        "kRtmLogin" => 1000,
    );

    public $appID;
    public $appCertificate;
    public $channelName;
    public $uid;
    public $message;

    public function __construct()
    {
        $this->message = new Message();
    }

    public function setUid($uid)
    {
        if ($uid === 0) {
            $this->uid = "";
        } else {
            $this->uid = $uid . '';
        }
    }

    public function isNonemptyString($name, $str)
    {
        if (is_string($str) && $str !== "") {
            return true;
        }
        echo $name . " check failed, should be a non-empty string";

        return false;
    }

    public static function init($appID, $appCertificate, $channelName, $uid)
    {
        $accessToken = new AccessToken();

        if (!$accessToken->isNonemptyString("appID", $appID) ||
            !$accessToken->isNonemptyString("appCertificate", $appCertificate) ||
            !$accessToken->isNonemptyString("channelName", $channelName)) {
            return null;
        }

        $accessToken->appID = $appID;
        $accessToken->appCertificate = $appCertificate;
        $accessToken->channelName = $channelName;

        $accessToken->setUid($uid);
        $accessToken->message = new Message();

        return $accessToken;
    }

    public static function initWithToken($token, $appCertificate, $channel, $uid)
    {
        $accessToken = new AccessToken();
        if (!$accessToken->extract($token, $appCertificate, $channel, $uid)) {
            return null;
        }

        return $accessToken;
    }

    public function addPrivilege($key, $expireTimestamp)
    {
        $this->message->privileges[$key] = $expireTimestamp;

        return $this;
    }

    public function extract($token, $appCertificate, $channelName, $uid)
    {
        $ver_len = 3;
        $appid_len = 32;
        $version = substr($token, 0, $ver_len);
        if ($version !== "006") {
            echo 'invalid version ' . $version;
            return false;
        }

        if (!$this->isNonemptyString("token", $token) ||
            !$this->isNonemptyString("appCertificate", $appCertificate) ||
            !$this->isNonemptyString("channelName", $channelName)) {
            return false;
        }

        $appid = substr($token, $ver_len, $appid_len);
        $content = (base64_decode(substr($token, $ver_len + $appid_len, strlen($token) - ($ver_len + $appid_len))));

        $pos = 0;
        $strPost = "0";
        $len = unpack("v", $content . substr($strPost, 2))[1];
        $pos += 2;
        $sig = substr($content, $pos, $len);
        $pos += $len;
        $crc_channel = unpack("V", substr($content, $pos, 4))[1];
        $pos += 4;
        $crc_uid = unpack("V", substr($content, $pos, 4))[1];
        $pos += 4;
        $msgLen = unpack("v", substr($content, $pos, 2))[1];
        $pos += 2;
        $msg = substr($content, $pos, $msgLen);

        $this->appID = $appid;
        $message = new Message();
        $message->unpackContent($msg);
        $this->message = $message;

        //non reversable values
        $this->appCertificate = $appCertificate;
        $this->channelName = $channelName;
        $this->setUid($uid);

        return true;
    }

    public function build()
    {
        $msg = $this->message->packContent();
        $val = array_merge(
            unpack("C*", $this->appID),
            unpack("C*", $this->channelName),
            unpack("C*", $this->uid),
            $msg
        );

        $sig = hash_hmac('sha256', implode(array_map("chr", $val)), $this->appCertificate, true);

        $crc_channel_name = crc32($this->channelName) & 0xffffffff;
        $crc_uid = crc32($this->uid) & 0xffffffff;

        $content = array_merge(
            unpack("C*", $this->packString($sig)),
            unpack("C*", pack("V", $crc_channel_name)),
            unpack("C*", pack("V", $crc_uid)),
            unpack("C*", pack("v", count($msg))),
            $msg
        );
        $version = "006";
        $ret = $version . $this->appID . base64_encode(implode(array_map("chr", $content)));

        return $ret;
    }

    public function packString($value)
    {
        return pack("v", strlen($value)) . $value;
    }
}

Tạo lớp Message

Tạo file app/Libs/Agora/Message.php


salt = rand(0, 100000);
        $date = new \DateTime("now", new \DateTimeZone('UTC'));
        $this->ts = $date->getTimestamp() + 24 * 3600;
        $this->privileges = array();
    }

    public function packContent()
    {
        $buffer = unpack("C*", pack("V", $this->salt));
        $buffer = array_merge($buffer, unpack("C*", pack("V", $this->ts)));
        $buffer = array_merge($buffer, unpack("C*", pack("v", count($this->privileges))));
        foreach ($this->privileges as $key => $value) {
            $buffer = array_merge($buffer, unpack("C*", pack("v", $key)));
            $buffer = array_merge($buffer, unpack("C*", pack("V", $value)));
        }
        return $buffer;
    }

    public function unpackContent($msg)
    {
        $pos = 0;
        $salt = unpack("V", substr($msg, $pos, 4))[1];
        $pos += 4;
        $ts = unpack("V", substr($msg, $pos, 4))[1];
        $pos += 4;
        $size = unpack("v", substr($msg, $pos, 2))[1];
        $pos += 2;

        $privileges = array();
        for ($i = 0; $i < $size; $i++) {
            $key = unpack("v", substr($msg, $pos, 2));
            $pos += 2;
            $value = unpack("V", substr($msg, $pos, 4));
            $pos += 4;
            $privileges[$key[1]] = $value[1];
        }
        $this->salt = $salt;
        $this->ts = $ts;
        $this->privileges = $privileges;
    }
}

Tạo lớp RtmTokenBuilder

Tạo file app/Libs/Agora/RtmTokenBuilder.php


addPrivilege($Privileges["kRtmLogin"], $privilegeExpireTs);
        
        return $token->build();
    }
}

Tạo agora service

Tạo file app/Services/AgoraService.php


appID = config('agora.app_id');
        $this->appCertificate = config('agora.app_certificate');
    }

    public function getRtcToken(string $channelName, int $uid = 0, int $expireTimestamp = 0)
    {
        try {
            $builder = AccessToken::init($this->appID, $this->appCertificate, $channelName, $uid);
            $builder->addPrivilege(AccessToken::$Privileges["kJoinChannel"], $expireTimestamp);
            
            return $builder->build();
        } catch (\Exception $e) {
            Log::error('[AGORA_GENERATE_RTC_TOKEN_ERROR] '. $e->getMessage());

            return false;
        }
    }

    public function getRtmToken(string $channelName, int $expireTimestamp = 0)
    {
        try {
            $token = RtmTokenBuilder::buildToken(
                $this->appID,
                $this->appCertificate,
                $channelName,
                RtmTokenBuilder::ROLE_RTM_USER,
                $expireTimestamp
            );

            return $token;
        } catch (\Exception $e) {
            Log::error('[AGORA_GENERATE_RTM_TOKEN_ERROR] '. $e->getMessage());

            return false;
        }
    }
}

Tạo file config agora

Tạo file app/config/agora.php


 env('AGORA_APP_ID', null),
    'app_certificate'      => env('AGORA_APP_CERTIFICATE', null),
];

Generate token agora

Tạo controller app/Http/Controller/AgoraController.php generate token


agoraService = app(AgoraService::class);
    }

    public function generateToken()
    {
        try {
            $channelName = (string) Uuid::generate(4);
            // Rtc token dùng để video call
            $token = $this->agoraService->getRtcToken($channelName);
            // Rtm token dùng để chat
            $rtmToken = $this->agoraService->getRtmToken($channelName);
            if (!$token || !$rtmToken) {
                $this->error('Generate token error');
            }

            $data = [
                'channel_name' => $channelName,
                'token' => $token,
                'rtm_token' => $rtmToken,
            ];

            return $this->success($data);
        } catch (Exception $e) {
            return $this->error($e->getMessage());
        }
    }
}

Tài liệu tham khảo agora generate token