前段時間公司提了一個新的需求,在商品的詳情頁要實現站內買家和商品賣家實時通信的功能以方便溝通促成交易,要開發此功能當時首先考慮到的就是swoole和workerman了,從網上大概瞭解了一下關於這兩款工具的闡述,功能都是至關強大的,考慮到項目的進度問題,仍是選擇上手容易比較快的GatewayWorker。php
先看一下咱們前端設計高大上的模板,分別是用戶和賣家後臺。 功能仍是比較全的,幾乎模仿的是QQ。html
業務上的大概需求是,用戶在進入某個商品詳情頁下,給用戶提供一個和賣家溝通的接口,根據商品的ID找到對應的賣家,相似於淘寶,還有發送圖片,發送對應的商品連接;商戶後臺也差很少。前端
咱們的平臺上有虛擬商品和實體商品兩大分類,當時也考慮到了消息的讀取狀態。個人表最初設計以下,沒有加任何的索引,考慮的或許也不夠周全,有見地的前輩還望指點一二!node
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和linux
Windows下的整合安裝。web
http://www.cnblogs.com/wt645631686/p/7219519.html
整合好了以後須要根據當前服務器的一些端口配置在修改一些默認的配置,由於須要客戶端經過指定的端口創建鏈接。ajax
TP5整合好了以後Gateway和workerman的主體目錄結構都在TP5的框架目錄vendor下的workerman目錄下。須要修改裏面gateway目錄下的一些文件的端口及IP地址配置。json
配置完成以後,進入項目目錄,按照workerman官方手冊提供的使用方法,用命令php start.php start啓動socket服務,如如下截圖,分別是1238和8282端口。固然能夠在後臺運行,詳細的使用方法請參考手冊。api
啓動好了以後那麼就須要在客戶端開始下手了,咱們項目裏是在前端頁面裏用創建的連接。看前端代碼安全
當前的全部代碼並非最終的,目前只是階段性開發,後期在項目中逐步完善。
var ws; // 鏈接服務端 function connect() { // 建立websocket ws = new WebSocket("ws://"+document.domain+":8282"); //當時爲了方便之後的維護,這裏在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'), ]); }
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就能夠慢慢實現並開發出更爲健壯的項目!