├── Action.php
├── Page
└── Menus.php
├── Plugin.php
├── README.md
└── Widget
├── Menus.php
└── Utils.php
/Action.php:
--------------------------------------------------------------------------------
1 | db = Typecho_Db::get();
23 | $this->_imageNum = Helper::options()->plugin('WeChatHelper')->imageNum;
24 | $this->_tulingApi = Helper::options()->plugin('WeChatHelper')->tulingApi;
25 |
26 | $this->_imageDefault = Helper::options()->plugin('WeChatHelper')->imageDefault;
27 | $this->_textTpl = "
28 |
29 |
30 | %s
31 |
32 |
33 | 0
34 | ";
35 | $this->_imageTpl = "
36 |
37 |
38 | %s
39 |
40 | %s
41 | %s
42 | 1
43 | ";
44 | $this->_itemTpl = "-
45 |
46 |
47 |
48 |
49 |
";
50 | }
51 |
52 | /**
53 | * 链接重定向
54 | *
55 | */
56 | public function link()
57 | {
58 | if($this->request->isGet()){
59 | $this->getAction();
60 | }
61 | if($this->request->isPost()){
62 | $this->postAction();
63 | }
64 | }
65 |
66 | /**
67 | * 校验
68 | *
69 | */
70 | public function getAction(){
71 | $_token = Helper::options()->plugin('WeChatHelper')->token;
72 | $echoStr = $this->request->get('echostr');
73 |
74 | if($this->checkSignature($_token)){
75 | echo $echoStr;
76 | exit;
77 | }
78 | }
79 |
80 | /**
81 | * 数据
82 | *
83 | */
84 | public function postAction(){
85 | $postStr = file_get_contents("php://input");
86 | //$this->request->get("HTTP_RAW_POST_DATA");
87 |
88 |
89 | //$dir = __TYPECHO_ROOT_DIR__ . __TYPECHO_PLUGIN_DIR__ . '/WeChatHelper';
90 | //$myfile = $dir.'/wechatDebug.txt';
91 | //$file_pointer = @fopen($myfile,"a");
92 | //@fwrite($file_pointer,$postStr );
93 | //@fclose($file_pointer);
94 |
95 |
96 | if (!empty($postStr)){
97 | $options = Helper::options()->plugin('WeChatHelper');
98 | $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
99 | $fromUsername = $postObj->FromUserName;
100 | $toUsername = $postObj->ToUserName;
101 | $time = time();
102 | $msgType = $postObj->MsgType;
103 | $keyword = trim($postObj->Content);
104 | $cmd = strtolower(substr($keyword, 0, 1));
105 | if($msgType == "text" ){
106 | if($cmd=="h" || $cmd=="H"){
107 | $contentStr = "\"n\" 最新日志\n\"r\" 随机日志\n\"l\" 手气不错\n\"s 关键词\" 搜索日志\n\" ";
108 | $resultStr = $this->baseText($postObj, $contentStr);
109 | }elseif ($cmd=="f" || $cmd=="F") {
110 | $resultStr = $this->commentRank($postObj);
111 | }elseif ($cmd=="r" || $cmd=="R") {
112 | $resultStr = $this->randomPost($postObj);
113 | }elseif ($cmd=="n" || $cmd=="N") {
114 | $resultStr = $this->newPost($postObj);
115 | }elseif ($cmd=="l" || $cmd=="L") {
116 | $resultStr = $this->luckyPost($postObj);
117 | }elseif ($cmd=="s" || $cmd=="S") {
118 | $searchParam = substr($keyword, 1);
119 | $resultStr = $this->searchPost($postObj, $searchParam);
120 | }else{
121 | $info = $keyword ;
122 | //$resultStr = $this->chatText($postObj, $info);
123 | $resultStr = $this->searchPost($postObj, $searchParam);
124 | }
125 | }else if($msgType == "event"){
126 | if($postObj->Event == "subscribe"){
127 | $contentStr = $options->welcome;
128 | $resultStr = $this->baseText($postObj, $contentStr);
129 | //$resultStr = $this->newPost($postObj);
130 | }
131 | if($postObj->Event == "CLICK"){
132 | $eventkey = trim($postObj->EventKey);
133 | if ($eventkey=="n" || $eventkey=="N") {
134 | $resultStr = $this->newPost($postObj);
135 | }
136 | if ($eventkey=="l" || $eventkey=="L") {
137 | $resultStr = $this->luckyPost($postObj);
138 | }
139 |
140 | if ($eventkey=="r" || $eventkey=="R") {
141 | $resultStr = $this->randomPost($postObj);
142 | }
143 |
144 |
145 | }
146 |
147 | }
148 | if(empty($resultStr)){
149 | $resultStr = $this->baseText($postObj);
150 | }
151 | echo $resultStr;
152 | }else {
153 | echo "";
154 | exit;
155 | }
156 | /*
157 | $dir = __TYPECHO_ROOT_DIR__ . DIRECTORY_SEPARATOR;
158 | $myfile = $dir.'nihao.txt';
159 | echo $myfile;
160 | $file_pointer = @fopen($myfile,"a");
161 | @fwrite($file_pointer, $resultStr);
162 | @fclose($file_pointer);
163 | */
164 | }
165 |
166 | public function action(){
167 | //$this->widget('Widget_User')->pass('administrator');
168 | //$this->response->goBack();
169 | $this->link();
170 | if($this->request->is('menus')){ //菜单业务
171 | Typecho_Widget::widget('WeChatHelper_Widget_Menus')->action();
172 | }
173 |
174 | }
175 |
176 | private function checkSignature($_token)
177 | {
178 | $signature = $this->request->get('signature');
179 | $timestamp = $this->request->get('timestamp');
180 | $nonce = $this->request->get('nonce');
181 |
182 | $token = $_token;
183 | $tmpArr = array($token, $timestamp, $nonce);
184 | sort($tmpArr);
185 | $tmpStr = implode($tmpArr);
186 | $tmpStr = sha1($tmpStr);
187 |
188 | if($tmpStr == $signature){
189 | return true;
190 | }else{
191 | return false;
192 | }
193 | }
194 | /** 基础文本信息 **/
195 | private function baseText($postObj, $contentStr=''){
196 | if(empty($contentStr)){
197 | $options = Helper::options()->plugin('WeChatHelper');
198 | $contentStr = '<<<你在说什么? 可以发送\'h\'来查看帮助!';
199 | }
200 | $fromUsername = $postObj->FromUserName;
201 | $toUsername = $postObj->ToUserName;
202 | $time = time();
203 | $resultStr = sprintf($this->_textTpl, $fromUsername, $toUsername, $time, $contentStr);
204 | return $resultStr;
205 | }
206 |
207 | /** 最新日志 **/
208 | private function newPost($postObj){
209 | $db = Typecho_Db::get();
210 | $sql = $db->select()->from('table.contents')
211 | ->where('table.contents.status = ?', 'publish')
212 | ->where('table.contents.type = ?', 'post')
213 | ->order('table.contents.created', Typecho_Db::SORT_DESC)
214 | ->limit($this->_imageNum);
215 | $result = $db->fetchAll($sql);
216 |
217 | $resultStr = $this->sqlData($postObj, $result);
218 | return $resultStr;
219 | }
220 |
221 | /** 随机日志 **/
222 | private function randomPost($postObj){
223 | $db = Typecho_Db::get();
224 | $sql = $db->select()->from('table.contents')
225 | ->where('table.contents.status = ?','publish')
226 | ->where('table.contents.type = ?', 'post')
227 | ->where('table.contents.created <= unix_timestamp(now())', 'post') //添加这一句避免未达到时间的文章提前曝光
228 | ->limit($this->_imageNum)
229 | ->order('RAND()');
230 | $result = $db->fetchAll($sql);
231 |
232 | $resultStr = $this->sqlData($postObj, $result);
233 | return $resultStr;
234 | }
235 | /** 手气不错 **/
236 | private function luckyPost($postObj){
237 | $db = Typecho_Db::get();
238 | $sql = $db->select()->from('table.contents')
239 | ->where('table.contents.status = ?','publish')
240 | ->where('table.contents.type = ?', 'post')
241 | ->where('table.contents.password IS NULL')
242 | ->limit(1)
243 | ->order('RAND()');
244 | $result = $db->fetchAll($sql);
245 |
246 | $resultStr = $this->sqlData($postObj, $result);
247 | return $resultStr;
248 | }
249 |
250 | /** 搜索日志 **/
251 | private function searchPost($postObj, $searchParam){
252 | $searchParam = '%' . str_replace(' ', '%', $searchParam) . '%';
253 |
254 | $db = Typecho_Db::get();
255 | $sql = $db->select()->from('table.contents')
256 | ->where('table.contents.password IS NULL')
257 | ->where('table.contents.title LIKE ? OR table.contents.text LIKE ?', $searchParam, $searchParam)
258 | ->where('table.contents.status = ?', 'publish')
259 | ->where('table.contents.type = ?', 'post')
260 | ->order('table.contents.created', Typecho_Db::SORT_DESC)
261 | ->limit($this->_imageNum);
262 | $result = $db->fetchAll($sql);
263 |
264 | $resultStr = $this->sqlData($postObj, $result);
265 | return $resultStr;
266 | }
267 |
268 | private function sqlData($postObj, $data){
269 | $_subMaxNum = Helper::options()->plugin('WeChatHelper')->subMaxNum;
270 | $resultStr = "";
271 | $num = 0;
272 | $tmpPicUrl = "";
273 |
274 | if($data != null){
275 | foreach($data as $val){
276 | $val = Typecho_Widget::widget('Widget_Abstract_Contents')->filter($val);
277 | $content = Typecho_Common::subStr(strip_tags($val['text']), 0, $_subMaxNum, '...');
278 | //$preg = "/
_imageDefault;
295 | }
296 | }
297 |
298 | //$tmpPicUrl = $this->_imageDefault;
299 | }
300 | $tmpPicUrl = $tmpPicUrl."?imageView2/1/w/300";
301 | $resultStr .= sprintf($this->_itemTpl, $val['title'], $content, $tmpPicUrl, $val['permalink']);
302 | $num++;
303 | }
304 | }else{
305 | $resultStr = "没有找到任何信息!";
306 | }
307 | $fromUsername = $postObj->FromUserName;
308 | $toUsername = $postObj->ToUserName;
309 | $time = time();
310 | if($data != null){
311 | $resultStr = sprintf($this->_imageTpl, $fromUsername, $toUsername, $time, $num, $resultStr);
312 | }else{
313 | $resultStr = sprintf($this->_textTpl, $fromUsername, $toUsername, $time, $resultStr);
314 | }
315 | return $resultStr;
316 | }
317 |
318 | }
319 | ?>
320 |
--------------------------------------------------------------------------------
/Page/Menus.php:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
12 |
13 |
75 |
76 | form()->render(); ?>
77 |
78 |
79 |
80 |
81 |
85 |
86 |
103 |
104 |
--------------------------------------------------------------------------------
/Plugin.php:
--------------------------------------------------------------------------------
1 | getAdapterName() || "Mysql" === $db->getAdapterName()) {
27 | /**
28 | * 创建自定义菜单表
29 | */
30 | $db->query("CREATE TABLE IF NOT EXISTS " . $db->getPrefix() . 'wch_menus' . " (
31 | `mid` int(11) NOT NULL AUTO_INCREMENT,
32 | `level` varchar(10) DEFAULT 'button',
33 | `name` varchar(200) DEFAULT '',
34 | `type` varchar(10) DEFAULT 'view',
35 | `value` varchar(200) DEFAULT '',
36 | `sort` int(3) DEFAULT '0',
37 | `order` int(3) DEFAULT '1',
38 | `parent` int(11) DEFAULT '0',
39 | `created` int(10) DEFAULT '0',
40 | PRIMARY KEY (`mid`)
41 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1");
42 | $db->query("INSERT INTO `" . $db->getPrefix() . 'wch_menus' . "` (`mid`, `level`, `name`, `type`, `value`, `sort`, `order`, `parent`, `created`) VALUES
43 | (1, 'button', '首页', 'view', 'https://holmesian.org/', 10, 1, 0, 1503804104),
44 | (3, 'button', '搜索', 'view', 'https://m.holmesian.org/', 20, 2, 0, 1503804141),
45 | (4, 'button', '其他', 'click', NULL, 50, 5, 0, 1503804153),
46 | (6, 'sub_button', '最新文章', 'click', 'n', 51, 1, 4, 1503804247),
47 | (7, 'sub_button', '随机文章', 'click', 'r', 52, 2, 4, 1503807202),
48 | (8, 'sub_button', '手气不错', 'click', 'l', 54, 4, 4, 1503824995);");
49 |
50 | $db->query($db->sql()->insert('table.options')->rows(array("name"=>"WCH_access_token","user"=>"0","value"=>"0")));
51 | $db->query($db->sql()->insert('table.options')->rows(array("name"=>"WCH_expires_in","user"=>"0","value"=>"0")));
52 |
53 | } else {
54 | throw new Typecho_Plugin_Exception(_t('对不起, 本插件仅支持MySQL数据库。'));
55 | }
56 |
57 | Helper::addAction('WeChat', 'WeChatHelper_Action');
58 | Helper::addPanel(1, 'WeChatHelper/Page/Menus.php', '公众号菜单', '公众号菜单', 'administrator');
59 |
60 | return ('微信助手已经成功激活,请进入设置Token!');
61 | }
62 |
63 | /**
64 | * 禁用插件方法,如果禁用失败,直接抛出异常
65 | *
66 | * @static
67 | * @access public
68 | * @return void
69 | * @throws Typecho_Plugin_Exception
70 | */
71 | public static function deactivate()
72 | {
73 | $db = Typecho_Db::get();
74 | $options = Typecho_Widget::widget('Widget_Options');
75 | if ("Pdo_Mysql" === $db->getAdapterName() || "Mysql" === $db->getAdapterName()) {
76 | $db->query("drop table " . $db->getPrefix() . "wch_menus");
77 | $db->query($db->sql()->delete('table.options')->where('name like ?', "WCH_%"));
78 | }
79 | Helper::removePanel(1, 'WeChatHelper/Page/Menus.php');
80 |
81 | Helper::removeRoute('wechat');
82 | Helper::removeAction('wechatHelper');
83 | }
84 |
85 | /**
86 | * 获取插件配置面板
87 | *
88 | * @access public
89 | * @param Typecho_Widget_Helper_Form $form 配置面板
90 | * @return void
91 | */
92 | public static function config(Typecho_Widget_Helper_Form $form)
93 | {
94 |
95 | /** 用户添加订阅欢迎语 **/
96 | $welcome = new Typecho_Widget_Helper_Form_Element_Textarea('welcome', NULL, '欢迎!' . chr(10) . '发送\'h\'让小的给您介绍一下!', '订阅欢迎语', '用户订阅之后主动发送的一条欢迎语消息。');
97 | $form->addInput($welcome);
98 | /** 返回最大结果条数 **/
99 | $imageDefault = new Typecho_Widget_Helper_Form_Element_Text('imageDefault', NULL, 'https://holmesian.org/usr/themes/Holmesian/image/avatar.jpg', _t('默认显示图片'), '图片链接,支持JPG、PNG格式,推荐图为80*80。');
100 | $form->addInput($imageDefault);
101 | /** 返回最大结果条数 **/
102 | $imageNum = new Typecho_Widget_Helper_Form_Element_Text('imageNum', NULL, '5', _t('返回图文数量'), '图文消息数量,限制为10条以内。');
103 | $imageNum->input->setAttribute('class', 'mini');
104 | $form->addInput($imageNum);
105 | /** 日志截取字数 **/
106 | $subMaxNum = new Typecho_Widget_Helper_Form_Element_Text('subMaxNum', NULL, '200', _t('日志截取字数'), '显示单条日志时,截取日志内容字数。');
107 | $subMaxNum->input->setAttribute('class', 'mini');
108 | $form->addInput($subMaxNum);
109 |
110 | /** Token **/
111 | $token = new Typecho_Widget_Helper_Form_Element_Text('token', NULL, '', _t('令牌(Token)'), '需要与开发模式服务器配置中填写一致。服务器地址(URL):' . Helper::options()->index . '/wechat');
112 | $form->addInput($token);
113 |
114 | /** APP_ID **/
115 | $appid = new Typecho_Widget_Helper_Form_Element_Text('WCH_appid', NULL, NULL,
116 | _t('APP_ID'), _t('需要管理菜单时填写,与开发模式服务器配置中填写一致。'));
117 |
118 | /** APP_Secret **/
119 | $form->addInput($appid);
120 | $appsecret = new Typecho_Widget_Helper_Form_Element_Text('WCH_appsecret', NULL, NULL,
121 | _t('APP_Secret'), _t('需要管理菜单时填写,与开发模式服务器配置中填写一致。'));
122 | $form->addInput($appsecret);
123 |
124 | }
125 |
126 | /**
127 | * 个人用户的配置面板
128 | *
129 | * @access public
130 | * @param Typecho_Widget_Helper_Form $form
131 | * @return void
132 | */
133 | public static function personalConfig(Typecho_Widget_Helper_Form $form)
134 | {
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WeChatHelper
2 | 一款基于Typecho的微信助手插件(修改版)
3 |
4 |
5 | ## 插件功能 ##
6 |
7 | - 自定义菜单功能
8 | - 最新博客文章列表
9 | - 随机博客文章列表
10 | - 搜索博客文章
11 |
12 | ## 使用方法 ##
13 |
14 | 1. 下载插件
15 |
16 | 直接下载解压,或者在/typecho/usr/plugins目录下git clone https://github.com/holmesian/WeChatHelper.git
17 |
18 | 2. 登陆Typecho后台,在“控制台”下拉菜单中进入“插件管理”,启用插件。
19 |
20 | 3. 登陆微信公众平台( https://mp.weixin.qq.com )后台,在“开发”-》“基本配置”里,修改服务器地址为 http(s)://{域名}/wechat,(例如https://holmesian.org/wechat ) 。
21 |
22 | 4. 在插件设置中填写微信的“令牌(Token)”,与微信公众平台中的“令牌(Token)”保持一致。
23 |
24 | 5. 在微信公众平台启用服务器配置。
25 |
26 | 6. 在“自定义菜单”下中进入修改微信公众号菜单,并通过“微信接口操作”-》“创建自定义菜单”来发布菜单到公众号。(发布菜单需在插件设置里APP_ID、APP_Secret)
27 |
28 |
29 | ## 效果测试 ##
30 |
31 | 1. 添加微信号Aide-X查看效果。
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/Widget/Menus.php:
--------------------------------------------------------------------------------
1 | siteUrl = Helper::options()->siteUrl;
16 | }
17 |
18 | public function select() {
19 | return $this->db->select()->from('table.wch_menus');
20 | }
21 | public function insert(array $options) {
22 | return $this->db->query($this->db->insert('table.wch_menus')->rows($options));
23 | }
24 | public function update(array $options, Typecho_Db_Query $condition){
25 | return $this->db->query($condition->update('table.wch_menus')->rows($options));
26 | }
27 | public function delete(Typecho_Db_Query $condition){
28 | return $this->db->query($condition->delete('table.wch_menus'));
29 | }
30 | public function size(Typecho_Db_Query $condition){
31 | return $this->db->fetchObject($condition->select(array('COUNT(table.wch_menus.uid)' => 'num'))->from('table.wch_menus'))->num;
32 | }
33 |
34 | public function execute(){
35 | /** 构建基础查询 */
36 | $select = $this->select()->from('table.wch_menus');
37 |
38 | /** 给计算数目对象赋值,克隆对象 */
39 | $this->_countSql = clone $select;
40 |
41 | /** 提交查询 */
42 | $select->order('table.wch_menus.sort', Typecho_Db::SORT_ASC);
43 | $this->db->fetchAll($select, array($this, 'push'));
44 | }
45 |
46 | public function filter(array $value) {
47 | $value['levelVal'] = $value['level'] == 'button' ? '##' : '└──';
48 | $value['tr'] = $value['level'] == 'button' ? 'style="background-color: #F0F0EC"' : '';
49 | return $value;
50 | }
51 |
52 | public function push(array $value) {
53 | $value = $this->filter($value);
54 | return parent::push($value);
55 | }
56 |
57 | /**
58 | * 生成表单
59 | *
60 | * @access public
61 | * @param string $action 表单动作
62 | * @return Typecho_Widget_Helper_Form_Element
63 | */
64 | public function form($action = NULL) {
65 | if (isset($this->request->mid) && 'insert' != $action) {
66 | /** 更新模式 */
67 | $menu = $this->db->fetchRow($this->select()->where('mid = ?', $this->request->mid)->limit(1));
68 |
69 | if (!$menu) {
70 | $this->response->redirect(Helper::url('WeChatHelper/Page/Menus.php', $this->options->adminUrl));
71 | }
72 | }
73 | /** 构建表格 */
74 | $form = new Typecho_Widget_Helper_Form($this->security->getIndex('action/WeChat?menus'), Typecho_Widget_Helper_Form::POST_METHOD);
75 |
76 | $select = $this->select()->where('table.wch_menus.parent = ?', '0')->order('table.wch_menus.order', Typecho_Db::SORT_ASC);
77 | $buttonMenus = $this->db->fetchAll($select);
78 |
79 | $parent = '';
88 |
89 | $level = new Typecho_Widget_Helper_Form_Element_Radio('level',
90 | array('button' => _t('一级菜单'), 'sub_button' => _t('二级菜单 '.$parent)),
91 | 'button', _t('消息类型'), NULL);
92 | $form->addInput($level->multiMode());
93 |
94 | $name = new Typecho_Widget_Helper_Form_Element_Text('name', NULL, NULL,
95 | _t('标题'), _t('菜单标题,不超过16个字节。'));
96 | $form->addInput($name);
97 |
98 | $type = new Typecho_Widget_Helper_Form_Element_Radio('type', array('click' => _t('Click类型'), 'view' => _t('View类型')), 'click', _t('消息类型'), NULL);
99 | $form->addInput($type);
100 |
101 | $value = new Typecho_Widget_Helper_Form_Element_Text('value', NULL, NULL,
102 | _t('Key & URL值'), _t('Click类型:菜单KEY值,用于消息接口推送,不超过128字节;
View类型:网页链接,用户点击菜单可打开链接,不超过256字节。'));
103 | $form->addInput($value);
104 |
105 | $order = new Typecho_Widget_Helper_Form_Element_Select('order',
106 | array('1' => _t('1'),
107 | '2' => _t('2'),
108 | '3' => _t('3'),
109 | '4' => _t('4'),
110 | '5' => _t('5')), '1', _t('排序'), NULL);
111 | $form->addInput($order);
112 |
113 | $do = new Typecho_Widget_Helper_Form_Element_Hidden('do', NULL, NULL);
114 | $form->addInput($do);
115 |
116 | $mid = new Typecho_Widget_Helper_Form_Element_Hidden('mid', NULL, NULL);
117 | $form->addInput($mid);
118 |
119 | $submit = new Typecho_Widget_Helper_Form_Element_Submit(NULL, NULL, NULL);
120 | $submit->input->setAttribute('class', 'btn primary');
121 | $form->addItem($submit);
122 |
123 | if (isset($this->request->mid) && 'insert' != $action) {
124 | $level->value($menu['level']);
125 | $name->value($menu['name']);
126 | $type->value($menu['type']);
127 | $value->value($menu['value']);
128 | $order->value($menu['order']);
129 | $mid->value($menu['mid']);
130 | $submit->value(_t('编辑菜单'));
131 | $do->value('update');
132 | $_action = 'update';
133 | } else {
134 | $submit->value(_t('增加菜单'));
135 | $do->value('insert');
136 | $_action = 'insert';
137 | }
138 |
139 | if (empty($action)) {
140 | $action = $_action;
141 | }
142 |
143 | /** 给表单增加规则 */
144 | if ('insert' == $action || 'update' == $action) {
145 | $level->addRule(array($this, 'checkLevelNum'), _t('一级标题不能超过3个或同一一级标题下的二级标题不能超过5个。'), 'mid');
146 | $name->addRule('required', _t('标题不能为空'));
147 | $name->addRule(array($this, 'checkMaxLength'), _t('菜单标题最多包含16个字符'), 'type');
148 | $value->addRule(array($this, 'checkKeyOrUrl'), _t('URL格式不正确'), 'type');
149 | $value->addRule(array($this, 'checkKeyOrUrlMaxLength'), _t('View类型最多包含128个字符,Click类型最多包含256个字符。'), 'type');
150 | //$name->addRule('checkMaxLength', _t('菜单标题最多包含5个字符'), 5);
151 | }
152 |
153 | if ('update' == $action) {
154 | $mid->addRule('required', _t('菜单主键不存在'));
155 | //$mid->addRule(array($this, 'categoryExists'), _t('分类不存在'));
156 | }
157 |
158 | return $form;
159 | }
160 |
161 | public function checkMaxLength($name, $type){
162 | $type = $this->request->get($type);
163 | $length = 16;
164 | if(strlen($name) > $length){
165 | return false;
166 | }else{
167 | return true;
168 | }
169 | }
170 |
171 | public function checkKeyOrUrl($value, $type){
172 | $type = $this->request->get($type);
173 | if($type == 'view'){
174 | return Typecho_Validate::url($value);
175 | }else{
176 | return true;
177 | }
178 | }
179 |
180 | public function checkLevelNum($value, $mid){
181 | $mid = $this->request->get($mid);
182 | $select = $this->db->sql()->select(array('COUNT(table.wch_menus.mid)' => 'num'))->from('table.wch_menus')->where('level = ?', $value);
183 | if($value == 'button'){
184 | if($mid){
185 | $select->where('mid <> ?', $mid);
186 | }
187 | $num = $this->db->fetchObject($select)->num;
188 | if($num>=3){
189 | return false;
190 | }else{
191 | return true;
192 | }
193 | }else if($value == 'sub_button'){
194 | $parent = $this->request->get('parent');
195 | if($parent){
196 | $select->where('parent = ?', $parent);
197 | }
198 | if($mid){
199 | $select->where('mid <> ?', $mid);
200 | }
201 | $num = $this->db->fetchObject($select)->num;
202 | if($num>=5){
203 | return false;
204 | }else{
205 | return true;
206 | }
207 | }
208 | }
209 |
210 | public function checkKeyOrUrlMaxLength($value, $type){
211 | $type = $this->request->get($type);
212 | $length = $type == 'click' ? 256 : 128;
213 | if(strlen($value) > $length){
214 | return false;
215 | }else{
216 | return true;
217 | }
218 | }
219 |
220 | public function getParentOrder($menu){
221 | if($menu['level'] == 'sub_button'){
222 | $select = $this->db->sql()->select(array('table.wch_menus.order' => 'order'))->from('table.wch_menus')->where('mid = ?', $menu['parent']);
223 | $order = $this->db->fetchObject($select)->order;
224 | $menu['sort'] = ($order * 10) + $menu['order'];
225 | }else{
226 | $menu['sort'] = $menu['order'] * 10;
227 | $menu['parent'] = '0';
228 | }
229 | return $menu;
230 | }
231 |
232 | /**
233 | * 分类排序
234 | *
235 | * @access public
236 | * @return void
237 | */
238 | public function orderMenu() {
239 | $menus = $this->request->filter('int')->getArray('mid');
240 | $levels = $this->request->getArray('level');
241 | if ($menus) {
242 | $parent = 0;
243 | foreach ($menus as $sort => $mid) {
244 | $param = array('order' => $sort + 1);
245 | if($levels[$sort] == 'button'){
246 | $parent = $mid;
247 | $param['parent'] = '0';
248 | }else{
249 | $param['parent'] = $parent;
250 | }
251 | $this->update($param, $this->db->sql()->where('mid = ?', $mid));
252 | }
253 | }
254 |
255 | if (!$this->request->isAjax()) {
256 | /** 转向原页 */
257 | $this->response->redirect(Typecho_Common::url('manage-categories.php', $this->options->adminUrl));
258 | } else {
259 | $this->response->throwJson(array('success' => 1, 'message' => _t('分类排序已经完成')));
260 | }
261 | }
262 |
263 | public function insertMenu() {
264 | if ($this->form('insert')->validate()) {
265 | $this->response->goBack();
266 | }
267 | /** 取出数据 */
268 | $menu = $this->request->from('level', 'name', 'type', 'value', 'parent', 'order');
269 | $menu = $this->getParentOrder($menu);
270 | $menu['created'] = time();
271 |
272 | /** 插入数据 */
273 | $menu['mid'] = $this->db->query($this->insert($menu));
274 | $this->push($menu);
275 |
276 | $this->widget('Widget_Notice')->highlight('menus-mid-'.$menu['mid']);
277 | $this->widget('Widget_Notice')->set(_t('自定义菜单添加成功'), 'success');
278 | $this->response->redirect(Helper::url('WeChatHelper/Page/Menus.php', $this->options->adminUrl));
279 | }
280 |
281 | public function updateMenu() {
282 | if ($this->form('insert')->validate()) {
283 | $this->response->goBack();
284 | }
285 | /** 取出数据 */
286 | $menu = $this->request->from('level', 'name', 'type', 'value', 'parent', 'order', 'mid');
287 | $menu = $this->getParentOrder($menu);
288 |
289 | /** 插入数据 */
290 | $this->db->query($this->update($menu, $this->db->sql()->where('mid = ?', $this->request->filter('int')->mid)));
291 | if($menu['level'] == 'button'){
292 | $this->db->query($this->db->sql()->update('table.wch_menus')->where('parent = ?', $menu['mid'])->expression('sort', ($menu['order'] * 10) . ' + `order` '));
293 | }
294 | $this->push($menu);
295 |
296 | $this->widget('Widget_Notice')->highlight('menus-mid-'.$menu['mid']);
297 | $this->widget('Widget_Notice')->set(_t('自定义菜单修改成功'), 'success');
298 | $this->response->redirect(Helper::url('WeChatHelper/Page/Menus.php', $this->options->adminUrl));
299 | }
300 |
301 | public function deleteMenu() {
302 | $menus = $this->request->filter('int')->getArray('mid');
303 | $deleteCount = 0;
304 |
305 | if ($menus && is_array($menus)) {
306 | foreach ($menus as $menu) {
307 | if ($this->delete($this->db->sql()->where('mid = ?', $menu)->orWhere('parent = ?', $menu))) {
308 | $deleteCount ++;
309 | }
310 | }
311 | }
312 |
313 | /** 提示信息 */
314 | $this->widget('Widget_Notice')->set($deleteCount > 0 ? _t('自定义菜单已经删除') : _t('没有自定义菜单被删除'),
315 | $deleteCount > 0 ? 'success' : 'notice');
316 |
317 | /** 转向原页 */
318 | $this->response->redirect(Helper::url('WeChatHelper/Page/Menus.php', $this->options->adminUrl));
319 | }
320 |
321 | public function createMenu(){
322 | $accessToken = Utils::getAccessToken();
323 | if(!$accessToken){
324 | $this->widget('Widget_Notice')->set('获取Access Token异常!', 'error');
325 | $this->response->redirect(Helper::url('WeChatHelper/Page/Menus.php', $this->options->adminUrl));
326 | }
327 | $create['button'] = array();
328 | $select = $this->select()->where('level = ?', 'button')->order('table.wch_menus.order', Typecho_Db::SORT_ASC);
329 | $buttons = $this->db->fetchAll($select);
330 | if (count($buttons) > 3 || !count($buttons)) {
331 | $this->widget('Widget_Notice')->set(_t('错误:一级菜单没有找到或超过三个.'), 'error');
332 | $this->response->redirect(Helper::url('WeChatHelper/Page/Menus.php', $this->options->adminUrl));
333 | }
334 | foreach ($buttons as $row) {
335 | $button = array();
336 | $select = "";
337 | $select = $this->select()->where('level = ?', 'sub_button')->where('parent = ?', $row['mid'])->order('table.wch_menus.order', Typecho_Db::SORT_ASC);
338 | $subButtons = $this->db->fetchAll($select);
339 | if (!count($subButtons)) { //没有二级菜单
340 | $button['type'] = urlencode($row['type']);
341 | $button['name'] = urlencode($row['name']);
342 | $button[$row['type'] == 'view' ? 'url' : 'key'] = urlencode($row['value']);
343 | }else{
344 | $button['name'] = urlencode($row['name']);
345 | $tmp = array();
346 | foreach ($subButtons as $row) {
347 | $subButton = array();
348 | $subButton['type'] = urlencode($row['type']);
349 | $subButton['name'] = urlencode($row['name']);
350 | $subButton[$row['type'] == 'view' ? 'url' : 'key'] = urlencode($row['value']);
351 | array_push($tmp, $subButton);
352 | }
353 | $button['sub_button'] = $tmp;
354 | }
355 | array_push($create['button'], $button);
356 | }
357 |
358 | $json = json_encode($create);
359 |
360 | try {
361 | $client = Typecho_Http_Client::get();
362 | $params = array('access_token' => $accessToken);
363 | $response = $client->setQuery($params)->setData(urldecode($json))->send(Utils::MENU_CREATE_URL);
364 | } catch (Exception $e) {
365 | $this->widget('Widget_Notice')->set(_t('对不起,创建自定义菜单失败,请重试!'), 'error');
366 | $this->response->redirect(Helper::url('WeChatHelper/Page/Menus.php', $this->options->adminUrl));
367 | }
368 |
369 | $result = json_decode($response);
370 | if($result->errcode){
371 | $this->widget('Widget_Notice')->set(_t('对不起,创建自定义菜单失败,错误原因:'.$result->errmsg), 'notice');
372 | }else{
373 | $this->widget('Widget_Notice')->set(_t('恭喜您,创建自定义菜单成功!'), 'success');
374 | }
375 | $this->response->redirect(Helper::url('WeChatHelper/Page/Menus.php', $this->options->adminUrl));
376 | }
377 |
378 | public function removeMenu(){
379 | $accessToken = Utils::getAccessToken();
380 | if(!$accessToken){
381 | $this->widget('Widget_Notice')->set('获取Access Token异常!', 'error');
382 | $this->response->redirect(Helper::url('WeChatHelper/Page/Menus.php', $this->options->adminUrl));
383 | }
384 |
385 | try {
386 | $client = Typecho_Http_Client::get();
387 | $params = array('access_token' => $accessToken);
388 | $response = $client->setQuery($params)->send(Utils::MENU_REMOVE_URL);
389 | } catch (Exception $e) {
390 | $this->widget('Widget_Notice')->set(_t('对不起,删除自定义菜单失败,请重试!'), 'error');
391 | $this->response->redirect(Helper::url('WeChatHelper/Page/Menus.php', $this->options->adminUrl));
392 | }
393 |
394 | $result = json_decode($response);
395 | if($result->errcode){
396 | $this->widget('Widget_Notice')->set(_t('对不起,删除自定义菜单失败,错误原因:'.$result->errmsg), 'notice');
397 | }else{
398 | $this->widget('Widget_Notice')->set(_t('恭喜您,删除自定义菜单成功!'), 'success');
399 | }
400 | $this->response->redirect(Helper::url('WeChatHelper/Page/Menus.php', $this->options->adminUrl));
401 | }
402 |
403 | public function action() {
404 | $this->security->protect();
405 | $this->on($this->request->is('do=insert'))->insertMenu();
406 | $this->on($this->request->is('do=update'))->updateMenu();
407 | $this->on($this->request->is('do=delete'))->deleteMenu();
408 | $this->on($this->request->is('do=order'))->orderMenu();
409 | $this->on($this->request->is('do=create'))->createMenu();
410 | $this->on($this->request->is('do=remove'))->removeMenu();
411 | $this->response->redirect($this->options->adminUrl);
412 | }
413 | }
414 |
--------------------------------------------------------------------------------
/Widget/Utils.php:
--------------------------------------------------------------------------------
1 | '哟,客官,您来啦!'.chr(10).'发送\'h\'让小的给您介绍一下!',
8 | 'notfound' => '对不起,我完全不明白你在说什么!'
9 | );
10 | return $tmp[$msg];
11 | }
12 | public static function getMsgType($type = NULL){
13 | $result = array('text' => '文本消息',
14 | //'image' => '图片消息',
15 | 'system' => '系统消息',
16 | 'addons' => '插件扩展');
17 | if($type){
18 | return $result[$type];
19 | }else{
20 | return $result;
21 | }
22 | }
23 |
24 | public static function getSystemMsg(){
25 | $result = array('sys_random' => '随机日志',
26 | 'sys_recent' => '最新日志',
27 | 'sys_hot_comment' => '热评日志');
28 | return $result;
29 | }
30 |
31 | public static function getAccessToken(){
32 | $db = Typecho_Db::get();
33 | $WCH_expires_in = Typecho_Widget::widget('Widget_Options')->WCH_expires_in;
34 | $WCH_access_token = Typecho_Widget::widget('Widget_Options')->WCH_access_token;
35 | $options =Helper::options()->plugin('WeChatHelper');
36 | if(isset($options->WCH_appid) && isset($options->WCH_appsecret)){
37 | var_dump($options);
38 | if(isset($WCH_access_token) && isset($WCH_expires_in) && $WCH_expires_in > time()){
39 | return $WCH_access_token;
40 | }else{
41 | $client = Typecho_Http_Client::get();
42 | $params = array('grant_type' => 'client_credential',
43 | 'appid' => $options->WCH_appid, 'secret' => $options->WCH_appsecret);
44 | $response = $client->setQuery($params)->send('https://api.weixin.qq.com/cgi-bin/token');
45 | $response = json_decode($response);
46 | if(isset($response->errcode)){
47 | //throw new Typecho_Plugin_Exception(_t('对不起,请求错误。ErrCode:'.$response->errcode.' - ErrMsg:'.$response->errmsg));
48 | return NULL;
49 | }else{
50 | $db->query($db->update('table.options')->rows(array('value' => $response->access_token))->where('name = ?', 'WCH_access_token'));
51 | $db->query($db->update('table.options')->rows(array('value' => time() + $response->expires_in))->where('name = ?', 'WCH_expires_in'));
52 | return $response->access_token;
53 | }
54 | }
55 | }else{
56 | //throw new Typecho_Plugin_Exception(_t('对不起, 请先在高级功能中填写正确的APP ID和APP Secret。'));
57 | return NULL;
58 | }
59 | }
60 | }
61 |
62 | class MessageTemplate {
63 | const TEXT = 'text'; //文本
64 | const IMAGE = 'image'; //图片
65 | const VOICE = 'voice'; //语音
66 | const VIDEO = 'video'; //视频
67 | const MUSIC = 'music'; //音乐
68 | const NEWS = 'news'; //图文
69 | const THIRD = 'third'; //第三方
70 | private $toUserName;
71 | private $fromUserName;
72 | /**
73 | * 消息时间
74 | */
75 | private $createTime;
76 | /**
77 | * 消息类型
78 | */
79 | private $msgType;
80 | /**
81 | * 最终输出内容
82 | */
83 | private $result;
84 | /**
85 | * 设置消息内容
86 | */
87 | private $content;
88 | /**
89 | *
90 | */
91 | private $item = array();
92 | private $sendContent;
93 | private $_textTpl;
94 | private $_newsTpl;
95 | private $_itemTpl;
96 |
97 | public function __construct($postObj) {
98 | $this->toUserName = $postObj->ToUserName;
99 | $this->fromUserName = $postObj->FromUserName;
100 | $this->createTime = time();
101 | $this->_textTpl = "%s0";
102 | $this->_newsTpl = "%s%s%s0";
103 | $this->_itemTpl = " ";
104 | }
105 | /**
106 | * 设置直接发送的消息内容,适用于第三方平台
107 | */
108 | public function setSendContent($sendContent){
109 | $this->sendContent = $sendContent;
110 | return $this;
111 | }
112 | /**
113 | * 设置消息类型
114 | */
115 | public function setMsgType($msgType){
116 | $this->msgType = $msgType;
117 | return $this;
118 | }
119 | /**
120 | * 设置文本内容
121 | */
122 | public function setText($content) {
123 | $this->content = $content;
124 | return $this;
125 | }
126 | /**
127 | * 组合发送消息
128 | */
129 | public function addItem($item){
130 | array_push($this->item, $item);
131 | }
132 | public function send(){
133 | switch ($this->msgType) {
134 | case MessageTemplate::TEXT:
135 | $this->result = sprintf($this->_textTpl, $this->fromUserName, $this->toUserName, $this->createTime, $this->content);
136 | break;
137 | case MessageTemplate::THIRD:
138 | $this->result = $this->sendContent;
139 | break;
140 | case MessageTemplate::IMAGE:
141 | $this->result = '图片类型';
142 | break;
143 | case MessageTemplate::NEWS:
144 | foreach ($this->item as $key => $value) {
145 | $this->result .= sprintf($this->_itemTpl, $value['title'], $value['description'], $value['picurl'], $value['url']);
146 | }
147 | $this->result = sprintf($this->_newsTpl, $this->fromUserName, $this->toUserName, $this->createTime, count($this->item), $this->result);
148 | break;
149 | default:
150 | $this->result = 'error';
151 | }
152 | echo $this->result;
153 | }
154 | }
155 | ?>
--------------------------------------------------------------------------------