PHP 微信平台消息接收与发送

微信平台消息推送到开发者系统流程如下(官网描述):

当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。 微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次 关于重试的消息排重,推荐使用msgid排重。 假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。

流程如下: 用户发起消息到微信平台—>微信平台推送消息到开发者服务器—>开发者处理消息做出响应(该响应可以为各种类型的消息)—>微信将该消息传递给用户 处理的时候必须开启开发者模式,这里有个认证问题,我曾遇到的问题如下(顺便补充一下微信的文档)。 - 微信只提供了一个接口,我并没有发现单独设置开发者服务器接收消息的URL。

  • 有些IP的机器根本接收不到微信发出的验证请求。

答案如下: 1. 微信接口只需要一个URL就可以进行操作了。这点有一些蛋疼的地方,最初的认证和使用的接口用的是一个URL,而文档当中并没有描述清楚,害得我翻遍文档都没有找到答案,最终通过读微信提供的官方认证代码里面找到了我所需要的答案。当你进行认证的时候需要用认证的逻辑,认证完毕之后,你需要消灭掉这些认证的逻辑,写自己的业务代码。

  1. 有些IP被某些网络运营商禁掉了,而我看了一下成功接受请求的机器的微信服务器的IP都是上海电信的,而接受不到请求的机器用上海电信是ping不通的。具体可以查阅一下cnzz上的ping小工具。而如果你的开发者服务器架设在了阿里云上,则能接受到请求,如果一直报499错误,你需要把你的域名备案,这个是阿里云的行为。

简单的说开发者需要做的工作是:利用在微信公共账户中填写的URL,编写一个能反馈微信转发的用户信息的应用。 微信发给开发者服务器的消息是xml的,所以需要用$GLOBALS [“HTTP_RAW_POST_DATA”]这种方式来接受。粗略浏览一下文档就会发现,所有的消息/事件都是通过XML进行传输的,而传输数据类型取决其中的一个元素内容。 所有的XML都会包含四个固定元素 FromUserName|ToUserName|CreateTime|MsgType 。而其他元素取决于MsgType的内容,说到这里如果用其他语言肯定第一个联想到的就是简单工厂了。利用传输过来的type不同来匹配不同的对象。PHP有独有的特性来处理,我们先看看消息类型。 - text

  • image
  • voice
  • video
  • location
  • link

按章上述消息类型的不同建立不同名称的子类,将共有的输入,输出,交给父类来完成。代码如下 接口

<?php
/**
 * MSG 接口
 * @author Abel
 * email:abel.zhou@hotmail.com
 * 2014-2-7
 * UTF-8
 */
interface MSGInterface{

	/**
	 * 处理方法
	 */
	function progress();
}

[/codesyntax] 抽象类 [codesyntax lang=”php”] ``\` <?php /*\*

  • MSG抽象类
  • @author Abel
  • email:abel.zhou@hotmail.com
  • 2014-2-7
  • UTF-8 */ abstract class MSGAbstract implements MSGInterface { ``` /**
  • 传入的操作类
  • @var unknow */ protected $xml_msg = null;

/**

  • 返回的xml字符串
  • @var String */ protected $return_xml = null;

/**

  • MSG组装类
  • @var MSGSend */ protected $MSGSend = null;

/**

  • 父类构造函数
  • @param object $simple_xml */ function __construct($simple_xml) { $this->xml_msg = $simple_xml; $toUserName = $this->xml_msg->FromUserName; $fromUserName = $this->xml_msg->ToUserName; $this->MSGSend = new MSGSend($toUserName, $fromUserName); }

/**

  • 获得传入的对象
  • @return SimpleXMLElement */ public function getSimpleXml(){ return $this->xml_msg; }

/**

  • 获得组装好的字符串
  • @return string */ public function getReturnXml(){ return $this->return_xml; }
    }
    

[/codesyntax] 子类 [codesyntax lang=”php”]

\<?php
/\*\\\*
 * 文本信息处理类
 \* 
 * @author Abel
 * email:abel.zhou@hotmail.com
 * 2014-2-7
 * UTF-8
 \*/
class TextMessage extends MSGAbstract{

function __construct($simple_xml){ parent::__construct($simple_xml); }

/**

  • (non-PHPdoc)
  • @see MSGInterface::progress() */ public function progress(){ $keyword = trim ( $this->xml_msg->Content ); if (empty ( $keyword )) { echo ‘Input something…’; } switch ($keyword){ case ‘音乐’: break; case ‘视频’: break; case ‘’: break; case ‘’: break; case ‘’: break; default: $this->return_xml = $this->MSGSend->getTextMsg(‘Hello world :’.time()); }

}

}

[/codesyntax] 除了这些类之外还需要有一个返回消息的模板类,用来处理消息返回的xml: [codesyntax lang=”php”]

\<?php
/\*\\\*
 * @author Abel
 * email:abel.zhou@hotmail.com
 * 2014-2-8
 * UTF-8
 \*/
class MSGSend {

/**

  • 文本模板 *
  • @var string */ public static $TEXT_MSG = “ <![CDATA[%s]]> <![CDATA[%s]]> %s <![CDATA[text]]> <![CDATA[%s]]> 0 ”;

/**

  • 图片模板 *
  • @var string */ public static $IMAGE_MSG = “ <![CDATA[%s]]> <![CDATA[%s]]> %s <![CDATA[image]]> <![CDATA[%s]]> ”;

/**

  • 语音模板 *
  • @var string */ public static $VOICE_MSG = “ <![CDATA[%s]]> <![CDATA[%s]]> %s <![CDATA[voice]]> <![CDATA[%s]]> ”;

/**

  • 视频模板 *
  • @var string */ public static $VIDEO_MSG = “ <![CDATA[%s]]> <![CDATA[%s]]> %s <![CDATA[video]]> ”;

/**

  • 音乐模板 *
  • @var string */ public static $MUSIC_MSG = “ <![CDATA[%s]]> <![CDATA[%s]]> %s <![CDATA[music]]> <![CDATA[%s]]> <![CDATA[%s]]> <![CDATA[%s]]> <![CDATA[%s]]> <![CDATA[%s]]> ”;

/**

  • 图文模板 *
  • @var string */ public static $NEWS_MSG = “ <![CDATA[%s]]> <![CDATA[%s]]> %s <![CDATA[news]]> 1 <![CDATA[%s]]> <![CDATA[%s]]> <![CDATA[%s]]> <![CDATA[%s]]> “;

/**

  • 收件人 *
  • @var string */ private $toUserName = ‘’;

/**

  • 发送者 *
  • @var string */ private $fromUserName = ‘’;

/**

  • 创建时间 *
  • @var int */ private $createTime = 0;

/**

  • 构造 *
  • @param string $toUserName
  • @param string $fromUserName */ public function __construct($toUserName, $fromUserName) { $this->fromUserName = $fromUserName; $this->toUserName = $toUserName; $this->createTime = time (); }

/**

  • 获得返回文本消息 *
  • @param string $content
  • @return string */ public function getTextMsg($content) { return sprintf ( self::$TEXT_MSG, $this->toUserName, $this->fromUserName, $this->createTime, $content ); }

/**

  • 获得返回图片消息 *
  • @param string $mediaID */ public function getImageMsg($mediaID) { return sprintf ( self::$IMAGE_MSG, $this->toUserName, $this->fromUserName, $this->createTime, $mediaID ); }

/**

  • 获得返回语音消息 *
  • @param string $mediaID */ public function getVoiceMsg($mediaID) { return sprintf ( self::$VOICE_MSG, $this->toUserName, $this->fromUserName, $this->createTime, $mediaID ); }

/**

  • 获得返回视频消息
  • @param string $mediaID
  • @param string $title
  • @param string $desc
  • @return string */ public function getVideoMsg($mediaID, $title, $desc) { return sprintf ( self::$VIDEO_MSG, $this->toUserName, $this->fromUserName, $this->createTime, $mediaID, $title, $desc ); }

/**

  • 获得返回音乐消息
  • @param string $title
  • @param string $desc
  • @param string $musicUrl
  • @param string $hqMusicUrl
  • @param string $thumbMediaId
  • @return string */ public function getMusicMsg($title, $desc, $musicUrl, $hqMusicUrl, $thumbMediaId) { return sprintf ( self::$MUSIC_MSG, $this->toUserName, $this->fromUserName, $this->createTime, $title, $desc, $musicUrl, $hqMusicUrl, $thumbMediaId ); }

/**

  • 获得返回图文消息
  • @param string $title
  • @param string $desc
  • @param string $picUrl
  • @param string $url
  • @return string */ public function getNewsMsg($title, $desc, $picUrl, $url) { return sprintf ( self::$NEWS_MSG, $this->toUserName, $this->fromUserName, $this->createTime, $title, $desc, $picUrl, $url ); }
    }
    

[/codesyntax] 使用方法也很简单,利用PHP的特性,在你的controller里写下如下几句话即可。 [codesyntax lang=”php”]

// get post data, May be due to the different environments			
$postStr = $GLOBALS ["HTTP_RAW_POST_DATA"];

// extract post data
if (! empty ( $postStr )) {
	$postObj = simplexml_load_string ( $postStr, 'SimpleXMLElement', LIBXML_NOCDATA );
	$msgType = $postObj->MsgType;

	//如不存在需要处理的类型
	if(!in_array($msgType, $this->messageType)){
		echo '';
		exit;
	}
	//创建类型
	$className = ucfirst($msgType).'Message';

	$msg = new $className($postObj);
	$msg->progress();
	echo $msg->getReturnXml();exit;
          } ``` \`\`\\\`

[/codesyntax]

Categories:

Updated: