基於TP5使用Websocket框架之GatewayWorker開發電商平臺買家與賣家實時通訊

OldBoy~發表於2017-08-15

前段時間公司提了一個新的需求,在商品的詳情頁要實現站內買家和商品賣家實時通訊的功能以方便溝通促成交易,要開發此功能當時首先考慮到的就是swoole和workerman了,從網上大概瞭解了一下關於這兩款工具的闡述,功能都是相當強大的,考慮到專案的進度問題,還是選擇上手容易比較快的GatewayWorker和框架TP5。

先看一下我們前端設計高大上的模板,分別是使用者和賣家後臺。 功能還是比較全的,幾乎模仿的是QQ。

業務上的大概需求是,使用者在進入某個商品詳情頁下,給使用者提供一個和賣家溝通的介面,根據商品的ID找到對應的賣家,類似於淘寶,還有傳送圖片,傳送對應的商品連結;商戶後臺也差不多。

我們的平臺上有虛擬商品和實體商品兩大分類,當時也考慮到了訊息的讀取狀態。我的表最初設計如下,沒有加任何的索引,考慮的或許也不夠周全,有見地的前輩還望指點一二!

DROP TABLE IF EXISTS `hp_chat_log`;
CREATE TABLE `hp_chat_log` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '聊天記錄表主鍵id',
  `user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用者id',
  `merchant_id` varchar(15) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '商家id',
  `send_message` text COLLATE utf8_unicode_ci NOT NULL,
  `send_message_type` tinyint(1) NOT NULL DEFAULT '1' COMMENT '傳送訊息型別(1:普通文字;2:商品連結,3:使用者傳送圖片)',
  `sender` tinyint(1) NOT NULL DEFAULT '1' COMMENT '傳送方。1:使用者。2:商家',
  `send_time` int(11) NOT NULL DEFAULT '0' COMMENT '傳送時間',
  `read_status` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '是否已讀。0:未讀取。1:已讀取',
  `acc_isonline` tinyint(1) NOT NULL DEFAULT '0' COMMENT '接收方是否線上 (0:不線上;1:線上)',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=157 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

 模板有了,表設計好了,接下來就是搭建服務了,當前專案開發的框架用的是TP5,選擇的Websocket框架是GatewayWorker框架,關於GatewayWorker與TP5的整合方法可以看我的這篇文章,講到了在Linux和

Windows下的整合安裝。

http://www.cnblogs.com/wt645631686/p/7219519.html

整合好了之後需要根據當前伺服器的一些埠配置在修改一些預設的配置,因為需要客戶端通過指定的埠建立連線。

TP5整合好了之後Gateway和workerman的主體目錄結構都在TP5的框架目錄vendor下的workerman目錄下。需要修改裡面gateway目錄下的一些檔案的埠及IP地址配置。

 配置完成之後,進入專案目錄,按照workerman官方手冊提供的使用方法,用命令php start.php start啟動socket服務,如以下截圖,分別是1238和8282埠。當然可以在後臺執行,詳細的使用方法請參考手冊。

啟動好了之後那麼就需要在客戶端開始下手了,我們專案裡是在前端頁面裡用建立的連結。看前端程式碼

當前的所有程式碼並不是最終的,目前只是階段性開發,後期在專案中逐步完善。

var ws;
    // 連線服務端
    function connect() {
       // 建立websocket
       ws = new WebSocket("ws://"+document.domain+":8282");  //這裡如果使用127.0.0.1或者localhost會出現連線失敗。當時為了方便以後的維護,這裡在php的全域性檔案裡定義了一個常量來定義ip,後來本地開發完提交到linux伺服器環境之後發現連結失敗!按照此行程式碼會有效連線~
       console.log(ws);
       ws.onopen = onopen;
       ws.onmessage = onmessage;
       ws.onclose = function(e) {
        console.log(e);
          console.log("連線關閉,定時重連");
          connect();
       };
       ws.onerror = function(e) {
        console.log(e);
          console.log("出現錯誤");
       };
    }
     // 握手
    function onopen()
    {
        var joint = '{"type":"handshake","role":"user"}';
        ws.send(joint);
    }
    // 服務端發來訊息時
    function onmessage(e)
    {
        var data = JSON.parse(e.data);
          console.log(data);
        switch(data['type']){
            // 服務端ping客戶端
            case 'ping':
                ws.send('{"type":"pong"}');
                break;
            // 登入 更新使用者列表
            case 'handshake':
                bindUid(data.client_id);
                $('#client_id').val(data.client_id);
                break;
            // 提醒
            case 'reception':
                //{"type":"say","from_client_id":xxx,"to_client_id":"all/client_id","content":"xxx","time":"xxx"}
                warn(data['content'], data['time'], data['timestamp']);
                break;
        }
    }

    //繫結uid
    function bindUid (client_id) {
        var bindUrl = "{:url('push/push/BindUserClientId')}";
        $.post(bindUrl, {client_id: client_id}, function(data){
            console.log(data);
        }, 'json');
    }

    //傳送連線
    function sendLink () {
       sendTrigger('link');
    }
    // 傳送資訊
    function sendMessage (){
        sendTrigger('message');
    }
    function sendTrigger(sendType) {
      var toMid     = $('#toMid').val();
      var pid       = $('#pid').val();
      var message   = $("footer .send_content").val();
      var client_id = $('#client_id').val();
      var sendUrl   = "{:url('push/push/SendMessageToMerchant')}";
      $.ajax({
        url:sendUrl,
        type:'POST',
        data:{message:message,toMid:toMid,pid:pid,client_id:client_id,sendType:sendType},
        async:false,
        dataType:'JSON',
        success:function(data){
            data = JSON.parse(data);
            if (data.status < 0) {
                alert('傳送失敗,請稍後再試!');
            } else {
                $('#send_timestamp').val(data.timeStamp);
                $('#send_timestr').val(data.timeStr);
                if (sendType == 'link') {
                    $('#main').append(data.html);
                }
            }
        }
      })
    }

    // 提醒
    function warn(content, time, prevTmestamp){
        var V_image = $('#V_image').val();
        var str = '<div class="chat-receiver">' + timestampWarn(prevTmestamp, time) + '<div class="chat-avatar"><img src="'+ V_image+ '" alt=""></div>
        <div class="chat-content"><div class="chat-triangle"></div><span>
' + content + '</span></div>'; domChange(str); $("#main").scrollTop($("#main")[0].scrollHeight); } //傳送 function sender(content, time, prevTmestamp) { var user_image = $('#user_image').val(); var str = '<div class="chat-sender">' + timestampWarn(prevTmestamp, time) + '<div class="chat-avatar"><img src="' +user_image + '" alt="">
</div><div class="chat-content"><div class="chat-triangle"></div>
' + '<span>' + content + '</span></div></div>'; domChange(str); } //訊息時間控制 function timestampWarn (nowTimestamp , nowTime) { var prevTimestamp = $('#prev_timestamp').val(); $('#prev_timestamp').val(nowTimestamp); var timeOffset = 6; var accTime = ''; if ((nowTimestamp - prevTimestamp) > timeOffset) { accTime = '<div style="clear:both;"></div><p class="chat-history-date">' + nowTime + '</p>'; } return accTime; }
<body onload="connect();">
</body>

 在開發過程中,修改的GatewayWorker檔案並不多,除了幾個主要的埠及IP需要修改之外,僅僅修改一個重要的檔案就夠了,那就是Push模組(專案的通訊模組)同級的Events.php檔案。看一下專案需求裡

修改後的程式碼,一個方法;

/**
    * 當客戶端發來訊息時觸發
    * @param int $client_id 連線id
    * @param mixed $message 具體訊息
    */
   public static function onMessage($client_id, $message)
   {
        $message_data = json_decode($message,true);
        if (!$message_data) {
            return ;
        }
        switch($message_data['type']) {
            case 'pong':
                return;
            case 'handshake':                
                $new_message    = [
                    'type'      => $message_data['type'],
                    'client_id' => $client_id, 
                    'time'      => date('H:i:s')
                ];
                Gateway::sendToClient($client_id, json_encode($new_message));
                return;
            case 'send':
                if (!isset($message_data['toClientUid'])) {
                  throw new \Exception("toClient not set. client_ip:{$_SERVER['REMOTE_ADDR']}");
                }
                $toUid          = $message_data['toClientUid'];
                $message        = $message_data['content'];
                $new_message    = [
                    'type'      => 'reception',
                    'content'   => $message, 
                    'time'      => date('H:i:s'),
                    'timestamp' => time(),
                    'c_type'    => $message_data['c_type'],
                    'primary'   => $message_data['Db_id']
                ];  
                //傳送者角色
                $source_info = explode('_', $message_data['source']);
                if ($source_info[0] == 'U') {
            //為了安全,特意做了加密 $new_message[
'source'] = encrypt_hopeband($source_info[1], 'E', 'XXXXXXX');     } return Gateway::sendToUid($toUid, json_encode($new_message)); } }

 然後看一下Push模組下的控制器檔案,在配合前端在繫結客戶端ID及傳送資訊做的一些處理。

class Push extends Base{

    protected static $user_headimage = '';
    protected static $uid = null;



    public function __construct () {
        parent::__construct();
        $this->checkUserLogin();
        //使用者頭像暱稱等資訊
        self::$uid            = session('userinfo.uid');
        $user_info            = Hmodel\User::getUserChatinfoById(self::$uid);
        self::$user_headimage = json_decode($user_info['headimgurl'],true)[0];

    }


    public function chatAction () {
        $product_id = intval(input('param.pid', 0, 'int'));
        $toMid      = Hmodel\Product::getMidByProductid($product_id);
        if ($toMid === false) notFund();

        $productHtml = $this->returnProductData2Html($product_id, 'default');

        $int_toMid = substr($toMid, 2);
        $V_headInfo = Pmodel\Push::getVmerchantHeadImageByVid($int_toMid);
        $V_headimage = is_not_empty_array($V_headInfo) ? json_decode($V_headInfo['headimgurl'])[0] :'/uploads/logo.png';

        if (substr($toMid, 0, 1) == 'V') {
            $chatLogData = Pmodel\Push::getChatlogByUseridAndVid(self::$uid, $int_toMid); 
            if (is_not_empty_array($chatLogData)) {
                $chatLog = self::chatlogData2Html($chatLogData, $V_headimage);
            }
        } elseif (substr($toMid, 0, 1) == 'E') {

        }


        $view = new View;
        $view->assign('pHtml', $productHtml);
        $view->assign('toMid', $toMid);
        $view->assign('pid', $product_id);
        $view->assign('chatlogHtml', $chatLog);
        $view->assign('role', 'user');
        $view->assign('user_image', self::$user_headimage);
        $view->assign('V_image', $V_headimage);
        return $view->fetch();
    }


      private static function chatlogData2Html ($data = [], $V_headimage = '') {
        $todayTimestamp = strtotime(date('Y-m-d'));
        $html = '';
        foreach ($data as $k => $v) {
            $date = $v['send_time'] < $todayTimestamp ? date('Y/m/d H:i:s', $v['send_time']) : date('H:i:s', $v['send_time']);
            $time_nodes = '';
            if (($data[$k]['send_time'] - $data[$k-1]['send_time']) > 180) {
                $time_nodes = '<div style="clear:both;"></div><p class="chat-history-date">' .$date.'</p>';
            } 
            //sender->傳送方   1:使用者。2:商家
            if ($v['sender'] == 1) {
                
                //send_message_type->傳送訊息型別  (1:普通文字;2:商品連結)
                if ($v['send_message_type'] == 1) {
                    $html.= '<div class="chat-sender">';
                    $html.= $time_nodes;
                    $html.= '<div class="chat-avatar"><img src="' . self::$user_headimage . '" alt=""></div>';
                    $html.= '<div class="chat-content"><div class="chat-triangle"></div><span>' . $v['send_message'].'</span></div>';
                    $html.= '</div>';
                }elseif ($v['send_message_type'] == 2) {
                    $html.= $time_nodes;
                    $product_info = json_decode($v['send_message'],true);
                    $html.= self::productData2SendHtml($product_info);
                }elseif ($v['send_message_type'] == 3) {
                    $images_arr = json_decode($v['send_message'],true);
                  
                    $html.= '<div class="chat-sender">';
                    $html.= $time_nodes;
                    $html.= '<div class="chat-avatar"><img src="' . self::$user_headimage . '" alt=""></div>';
                    $html.= '<div class="chat-content"><div class="chat-triangle"></div>';
                    foreach ($images_arr as $v ) {
                        $html.= '<img src="' .WEB_SITE. '/' . $v . '" style="max-width:85%">';
                    }
                    $html.= '</div>';
                    $html.= '</div>';
                }
            }else {
                if ($v['send_message_type'] == 1) {
                    $html.= '<div class="chat-receiver">';
                    $html.= '<div class="chat-avatar"><img src="' . $V_headimage . '" alt=""></div>';
                    $html.= '<div class="chat-content"><div class="chat-triangle"></div><span>' . $v['send_message'].'</span></div>';
                    $html.= '</div>';
                }elseif ($v['send_message_type'] == 2) {

                }
            }
        }
        return $html;
    }
public function BindUserClientIdAction () {
        if (!Request::instance()->isPost()) { notFund(); }
        $bindUserid = 'U_' . session('userinfo.uid');
        $client_id = input("param.client_id", 0, "string"); 
        // 設定GatewayWorker服務的Register服務ip和埠
        Gateway::$registerAddress = SOCKET_SERVER_PORT;
        // client_id與uid繫結
        // Gateway::closeClient($client_id);
        return Gateway::bindUid($client_id, $bindUserid);
}
//使用者傳送訊息給商家
    public function SendMessageToMerchantAction () {
        if (!Request::instance()->isPost()) { notFund(); }
        $message   = $_POST['message']; 
        $toMid     = input('post.toMid', '' , 'string');
        $product_id= input('post.pid', 0, 'int');
        $client_id = input('post.client_id', '', 'string');
        $sendType  = input('post.sendType', '', 'string');



        if (!in_array($sendType,['link', 'message'])) {                             //客戶端錯誤
            return json_encode(['status' => -1]);
        }
        if (strlen($client_id) != 20 ) {                                            //客戶端錯誤
            return json_encode(['status' => -1]);
        }
        if (!is_not_empty_string($toMid) || !is_positive_integer($product_id)) {    //系統錯誤
            return json_encode(['status' => -2]);
        }
        $db_toMid      = Hmodel\Product::getMidByProductid($product_id);            //資料錯誤
        if ($db_toMid != $toMid) {
            return json_encode(['status' => -3]);
        }
        require_once dirname(dirname(__FILE__)) . '/Events.php';

        $uid            = session('userinfo.uid');
        $accIsOnline    = Gateway::isUidOnline($toMid) == 1 ? 1 : 0;                //判讀商家是否線上
        $message_type   = 1;
        if ($sendType == 'link') {
            $message_type = 2;
            $productData = $this->referProductData($product_id);
            unset($productData['product_price']);
            unset($productData['score']);
            unset($productData['product_stock']);
            unset($productData['product_param']);
            unset($productData['product_desc']);
            unset($productData['product_main']);
            unset($productData['category_id']);
            unset($productData['merchant_id']);
            $message = json_encode($productData);
        }
        //Log入庫
        $insertId       = Pmodel\Push::addChatLog($uid, $toMid, $message, $message_type, 1, $accIsOnline);
        if($message_type == 1){
            if(!is_numeric($message)){
                $message = '"'.$message.'"';
            }
            if ($message == '') {
                $message = '';
            }
        }
        if ($insertId === false) {                                                  //入庫失敗(伺服器故障)
            return json_encode(['status' => -3]);
        }
        $Worker = new \Events;
        $message_json   = '{"type":"send","source":"U_' . $uid . '","toClientUid":"' . $toMid . '","content":' . $message .',
               "c_type":
' . $message_type .', "Db_id":' . $insertId . '}'; $Worker::onMessage($client_id, $message_json); //成功返回相關資料 return json_encode([ 'status' => 1, 'timeStamp' => time(), 'timeStr' => date('H:i:s'), 'html' => $message_type == 1 ? '' : self::productData2SendHtml($productData) ]); } //商家傳送資訊給使用者 public function sendMessageToUserAction () { if (!Request::instance()->isPost()) { notFund(); } $post_message = is_not_empty_string($_POST['message']) ? $_POST['message'] : ''; $toUserCode = input('post.toUserCode', '' , 'string'); $toU_uid = encrypt_hopeband($toUserCode, 'D', 'xxxxx'); $V_client_id = input('post.client_id', '', 'string'); $V_uid_code = input('post.myCode', '', 'string'); $V_uid = encrypt_hopeband($V_uid_code, 'D', 'xxxxx'); $make_message = []; $message = ''; self::trimImageAndTextinfo2str($post_message, $make_message); if (is_not_empty_array($make_message)) { foreach ( $make_message as &$v ) { $message .= self::checkIflegalAndReturn($v); } } if (strlen($V_client_id) != 20 || Gateway::isOnline($V_client_id) != 1) { //客戶端錯誤 return json_encode(['status' => -2]); } $V_merchantInfo = Pmodel\Push::getVmerchantInfoByVid($V_uid); if (!is_not_empty_array($V_merchantInfo)) { //商家資訊不存在 return json_encode(['status' => -1]); } require_once dirname(dirname(__FILE__)) . '/Events.php'; $accIsOnline = Gateway::isUidOnline('U_' . $toU_uid) == 1 ? 1 : 0; //判讀使用者是否線上 $message_type = 1; //Log入庫 $insertId = Pmodel\Push::addChatLog($toU_uid, 'V_' . $V_uid, $message, 1, 2, $accIsOnline); if ($insertId === false) { //入庫失敗(伺服器故障) return json_encode(['status' => -3]); } $Worker = new \Events; $img_encrypt_code = encrypt_hopeband('Hp_(legal)', 'E', 'Hp_HopeBand_Chat_img'); $message = str_replace($img_encrypt_code .' src="', $img_encrypt_code . " src='", $message); $message = str_replace('">', "'>", $message); $message_json = '{"type":"send","toClientUid":"U_' . $toU_uid . '","content":"' . $message .'","Db_id": "' . $insertId . '"}'; $Worker::onMessage($client_id, $message_json); //成功返回相關資料 return json_encode([ 'status' => 1, 'timeStamp' => time(), 'timeStr' => date('H:i:s'), ]); }

 

額外還有一些關於訊息處理方面的;

 //驗證是否是否是圖片,如果是並且返回圖片地址,否則返回字串
    private static function checkIflegalAndReturn ( $message = '') {
        header('content-type:text/html; charset=utf-8');
        $img_encrypt_code = encrypt_hopeband('Hp_(legal)', 'E', 'Hp_HopeBand_Chat_img');
        if (substr($message, 0, 21) != '<img src="data:image/' || substr($message, strpos($message, ';', 0) ,8) != ';base64,' || 
            substr($message, -2, 2) != '">') {
            return $message;
        }
        $preg = '/<img.*?src="(.*?)".*?>/is';
        preg_match( $preg, $message,$arr);
        $img_src = self::base64_upload($arr[1]);
        return '<img '.$img_encrypt_code.' src="' . $img_src . '">';
    }

    //把接受到的訊息文字和圖片有序提出並解析
    private static function trimImageAndTextinfo2str ($message = '', &$message_arr = []) {
        if (!is_not_empty_string($message)) return '';
        $img_start_code = '<img src="data:image/';
        $img_end_code = '">';
        $tmp_message = strlen($message);
        $initial     = substr($message,0,strlen($img_start_code));
   
        if ($initial == $img_start_code) {
            $start = strpos($message, $img_start_code, 0); 
            $end   = strpos($message, $img_end_code , 0); 
            $message_arr[] = substr($message, 0, $end + 2);
            $message = substr($message, $end + 2);
        }else{
            $start = strpos($message, $img_start_code);
            if ($start !== false) {
                $message_arr[] = substr($message, 0, $start);
                $message = substr($message, $start);
            }else{
                //防止xss攻擊
                $message_arr[]= string_remove_xss(htmlspecialchars_decode($message));
            }
        }
        if (($tmp_message) != strlen($message) && is_not_empty_string($message)) {
            self::trimImageAndTextinfo2str($message, $message_arr);
        }
      return $message_arr;

    }

    private static function base64_upload($base64 = '') {
    $base64_image = str_replace(' ', '+', $base64);
    if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $base64_image, $result)){
        if($result[2] == 'jpeg'){
            $image_name = getCode(16,4).'.jpg';
        }else{
            $image_name = getCode(16,4).'.'.$result[2];
        }
        $image_file = "./upload/chat".'/'.date('Y').'/'.date('m').'/'.date('d').'/'.$image_name;    //伺服器檔案儲存路徑
        //判斷檔案路徑是否存在
        $path = "./upload/chat".'/'.date('Y').'/'.date('m').'/'.date('d').'/';
        is_dir($path) or mkdir($path,0777,true);
        if (file_put_contents($image_file, base64_decode(str_replace($result[1], '', $base64_image)))){
            return $image_file;
        }else{
            return false;
        }
    }else{
        return false;
    }
  }

微信的圖片上傳

JS部分

/* 退款選擇圖片 -------- start */
        
$("#chooseImage").click(function()
{
                
                wx.chooseImage(
                {
                    count: 9,                                 // 預設9
                    sizeType: ['original','compressed'],     // 可以指定是原圖還是壓縮圖,預設二者都有
                    sourceType: ['album', 'camera'],         // 可以指定來源是相簿還是相機,預設二者都有
                    success: function (res)
                    {
                           images.localId = res.localIds; // 返回選定照片的本地ID列表,localId可以作為img標籤的src屬性顯示圖片                       
                            //for(var j = 0;j<images.localId.length;j++)
                              // {                      
                                    // var str = '<div serverId='+images.serverId[j]+' class="chat-sender"><div class="chat-avatar">
                     //<img src="/home/push/img/1.png" alt="">
                   //</div><div class="chat-content"><div class="chat-triangle"></div>
                     //<img src='+images.localId[j]+' data-originalDrawing-src='+images.localId[j]+' data-preview-src="" data-preview-group="1"/></div></div>'
// $("#main").append(str); // } var t = 0; var i = 0, length = images.localId.length; images.serverId = []; /* upload 方法 -------- start */ function upload() { wx.uploadImage( { localId: images.localId[i], success: function (res) { i++; images.serverId.push(res.serverId); if (i < length) { upload(); } var str = '<div serverId='+res.serverId+' class="chat-sender"><div class="chat-avatar">
                         <img src="/home/push/img/1.png" alt="">
                            </div><div class="chat-content"><div class="chat-triangle"></div>
                         <img src=
'+images.localId[i-1]+' data-originalDrawing-src='+images.localId[i-1]+' data-preview-src="" data-preview-group="1"/>
                           </div></div>
' $("#main").append(str); if(i >= length ) uploadImageToDb(images.serverId); }, fail: function (res){ } }); } /* upload 方法 -------- end */ upload(); } }) }); function uploadImageToDb(images){ var str = ""; var upUrl = "http://xxxxxx.com/push/push/uploadImgage"; var toMid = $('#toMid').val(); var client_id = $('#client_id').val(); $.post(upUrl,{images:images,toMid:toMid,client_id:client_id},function(data){ if(data == 1){ for(var n = 0 ; n < $(".chat-sender").length ; n++){ str = $(".chat-sender").eq(n).attr("serverId")+","; for(var z=0;z<data.length;z++){ if(data[z] == str){ $(".chat-sender").eq(n).find(".chat-content").append('<div class="chat-sender">上傳失敗</div>'); } } } } }) } /* 退款選擇圖片 -------- end */

後臺部分

//微信上傳圖片
    public function uploadImgageAction () {
        if (!Request::instance()->isPost()) { notFund(); }
        $images    = $_POST['images'];
        if (empty($images)) die;
        $toMid     = input('post.toMid', '' , 'string');
        $client_id = input('post.client_id', '', 'string');
        if (strlen($client_id) != 20 ) {                                            //客戶端錯誤
            return json_encode(['status' => -1]);
        }
        if (!is_not_empty_string($toMid)) {                                         //系統錯誤
            return json_encode(['status' => -2]);
        }

        require_once dirname(dirname(__FILE__)) . '/Events.php';
 
        $accIsOnline    = Gateway::isUidOnline($toMid) == 1 ? 1 : 0;                //判讀商家是否線上
        $message_type   = 3;
        //微信上傳圖片處理Start
        $res = json_decode(file_get_contents("access_token.json"));
        foreach ($res as $key => $value) {
            if($key == 'access_token'){
                $access_token = $value;
            }
        }
        $data = [];
        foreach ($images as $k => $v) {
            $str = date('YmdHis').rand(1000,9999).'.jpg';
            $targetName = './upload/chat/'.$str;
            if (!file_exists("./upload/chat/")) {
              mkdir("./upload/chat/", 0777, true);
            }
            $ch = curl_init("http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=".$access_token."&media_id=".$v);
            $fp = fopen($targetName, 'wb');
            curl_setopt($ch, CURLOPT_FILE, $fp);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            $msg["status"] = curl_exec($ch);
            $msg["filename"] = $str;
            curl_close($ch);
            fclose($fp);
            $data[] = $targetName;
        }
        //微信上傳圖片處理End
        if (!is_not_empty_array($data)) {                                       //微信伺服器端圖片上傳錯誤
            return json_encode(['status' => -2]); 
        }
        $message = json_encode($data);
        //Log入庫
        $insertId       = Pmodel\Push::addChatLog(self::$uid, $toMid, $message, $message_type, 1, $accIsOnline);
        if ($insertId === false) {                                                  //入庫失敗(伺服器故障)
            return json_encode(['status' => -3]);
        }
        $Worker = new \Events;
        $message_json   = '{"type":"send","source":"U_' . self::$uid . '","toClientUid":"' . $toMid . '","content":' . $message .',
               "c_type":
' . $message_type .', "Db_id":' . $insertId . '}'; $Worker::onMessage($client_id, $message_json); //成功返回相關資料 return json_encode([ 'status' => 1, 'timeStamp' => time(), 'timeStr' => date('H:i:s') ]); }

其他一些不是很重要的程式碼就不拿出來了。

當前專案只是一個簡單的需求,並沒有把GatewayWorker很多強大的功能體現出來,大家以後在專案開發中遇到更為複雜的需求,參考官方手冊提供的一些Demo就可以慢慢實現並開發出更為健壯的專案!

相關文章