thinkcmf5(tp5.0) + workman实现简单客服聊天功能

配置过程中遇到的问题及说明:

1、首先需要对长连接相关概念有一定了解。

2、通过composer默认安装的workman版本不对,报错,使用命令composer require topthink/think-worker=1.0.1

3、通过1、发现composer包列表网址,https://packagist.org,可以通过该网址查找composer包,包括说明。

4、报错:stream_socket_server() has been disabled for security reasons … ,修改php.ini,disable_functions项,去掉stream_socket_server。

 

安装步骤说明:

1、composer安装命令,composer包安装倒了vendor/workerman/目录中。


GeSHi Error: GeSHi could not find the language php (using path /home/wwwroot/www.hillmatrix.com/wp-content/plugins/codecolorer/lib/geshi/) (code 2)

2、在项目根目录中新建server文件,内容如下:


GeSHi Error: GeSHi could not find the language php (using path /home/wwwroot/www.hillmatrix.com/wp-content/plugins/codecolorer/lib/geshi/) (code 2)

3、服务器端控制器代码:


GeSHi Error: GeSHi could not find the language php (using path /home/wwwroot/www.hillmatrix.com/wp-content/plugins/codecolorer/lib/geshi/) (code 2)

4、linux进入项目根目录,启用服务监听端口。

1
php server start
1
2
3
4
5
6
7
8
Workerman[server] start in DEBUG mode
------------------------------------------- WORKERMAN --------------------------------------------
Workerman version:3.5.17 PHP version:5.6.36
-------------------------------------------- WORKERS ---------------------------------------------
proto user worker listen processes status
tcp root none websocket://0.0.0.0:2346 1 [OK]
--------------------------------------------------------------------------------------------------
Press Ctrl+C to stop. Start success.

5、前端页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
<style>
        .content{<br />            width: 700px;<br />            margin: auto;<br />        }<br />        .box{<br />            padding-bottom: 3px;<br />            padding-top: 3px;<br />        }<br />        .box input{<br />            width: 70%;<br />        }<br />        .box button{<br />            width: 25%;<br />        }<br />    </style>

&nbsp;
<h3>CHAT TEST</h3>

<hr />

<div class="content">
<div class="box"><input name="name" type="text" />
<button id="setName">设置昵称</button></div>
<div class="box"><input name="message" type="text" />
<button id="send">发送</button></div>
<div id="content" class="box"></div>
</div>
<script>
    var ws;
    var connected = false;

    $(function () {

        ws = new WebSocket("ws://local.hillmatrix.com:2346");
        ws.onopen = function() {
            console.log('WebSocket 连接成功');
            connected = true;
        };
        ws.onmessage = function(e) {
            // e.data
            console.log(e.data);
            try {
                var data = JSON.parse(e.data);
                //非法数据,不处理
                if (!data.hasOwnProperty("code")) return;
                if (data.code != 0){
                    if (data.hasOwnProperty("msg")){
                        alert(data.msg);
                    }
                    return
                }

                if (!data.hasOwnProperty("data") || !data.hasOwnProperty("type") || !data.hasOwnProperty("data")) return;

                switch (data.type){
                    case 'private_message':
                        addChatItem(data.data.name + '(悄悄的...)',data.data.message)
                        break;
                    case 'message':
                        addChatItem(data.data.name,data.data.message)
                        break;
                    case 'msg':
                        alert(data.data.msg)
                        break;
                }

            }catch (ex) {

            }
        };

    });

    $("#setName").click(function () {
        var name = $('input[name=name]').val().trim();
        if (name==''){
            alert('昵称不能为空');
            return;
        }
        sendData('setName',{name:name});
    });

    $("#send").click(function () {
        var message = $('input[name=message]').val().trim();
        if (message==''){
            alert('内容不能为空');
            return;
        }

        if(message.indexOf(":") >= 0){
            sendData('private_message',{message:message});
        }else{
            sendData('message',{message:message});
        }

    })

    function addChatItem( name,message ) {
        var temp = '</p>
<p>
</p>
<div class="box"><p>
</p>
<p>__NAME__ 说:</p>
<p>
</p>
<p>__CONTENT__</p>
<p>
</div>
<p>
</p>
<p>';
        temp = temp.replace( "__NAME__",name );
        temp = temp.replace( "__CONTENT__",message );
        $("#content").append(temp);
    }

    function sendData(type,data) {
        if(ws.readyState != 1){
            alert(connected ? "连接已中断" : "连接不成功");
            return;
        }
        ws.send(JSON.stringify({type:type,data:data}));
    }
</script>

6、测试效果

参考代码:https://gitee.com/goto8848/build_a_simple_chat_room_with_workerman

官方文档:http://doc.workerman.net/faq/send-data-to-client.html

thinkphp5.1 + workerman 留着以后参考:https://blog.csdn.net/qq_27238185/article/details/81477303

PDF文档数字签名

fpdf官网:http://www.fpdf.org/?lang=zh

tcpdf官网:https://tcpdf.org/

1、对证书签名与验签逻辑优化,在linux系统中生成根证书CA,用CA为子证书签名,最后使用子证书为pdf做签名,防止pdf伪造自签证书。

1
2
3
4
5
6
7
8
#1、生成根证书 #a).生成根证书私钥(key文件)
openssl genrsa -aes256 -out ca.key 2048

#b).生成根证书签发申请文件(csr文件)
openssl req -new -key ca.key -out ca.csr -config /usr/lib/ssl/openssl.cnf

#c).自签发根证书(crt文件)
openssl x509 -req -days 3650 -sha1 -extensions v3_ca -signkey ca.key -in ca.csr -out ca.crt
1
2
3
4
5
6
7
8
9
10
11
#2、用根证书签发server端证书
#a).生成根证书私钥(key文件)
openssl genrsa -aes256 -out tcpdf.key 2048

#b).生成根证书签发申请文件(csr文件)
openssl req -new -key tcpdf.key -out tcpdf.csr -config /usr/lib/ssl/openssl.cnf

#c).使用根证书签发服务端证书
openssl ca -in tcpdf.csr -out tcpdf.crt -days 730 -cert ca.crt -keyfile ca.key -config /usr/lib/ssl/openssl.cnf

#The organizationName field needed to be the same in the CA certificate (Timeswealth Global Root CA)

若发生错误: I am unable to access the ./demoCA/newcerts directory ./demoCA/newcerts: No such file or directory

做如下处理

1
2
3
4
5
mkdir demoCA
mkdir demoCA/newcerts
mkdir demoCA/private
touch demoCA/index.txt
echo "01" &gt;&gt; demoCA/serial

备注:一下是tcpdf官方提供的生成自签名证书方法,测试用,如果用于实际会有逻辑漏洞,没有根证书约束。

1
2
3
4
5
6
7
8
9
10
11
/* NOTES:

- To create self-signed signature: openssl req -x509 -nodes -days 365000 -newkey rsa:1024 -keyout tcpdf.crt -out tcpdf.crt

- To export crt to p12: openssl pkcs12 -export -in tcpdf.crt -out tcpdf.p12

- To export p12 to pfx: openssl pkcs12 -export -inkey tcpdf.crt -in tcpdf.crt -out tcpdf.pfx

- To convert pfx certificate to pem: openssl pkcs12 -in tcpdf.pfx -out tcpdf.crt -nodes

*/

自己封装的tcpdf操作类


GeSHi Error: GeSHi could not find the language php (using path /home/wwwroot/www.hillmatrix.com/wp-content/plugins/codecolorer/lib/geshi/) (code 2)

操作类的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<pre>require_once APP_ROOT_PATH."/system/utils/tcpdf_proxy.php";

$tcpdf = new TcpdfProxy();

$html = '&lt;html&gt;content&lt;/html&gt;';

$singConf = array();

$singConf['image'] = APP_ROOT_PATH.app_conf('CONTRACT_SEAL');

$singConf['sign_info'] = array(
    'Name' =&gt; app_conf('SHOP_TITLE'),
);

$tcpdf-&gt;setSignConf($singConf);

$tcpdf-&gt;outputPdf($html,'contract.pdf');</pre>