当前位置: 首页 > 工具软件 > Webman > 使用案例 >

php webman对接Luckysheet share多人协作模式项目 成功

都建树
2023-12-01
gitee地址  https://gitee.com/zxadmin/luckysheet-phpserver
此项目目前定义为对接失败,当然Luckysheet也可以去除掉加密的部分,直接json通信就没问题
2022年9月21日09:41:18
终于解决了webman对接问题
因为现在php8 default_charset = "UTF-8" PHP的默认处理字符集是utf-8
但是gzip的默认字符集是 ISO-8859-1, gzdecode函数处理也需要 ISO-8859-1字符集
参考了java版本的代码发现他也是转还了字符集
public static String uncompress(String str) throws IOException {
        if (str == null || str.length() == 0) {
            return str;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayInputStream in = new ByteArrayInputStream(str.getBytes("ISO-8859-1"));
        GZIPInputStream gunzip = new GZIPInputStream(in);
        byte[] buffer = new byte[256];
        int n;
        while ((n = gunzip.read(buffer)) >= 0) {
            out.write(buffer, 0, n);
        }
        // toString()使用平台默认编码,也可以显式的指定如toString("GBK")
        return out.toString();
    }
str.getBytes("ISO-8859-1"),我就尝试转换了一下

$content = mb_convert_encoding($data, 'ISO-8859-1', 'utf-8');
var_dump(json_decode(urldecode(gzdecode($content)), true));
然后就解析成功了,现在php对接Luckysheet也可以了

luckysheet 是前端测试代码
luckysheet/pako/examples/browser.html pako是加密测试代码
luckysheet/pako/examples/browser_post.html pako是加密测试代码
luckysheet/pako/examples/browser_socket.html pako是加密测试代码

Luckysheet的 share多人协作数据发送对接流程:

Luckysheet的配置
$(function () {

// According to the browser language
var lang = luckysheetDemoUtil.language() === 'zh' ? 'zh' : 'en';
//var isShare = luckysheetDemoUtil.getRequest().share; // '?share=1' opens the collaborative editing mode
//var gridKey = luckysheetDemoUtil.getRequest().gridKey; // workbook id for collaborative editing, or directly define here
var isShare = 1; // '?share=1' opens the collaborative editing mode
var gridKey = "1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2xc"; // workbook id for collaborative editing, or directly define here
var options = null;

if (isShare || gridKey) {
	// http://localhost:3000/?gridKey=12eyy789-kk45ofid-23737245
	if (!gridKey) {
		alert('If gridKey is not provided in the address bar, please add it in the source code')
	}
	options = {
		container: "luckysheet",
		lang: lang,
		allowUpdate: true,
		updateImageUrl: "http://192.168.154.131" + "/luckysheet/updateImg",
		updateUrl: "ws://192.168.154.131:8888",
		gridKey: gridKey,
		loadUrl: "http://192.168.154.131" + "/luckysheet/load",
		loadSheetUrl: "http://192.168.154.131" + "/luckysheet/loadsheet"
	}
	} else {
		console.log(1111111);
	}

	luckysheet.create(options);
	})


1,选请求 luckysheet/load接口
接口返回
[{"color":"","list_id":"1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2xc","column":60,"index":"1","jfgird_select_save":[{"top_move":180,"top":180,"left":222,"column_focus":3,"width":73,"column":[3,3],"left_move":222,"width_move":73,"row":[9,9],"row_focus":9,"height_move":19,"height":19}],"rh_height":1790,"visibledatacolumn":[],"scrollTop":0,"block_id":"fblock","rowsplit":[],"visibledatarow":[],"jfgrid_selection_range":{},"name":"Sheet1","celldata":[],"ch_width":4748,"row":84,"scrollLeft":0,"id":350081777752215552,"chart":[],"config":{},"order":0,"status":1},{"color":"","list_id":"1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2xc","column":60,"index":"2","jfgird_select_save":[],"rh_height":1790,"visibledatacolumn":[],"scrollTop":0,"block_id":"fblock","rowsplit":[],"visibledatarow":[],"jfgrid_selection_range":{},"name":"Sheet2","ch_width":4748,"row":84,"scrollLeft":0,"id":350081777752215553,"chart":[],"config":{},"order":1,"status":0},{"color":"","list_id":"1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2xc","column":60,"index":"3","jfgird_select_save":[],"rh_height":1790,"visibledatacolumn":[],"scrollTop":0,"block_id":"fblock","rowsplit":[],"visibledatarow":[],"jfgrid_selection_range":{},"name":"Sheet3","ch_width":4748,"row":84,"scrollLeft":0,"id":350081777752215554,"chart":[],"config":{},"order":2,"status":0}]

2,就会建websocket通信 ws://192.168.154.131:8888

$data1 = '{"message":"连接成功","type":"0","status":"0"}';

$data2 = '{"data":"","message":"反馈以前操作信息","type":"4","status":"0"}';
发送个前端

这样就可以一share多人协作模式正常打开了

3,如果操作Luckysheet会触发 saveParam方法
通过 
let msg = pako.gzip(encodeURIComponent(JSON.stringify(d)), { to: "string" });

if(_this.websocket!=null){
	_this.websocket.send(msg);
}
发送给服务端,这个是经过pako加密的,服务端需要先解开数据加密,然后根据
_this.saveParam("rv", sheetIndex, v, { "range": { "row": [str, edr], "column": [c1, c2] } });

 if(i == n - 1){
  _this.saveParam("rv_end", sheetIndex, null);
 }

告诉客户端返回不通过的status,需要查看 server.js的源代码
返回数据格式
{
    createTime: 命令发送时间
    data:{} 修改的命令
    id: "7a"   websocket的id
    returnMessage: "success"
    status: "0"  0告诉前端需要根据data的命令修改  1无意义
    type: 0:连接成功,1:发送给当前连接的用户,2:发送信息给其他用户,3:发送选区位置信息,999:用户连接断开
    username: 用户名
}

webman的时候需要返回这种格式的json给当前连接的客户端,然后广播给其他客户端,这样就完成了多人协作的基本功能


<?php

namespace process;

use Webman\Channel\Client;
use Workerman\Connection\TcpConnection;
use Workerman\Timer;

class Luckysheet
{

    protected $connections = [];

    public function __construct()
    {
    }

    public function onConnect(TcpConnection $connection)
    {
        echo "onConnect\n";
    }

    public function onWebSocketConnect(TcpConnection $connection, $http_buffer)
    {
        echo "onWebSocketConnect\n";
        $data1 = '{"message":"连接成功","type":"0","status":"0"}';
        $connection->send($data1);
        $data2 = '{"data":"","message":"反馈以前操作信息","type":"4","status":"0"}';
        $connection->send($data2);

        $key = $this->getUid($connection->getLocalIp(), $connection->getLocalPort(), $connection->worker->workerId, $connection->worker->id, $connection->id);

        $this->connections[$key] = $connection;
    }

    /*
     * {
    createTime: 命令发送时间
    data:{} 修改的命令
    id: "7a"   websocket的id
    returnMessage: "success"
    status: "0"  0告诉前端需要根据data的命令修改  1无意义
    type: 0:连接成功,1:发送给当前连接的用户,2:发送信息给其他用户,3:发送选区位置信息,999:用户连接断开
    username: 用户名
    }
     */
    public function onMessage(TcpConnection $connection, $data)
    {

        $key = $this->getUid($connection->getLocalIp(), $connection->getLocalPort(), $connection->worker->workerId, $connection->worker->id, $connection->id);

        $return = [];
        $return['createTime'] = time();
        $return['data'] = null;
        $return['returnMessage'] = 'success';
        $return['status'] = '1';
        $return['type'] = 0;
        $return['id'] = $key;
        $return['username'] = $key;

        if ($data == 'rub') {
            //心跳不回复
        } else {
            //解析数据出错,目前不清楚是为什么,不能解析,就无法 给$return 返回对应的数据
            $out = json_decode(urldecode(gzdecode($data)), true);
			//返回错误是 gzdecode data error

            //单线程版本写法,多线程需要channel通信
            $this->broadcast($key, $out);

            $connection->send(json_encode($return));
        }
    }

    public function onClose(TcpConnection $connection)
    {
        echo "onClose\n";
    }

    public function getUid($local_ip, $local_port, $workerId, $worker_id, $connection_id)
    {
        $str = $local_ip . $local_port . $workerId . $worker_id . $connection_id;
        return md5($str);
    }

    public function broadcast($key, $data)
    {
        foreach ($this->connections as $k => $connection) {
            if ($k !== $key) {
                $connection->send($data);
            }
        }
    }
}

目前在webman的websocket去解析 加密数据

但是在其他地方都可以解析出来
1,java版本解析没问题
2,laravel中
3,webman api模式

测试前端
const obj = [
  { foo: 'bar', baz: 'baz' },
  { abra: 1, cadabra: null }
]

let msg = pako.gzip(encodeURIComponent(JSON.stringify(obj)), { to: "string" });
console.log(msg)

function send(msg) {
  var xhr = new XMLHttpRequest;
  xhr.open('POST', 'http://www.yd.com/open/test', true);
  xhr.send(msg);

  //setTimeout(send, 5000);
}
send(msg);


后端代码基本一样
webman api
   $in = $request->rawBody();
   $res = json_decode(urldecode(gzdecode($in)), true);
   return json($res);
   
laravel
	 $in = file_get_contents("php://input");
     $res = json_decode(urldecode(gzdecode($in)), true);

socket测试,没问题
<script src="./../dist/pako.js"></script>
<script>
  const obj = [
    { foo: 'bar', baz: 'baz' },
    { abra: 1, cadabra: null }
  ]

  let result = pako.gzip(encodeURIComponent(JSON.stringify(obj)), { to: "string" });
  ws = new WebSocket('ws://192.168.154.140:8888');
  ws.onopen = function () {
    ws.send(result);
  }

</script>


java版本的话,参考
https://gitee.com/chuanshanjun/luckysheet-saved-in-recovery

 类似资料: