您的位置:首页 > 移动开发 > 微信开发

用微信 远程遥控 服务器

2017-02-27 10:54 323 查看

摘要

微信公众好的开发很火,小程序更火。于是也凑个热闹,尝试了一把。

大致的功能还是有的,不过是不全,很多地方我没有进行处理。不过对于纯文本方式的交流,已经没有问题啦。





环境搭建

下面大致的讲讲微信公众号的原理吧。可能我理解的有些不到位,如果有些许不当,欢迎批评指教。

客户端发送给微信平台请求,微信平台将请求转发给私服,交给程序处理之后,获取到私服的处理结果,然后反馈给客户端。

当然,这其中起到核心作用的自然是“微信公众平台”啦。相当于提供了一个舞台,一个能让各位能人异士展现出各自的特色的平台。其实,不仅微信如此,阿里同样是这样,如此各大电商才能一展手脚不是。

开启配置

这第一步,就是先申请一个微信开发者账号,个人的话选择订阅号就足够了。网上相关的资料很多,也很详细,我就不多说了。咱们直奔主题好了。

首先登陆开发者账号成功后,开启服务器端的设置即可,如下图



开启完成,根据自己服务器的情况进行一下设置即可。

URL就是你的私服用于处理请求数据的地址

TOKEN就是一个令牌,随便设置。不过记住待会自己的代码上会用到。

至于密钥嘛,没什么较大的作用,暂且可以先不用管。



设置完,就可以启用了。这就好比家里的电线全部装修好了,现在要使用,按下开关一样。如下图



服务器环境

关于服务器这块,官网上讲解的也是很详细的啦。
https://mp.weixin.qq.com/wiki

我们还可以下载官方的demo来模拟。



代码也很简单。基本上学过了PHP基本语法的都能够看得懂。

<?php
/**
* wechat php test
*/

//define your token
define("TOKEN", "weixin");
$wechatObj = new wechatCallbackapiTest();
$wechatObj->valid();

class wechatCallbackapiTest
{
public function valid()
{
$echoStr = $_GET["echostr"];

//valid signature , option
if($this->checkSignature()){
echo $echoStr;
exit;
}
}

public function responseMsg()
{
//get post data, May be due to the different environments
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];

//extract post data
if (!empty($postStr)){
/* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection,
the best way is to check the validity of xml by yourself */
libxml_disable_entity_loader(true);
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$fromUsername = $postObj->FromUserName;
$toUsername = $postObj->ToUserName;

1523b
$keyword = trim($postObj->Content);
$time = time();
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
<FuncFlag>0</FuncFlag>
</xml>";
if(!empty( $keyword ))
{
$msgType = "text";
$contentStr = "Welcome to wechat world!";
$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
echo $resultStr;
}else{
echo "Input something...";
}

}else {
echo "";
exit;
}
}

private function checkSignature()
{
// you must define TOKEN by yourself
if (!defined("TOKEN")) {
throw new Exception('TOKEN is not defined!');
}

$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];

$token = TOKEN;
$tmpArr = array($token, $timestamp, $nonce);
// use SORT_STRING rule
sort($tmpArr, SORT_STRING);
$tmpStr = implode( $tmpArr );
$tmpStr = sha1( $tmpStr );

if( $tmpStr == $signature ){
return true;
}else{
return false;
}
}
}

?>
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


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
核心思路,无非检验一下签名,处理一下请求,反馈一下结果罢了。

这里我不得不想说的就是,我觉得腾讯其实可以将那些个模板什么的去掉,直接暴露出黑盒模式,这样的话安全性会更高一点。很多时候,权限放的越开,效果可能越差。

核心类

接下来就是我自己的处理逻辑了,参照官方文档。微信公众好上有6大接收接口,三大回复接口。依据MsgType即可判定。



验证

private function checkSignature() {
// you must define TOKEN by yourself
if (! defined ( "TOKEN" )) {
throw new Exception ( 'TOKEN is not defined!' );
}

$signature = $_GET ["signature"];
$timestamp = $_GET ["timestamp"];
$nonce = $_GET ["nonce"];

$token = TOKEN;
$tmpArr = array (
$token,
$timestamp,
$nonce
);
// use SORT_STRING rule
sort ( $tmpArr, SORT_STRING );
$tmpStr = implode ( $tmpArr );
$tmpStr = sha1 ( $tmpStr );

if ($tmpStr == $signature) {
return true;
} else {
return false;
}
}
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


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
验证方法核心就是依据咱们之前网页上设置的TOKEN来工作的,所以代码上会用得到。

回复

回复的代码需要依据客户端发送的数据的类型来区分对待,类型这块微信平台会将数据打包好封装起来,我们住需要调用内部的MsgType进行处理即可。

拓展

拓展部分,是我自己异想天开往上加的。

添加机器人

调用一个机器人接口,来代替自己发送回复,技能让用户得到一个良好的用户体验,还能愉悦大众,何乐而不为?

我这边测试了两个接口,一个是curl模式,一个是
file_get_contents
模式,都挺好用的啦。

<?php
/**
* 图灵 机器人接口
*
* 使用curl来进行浏览器模拟并抓取数据
*/
function turing($requestStr) {
// 图灵机器人接口
$url = "http://www.tuling123.com/openapi/api";
// 用于POST请求的数据
$data = array(
'key'=>"哈哈,这个key还是得你自己去申请的啦",
'info'=>$requestStr,
);

// 构造curl下载器
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$responseStr = curl_exec($ch);
curl_close($ch);

return $responseStr;
}

/**
* 调用另外的接口
* @param unknown $req
* @return mixed
*/
function test($req){
$url = "http://api.qingyunke.com/api.php?key=free&appid=0&msg=".$req;
$result = file_get_contents($url);
$result = json_decode($result, true);
return $result['content'];
}

$req = 'hello';
$res = test($req);
echo $res;
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


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

命令模式

手机相对于电脑一个很大的优点就是便携,我们虽然不能随时随地携带电脑,但是却能使用手机来代替。很多时候对服务器的管理需要的命令很简单,但是远程登录的时候也不方便。这个时候就用微信来帮忙传话也是不错的啦。

我平时喜欢使用Python写一些脚本,什么获取本地IP,聊天,查看内存,网速啥的,可谓是应有尽有。这下也终于能有用武之地了。利用微信的关键字匹配,就可以简单的让微信公众号当一个小小传话员啦。

这里给个思路,具体实现起来也比较简单,当做是文本来处理即可。

完整代码

下面贴出我服务器上的完整代码,有些私密的地方我做了些更改,届时按照自己的情况进行修改即可。

<?php
/**
* wechat php test
*/

// define your token
define ( "TOKEN", "您的TOKEN" );
$wechatObj = new wechatCallbackapiTest ();
// $wechatObj->valid();

// 调用回复信息方法
$wechatObj->responseMsg ();

// 微信消息处理核心类
class wechatCallbackapiTest {
public function valid() {
$echoStr = $_GET ["echostr"];

// valid signature , option
if ($this->checkSignature ()) {
echo $echoStr;
exit ();
} else {
echo "验证失败!";
}
}
public function responseMsg() {
// get post data, May be due to the different environments
// 类似$_POST但是可以接受XML数据,属于增强型
$postStr = $GLOBALS ["HTTP_RAW_POST_DATA"];

// extract post data
if (! empty ( $postStr )) {
/*
* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection,
* the best way is to check the validity of xml by yourself
*/
// 不解析外部数据,防止xxml漏洞
libxml_disable_entity_loader ( true );
$postObj = simplexml_load_string ( $postStr, 'SimpleXMLElement', LIBXML_NOCDATA );
$fromUsername = $postObj->FromUserName;
$toUsername = $postObj->ToUserName;
$keyword = trim ( $postObj->Content );
$time = time ();

/*
* 微信客户端发送信息的时候会附带一些参数,详见官方文档。所以要根据不同的类型,来分别做相关的处理。
* 于是MsgType 就充当这样的一个区分的标记
*/
$msgType = $postObj->MsgType;

/*
* 当有用户关注后者退订的时候,会触发相应的事件。所以再来个event事件的监听更为友好。
* $event = $postObj->Event.
* 具体的参数信息,官网上很详细。
*/
$event = $postObj->Event;

switch ($msgType) {
// 文本消息 处理部分
case "text" :
if (! empty ( $keyword )) {
// 在此处进行对关键字的匹配就可以实现:针对不同关键字组装的相应数据
if($keyword=='音乐' || $keyword == "music") {
$msgType = 'music';
$musictitle = "The Mountain";
$musicdescription = "夏日舒心清凉歌曲";
$musicurl = "http://101.200.58.242/wx/themaintain.mp3";
$hqmusicurl = "http://101.200.58.242/wx/themaintain.mp3";
musicMessageHandle($fromUsername, $toUsername, $time, $msgType, $musictitle, $musicdescription, $musicurl, $hqmusicurl);
}elseif($keyword == '1'){
$msgType = 'text';
$contentStr = "人生得意须尽欢,莫使金樽空对月!";
textMessageHandle($fromUsername, $toUsername, $time, $msgType, $contentStr);
}elseif($keyword == '命令模式'){
$msgType = 'text';
$contentStr = "进入命令模式,开始对服务器进行管理!\n接下来将依据您输入的命令对服务器进行管理!";
textMessageHandle($fromUsername, $toUsername, $time, $msgType, $contentStr);
}else {
// 直接调用 机器人接口,与用户进行交流
$msgType = "text";
$contentStr = turing($keyword)!=""?turing($keyword):"这里是微信 纯文本测试数据!";
textMessageHandle ( $fromUsername, $toUsername, $time, $msgType, $contentStr );
}
} else {
echo "您得输入点数据,我才能回复不是!";
}
break;
// 接收图片信息
case "image" :
if (! empty ( $keyword )) {
// $msgType = "image";
$contentStr = "您发送的图片看起来还真不错!";
textMessageHandle ( $fromUsername, $toUsername, $time, $msgType, $contentStr );
} else {
echo "服务器没能收到您发送的图片!";
}
break;
// 接收语音信息
case "voice" :
if (! empty ( $keyword )) {
// $msgType = "voice";
$contentStr = "您发送的语音听起来还真不错!";
textMessageHandle ( $fromUsername, $toUsername, $time, $msgType, $contentStr );
} else {
echo "服务器没能收到您发送的语音!";
}
break;
// 接收视频信息
case "video" :
if (! empty ( $keyword )) {
// $msgType = "video";
$contentStr = "您发送的视频看起来还真不错!";
textMessageHandle ( $fromUsername, $toUsername, $time, $msgType, $contentStr );
} else {
echo "服务器没能收到您发送的视频!";
}
break;
// 接收视频信息
case "shortvideo" :
if (! empty ( $keyword )) {
// $msgType = "shortvideo";
$contentStr = "您发送的小视频看起来还真不错!";
textMessageHandle ( $fromUsername, $toUsername, $time, $msgType, $contentStr );
} else {
echo "服务器没能收到您发送的小视频!";
}
break;
// 接收位置信息
case "location" :
if (! empty ( $keyword )) {
// $msgType = "location";
$contentStr = "您发送的位置已被接收!";
textMessageHandle ( $fromUsername, $toUsername, $time, $msgType, $contentStr );
} else {
echo "服务器没能收到您发送的位置!";
}
break;
// 接收视频信息
case "link" :
if (! empty ( $keyword )) {
// $msgType = "link";
$contentStr = "您发送的链接看起来还真不错!";
textMessageHandle ( $fromUsername, $toUsername, $time, $msgType, $contentStr );
} else {
echo "服务器没能收到您发送的链接!";
}
break;
// 对事件进行侦听
case "event":
switch ($event) {
case "subscribe":
// 发送一些消息!
$msgType = 'text';
$contentStr = "终于等到你!";
textMessageHandle($fromUsername, $toUsername, $time, $msgType, $contentStr);
break;
}
break;
default :
break;
}
} else {
echo "";
exit ();
}
}
private function checkSignature() { // you must define TOKEN by yourself if (! defined ( "TOKEN" )) { throw new Exception ( 'TOKEN is not defined!' ); } $signature = $_GET ["signature"]; $timestamp = $_GET ["timestamp"]; $nonce = $_GET ["nonce"]; $token = TOKEN; $tmpArr = array ( $token, $timestamp, $nonce ); // use SORT_STRING rule sort ( $tmpArr, SORT_STRING ); $tmpStr = implode ( $tmpArr ); $tmpStr = sha1 ( $tmpStr ); if ($tmpStr == $signature) { return true; } else { return false; } }
}

/**
* 定义为心中想难关的六个接口的数据发送格式模板
*/
function textMessageHandle($fromUsername, $toUsername, $time, $msgType, $contentStr) {
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
<FuncFlag>0</FuncFlag>
</xml>";
$resultStr = sprintf ( $textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr );
echo $resultStr;
}
function imageMessageHandle($fromUsername, $toUsername, $time, $msgType, $contentStr) {
$imageTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
<PicUrl><![CDATA[this is a url]]></PicUrl>
<MediaId><![CDATA[media_id]]></MediaId>
<MsgId>1234567890123456</MsgId>
</xml>";

$resultStr = sprintf ( $textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr );
echo $resultStr;
}
function musicMessageHandle($fromUsername, $toUsername, $time, $msgType, $musictitle, $musicDescription, $musicurl, $hqmusicurl) {
$musicTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Music>
<Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
<MusicUrl><![CDATA[%s]]></MusicUrl>
<HQMusicUrl><![CDATA[%s]]></HQMusicUrl>
</Music>
</xml>";
$resultStr = sprintf($musicTpl, $fromUsername, $toUsername, $time, $msgType, $musictitle, $musicDescription, $musicurl, $hqmusicurl);
echo $resultStr;
}

/**
* 图灵 机器人接口
*
* 使用curl来进行浏览器模拟并抓取数据
*/
function turing($requestStr) {
/* // 图灵机器人接口
$url = "http://www.tuling123.com/openapi/api";
// 用于POST请求的数据
$data = array(
"key"=>"您在图灵机器人官网上申请的key",
"info"=>$requestStr
);

// 构造curl下载器
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$requestStr = curl_exec($ch);
curl_close($ch);

return responseStr; */

$url = "http://api.qingyunke.com/api.php?key=free&appid=0&msg=".$requestStr;
$result = file_get_contents($url);
$result = json_decode($result, true);
return $result['content'];
}

?>
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282


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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282

总结

最后来回顾一下,本次试验用到了哪些知识点。

PHP的面向对象方法编程简单实现。

接口处理的两种方式

微信公众号后台私服的接入,处理,反馈。

前后端的交互,以及聊天机器人的应用。

其实,这些代码跟我一开始的设想还是差别挺大的,原本是想实现一个“遥控器”,晚上想睡觉之前,用微信发一条命令“打开电热毯”,半个小时后,电视看完了,去睡觉的时候发现被窝很暖和,是的,只要加上点硬件,这很容易实现啦再者冰箱了,电视了统统可以完成,那样估计就诊的是“智能家居”了吧。

不过马上考试了,先不折腾了。期末考试完,寒假没事的时候再来完善一下好了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: