首页 > 代码库 > 【微信公众平台开发】之二:高级功能开发(基于SAE)

【微信公众平台开发】之二:高级功能开发(基于SAE)

导引:选择BAE还是SAE

*BAE3.0使用git推送每次修改非常爽,

本地修改>推送到oschina(自己留念)和BAE>点击发布>实际测试;

但是没有在线代码编辑功能!!中间出现问题就很坑爹,得重来一遍。

*SAE缺点是不能使用git,但可以在线编辑!(很多时候只是想验证新想法,在线编辑非常有用)。还有SAE可以上传多个版本的代码,比如版本1设为默认发布,版本2调试新功能a,版本3调试新功能b。而且不同版本可独立访问,调试起来非常方便。我一般先用“微信开发测试小助手”测试新功能可用,再将其添加到默认版本。

*微信开发模式页面需要填写服务器URL和Token,如果BAE可以多个版本共存,那么微信接口可以在SAE和BAE之间随意切换,而且BAE的版本回退好像有点问题。

*综上,BAE很坑,用SAE吧

0、资料

0.1、五星PHP+新浪SAE平台免费搭建微信公众帐号平台消息接口,实现查天气、无(http://coolwb.com/2460.html)

0.2、微信本地调试工具“Fiddler”(没用过)以及“微信开发测试小助手”(推荐这个);

1、对各类信息的回复以及图文回复

<?php
/**
  * wechat php test
  * 主要用于本机测试
  * by Jason
  * 2014.9.17
  */

//define your token
define("TOKEN", "weixin");
$wechatObj = new wechatCallbackapiTest();
//$wechatObj->valid(); 注释掉验证函数
$wechatObj->responseMsg();//调用回复信息方法

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;
                $keyword = trim($postObj->Content);
                $time = time();
				
				//type为消息类型,customevent为事件类型
				$type =$postObj->MsgType;
				$customevent =$postObj->Event;
				//经纬度
				$weiDu = $postObj->Location_X;
				$jingDu= $postObj->Location_Y;
				
                $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($type=="event" and $customevent=="subscribe"){
					$msgType = "text";
					$contentStr="感谢您的关注\n回复menu 查看本菜单\n回复1 查看联系方式\n回复2 查看小道消息\n回复3 查看办公地址\n回复图片查看新闻";					
					$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
					echo $resultStr;
				}
				//单图文test,执行本句之后不再执行switch语句
            	//$this->replyNews1($fromUsername, $toUsername, $time);
				//接收普通消息
				switch($type){
					//文本消息
                    //文本消息0不适合在本地软件调试
					case "text":{
						if(!empty( $keyword )){
							//关键词回复
							if($keyword=="menu"){
								$contentStr="感谢您的关注\n回复menu 查看本菜单\n回复1 查看联系方式\n回复2 查看小道消息\n回复3 查看办公地址\n回复news 查看新闻";
							}else if($keyword==1){
								$contentStr="联系方式:1007511108";
							}else if($keyword==2){
								$contentStr="小道消息正在加载,请稍候……";
							}else if($keyword==3){
								$contentStr="办公地址:大学城中心湖水下5米";
                            }else if($keyword=="news"){
                                $contentStr="";//设字符串为空
                                $this->replyNews1($fromUsername, $toUsername, $time);
                            }else{
								$contentStr="this is not a legal keyword,please try again";
                                
							}						
						}else{
							$contentStr="输入为空";
						}
						break;
					}
					//图片消息
					case "image":
						$contentStr="这张图真好看";
						break;
					//语音消息
					case "voice":
						sleep(2);
						$contentStr="嗯……你声音真好听";		
						break;
					//视频消息
					case "video":
						sleep(3);
						$contentStr="这部片子不是我喜欢的类型";		
						break;
					//地理位置消息
					case "location":{
						$contentStr="你的纬度是{$weiDu},经度是{$jingDu},捕食者1号已锁定目标!";	
						break;
					}
					//链接消息
					case "link":
						$contentStr="你确定发送的链接没有病毒??";		
						break;
					//消息不是以上类型
					default:
						$contentStr="此项功能尚未开发";
						break;			
				}
				//统一输出
				$msgType = "text";
				$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
				echo $resultStr;

        }else {
        	echo "";
        	exit;
        }
    }
	//发送消息
	//音乐回复
	function replyMusic(){
	}
	//单图文回复
	function replyNews1($fromUsername, $toUsername, $time){
		$newsTpl="<xml>
					<ToUserName><![CDATA[%s]]></ToUserName>
					<FromUserName><![CDATA[%s]]></FromUserName>
					<CreateTime>%s</CreateTime>
					<MsgType><![CDATA[news]]></MsgType>
					<ArticleCount>1</ArticleCount>
					<Articles>
					<item>
					<Title><![CDATA[食品安全关乎人民群众的切身利益]]></Title> 
					<Description><![CDATA[这个news很难Description]]></Description>
					<PicUrl><![CDATA[http://lawlietfans.duapp.com/picture/big1.png]]></PicUrl>
					<Url><![CDATA[http://www.baidu.com]]></Url>
					</item>
					
					</Articles>
					</xml> ";
		$resultStr = sprintf($newsTpl, $fromUsername, $toUsername, $time);
		echo $resultStr;
	}
	//多图文回复
	function replyNews2(){
	}
	
	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;
		}
	}
}

?>

2、API

2.1、图灵机器人

这是我发现的最好的免费智能机器人,查看(http://www.tuling123.com)的帮助文档按照步骤做即可,很简单。

然后解析api返回的json数据即可:

$apiStr = file_get_contents($url); 
$apiObj =json_decode($apiStr);
$contentStr = $apiObj->text;

2.2、LBS开发:百度地图
占位

3、数据库

官方文档(http://sae.sina.com.cn/doc/php/mysql.html)

试图在SAE平台使用BAE中的数据库是行不通的(我还傻傻想为什么),在那家平台就当然要用那家数据库;

首先参考(四星http://blog.csdn.net/zh379835552/article/details/39160967) 

和(五星http://www.cnblogs.com/mchina/p/3332283.html)进入mysqlMyAdmin控制台;

接着创建表weixin并插入数据

CREATE TABLE IF NOT EXISTS `weixin` (

  `id` int(8) NOT NULL AUTO_INCREMENT,

  `title` varchar(255) NOT NULL,

  `content` varchar(255) NOT NULL,

  PRIMARY KEY (`id`)

-- 转存表中的数据 `weixin`

INSERT INTO `weixin` (`id`, `title`, `content`) VALUES

(1, ‘中国合伙人‘, ‘导演:陈可辛;编剧:张冀‘),

(2, ‘死亡笔记‘, ‘导演:dy;编剧:bj‘);

接着编辑php代码,运行即可成功(注释详细,一看就会)

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh">
 <head>
   <meta http-equiv="content-type" content="text/html;charset=utf-8"/>
  <title>database data test</title>
 </head>
 <body>
<?php
//echo "Welcome to Sina Cloud";
//SAE的mysql是utf8编码的所以需要在meta标签中指定页面的charset为utf-8
//从环境变量中取出数据库所要的参数
    $host=getenv(‘SAE_MYSQL_HOST_M‘);
    $port=getenv(‘SAE_MYSQL_PORT‘);
    $user=getenv(‘SAE_MYSQL_USER‘);
    $pwd=getenv(‘SAE_MYSQL_PASS‘);
/***配置数据库名称,全局名MYSQLNAME或者$dbname ***/
 define("MYSQLNAME", "sNAwDmdhLkhSLCmATYsf");
 $dbname=‘app_lawlietfans‘;
//定义好的参数
/*接着调用mysql_connect()连接服务器,可以用上面赋值之后的host、port、user、pwd来替代这里的参数*/
$link = mysql_connect(SAE_MYSQL_HOST_M.‘:‘.SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
if(!$link) {
      die("Connect Server Failed: " . mysql_error());
    }
/*连接成功后立即调用mysql_select_db()选中需要连接的数据库*/
if(!mysql_select_db($dbname,$link)) {
      die("Select Database Failed: " . mysql_error($link));
    }
/*至此连接已完全建立,就可对当前数据库进行相应的操作了*/
    /*!!!注意,无法再通过本次连接调用mysql_select_db来切换到其它数据库了!!!*/
    /* 需要再连接其它数据库,请再使用mysql_connect+mysql_select_db启动另一个连接*/
     
    /**
    * 接下来就可以使用其它标准php mysql函数操作进行数据库操作
    */

//检索数据
    $sql = "select * from weixin";
    $rs = mysql_query($sql, $link);
    if ($rs === false) {
        die("Select Failed: " . mysql_error($link));
    } else {
        echo "Select Succeed<br />";
        while ($row = mysql_fetch_assoc($rs)) {
            echo "{$row[‘id‘]} {$row[‘title‘]} {$row[‘content‘]}<br />";
        }
    }
 ?>
 </body>
</html>

接着在做一个查询电影的功能也很简单。

4、超链接调用其他wap站应用

对工具类的功能来说,与其在微信中找各种接口不如直接调用其他wap站更好,(http://r2.mo.baidu.com/webapp_html.php?version=4_0&fn=webpage_flash)有一些wap站可以参考,推荐(http://m.46644.com/tool/);

有了这些链接,可以以超链接或者图文消息

(若“text”格式则需要XML转义字符:

 

< &lt;
> &gt;
& &amp;
‘  &apos;
" &quot;

 

)的形式引导用户直接访问需要的功能。(当然,如果有自己的wap站点更好。也可使用百度siteapp将普通站点一件转换为wap站)

5、缓存

如果要实现二级菜单,需要记住用户当前在菜单逻辑中的位置。微信服务器不支持cookie和session,使用数据库速度太慢,所以要使用缓存来实现此功能。

文档(http://sae.sina.com.cn/doc/php/memcache.html);

实现图灵机器人智能聊天和普通功能之间的切换;(得瑟下,效果非常好\(^o^)/)

//初始化SAE的缓存
 $mem=memcache_init();
 if($mmc==false)
   echo "mc init failed\n";
 $strUser = $mem->get($fromUsername."key");//获取缓存值
 //接下来修改前面代码case “text” 部分
 case "text":{
                        if(empty($strUser)){
                            if($keyword=="chat"){
                                //设置缓存变量$fromUsername."key"
                                $mem->set($fromUsername."key",$fromUsername."chat",$flag=0,$expire=0);
                                $contentStr="开始和luffy君进行对话,输入#退出聊天";
                            }else if($keyword=="menu"){
								$contentStr="回复menu 查看本菜单\n回复1、2、3、news查看消息\n回复chat和luffy君聊天";
							}else if($keyword==1){
								$contentStr="联系方式:1007511108";
							}else if($keyword==2){
								$contentStr="小道消息正在加载,请稍候……";
							}else if($keyword==3){
								$contentStr="办公地址:大学城中心湖水下5米";
                            }else if($keyword=="news"){
                                $contentStr="";//设字符串为空
                                $this->replyNews1($fromUsername, $toUsername, $time);
                            }else{
                            	$contentStr="回复menu 查看本菜单\n回复1、2、3、news查看消息\n回复chat和luffy君聊天";
                            }
                        }
                        else {
                            if($keyword=="#"){
                            	$contentStr="已经退出聊天,输入chat重新开始聊天";
                                $strUser=$mem->delete($fromUsername."key");
                            }else{
                                //判断是否为同一用户发送聊天请求
                                if($strUser==$fromUsername."chat"){
                                    $apiKey = "你的API key"; 
                                    $apiURL = "http://www.tuling123.com/openapi/api?key=KEY&info=INFO";
                                    // 设置报文头, 构建请求报文 
                                    //header("Content-type: text/html; charset=utf-8"); 
                                    $url = str_replace("INFO", $keyword, str_replace("KEY", $apiKey, $apiURL)); 
    
                                    // 用file_get_contents 以get方式获取内容
                                    //读取json类型数据
                                    $apiStr = file_get_contents($url); 
                                    $apiObj =json_decode($apiStr);
                                    $contentStr = $apiObj->text; 
                                }
                            }
                        }
						break;
					}


6、补充

学习别人的优秀框架:(http://sae.sina.com.cn/?m=appstore&category=2)

其中第一个开源到github,fork之后有空研究。在此感谢作者。


【微信公众平台开发】之二:高级功能开发(基于SAE)