Applicable platforms: window/Linux
Dependent projects: EaglePHP framework
Contains WeChat 5.0 API basic interface, custom menu, and advanced interface, as follows:
1. Receive user messages.
2. Reply to the user.
3. Accept event push.
4. Conversation interface custom menu.
5. Voice recognition.
6. Customer service interface.
7. OAuth2.0 web page authorization.
8. Generate QR code with parameters.
9. Obtain the user’s geographical location.
10. Obtain basic user information.
11. Get the follower list.
12. User grouping.
// Get user basic information
const USER_INFO_URL = '/user/info?';
// Get follower list
const USER_GET_URL = '/user/get?';
// Query group
const GROUPS_GET_URL = '/groups/get?';
// Create group
const GROUPS_CREATE_URL = '/groups/create?';
// Modify group name
const GROUPS_UPDATE_URL = '/groups/update?';
// Move user group
const GROUPS_MEMBERS_UPDATE_URL = '/groups/members/update?';
// Send customer service message
const MESSAGE_CUSTOM_SEND_URL = '/message/custom/send?';
// Create QR code ticket
const QRCODE_CREATE_URL = '/qrcode/create ?';
/**
* Initialization configuration data
* @param array $options
*/
public function __construct($options)
{
$this->token = isset($ options['token']) ? $options['token'] : '';
$this->appid = isset($options['appid']) ? $options['appid'] : '' ;
$this->appsecret = isset($options['appsecret']) ? $options['appsecret'] : '';
}
/**
* Get the incoming message
* When an ordinary WeChat user sends a message to a public account, the WeChat server will POST the XML data packet of the message to the URL filled in by the developer.
*/
public function getRev()
{
$postStr = file_get_contents('php://input');
if($postStr)
{
$this ->_receive = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
//Log::info(var_export($this->_receive, true));
}
return $this;
}
/**
* Get messages sent from WeChat server
*/
public function getRevData()
{
return $this->_receive;
}
/**
* Get the receiver
*/
public function getRevTo()
{
return isset($this->_receive['ToUserName']) ? $this->_receive['ToUserName'] : false;
}
/**
* Get the message sender (an OpenID)
*/
public function getRevFrom()
{
return isset($this->_receive['FromUserName']) ? $this->_receive['FromUserName'] : false;
}
/**
* Get the creation time of the received message (integer)
* /
public function getRevCTime()
{
return isset($this->_receive['CreateTime']) ? $this->_receive['CreateTime'] : false;
}
/**
* Get the received message type (text, image, voice, video, location, link, event)
*/
public function getRevType()
{
return isset($this->_receive['MsgType']) ? $this ->_receive['MsgType'] : false;
}
/**
* Get the received message number
*/
public function getRevId()
{
return isset ($this->_receive['MsgId']) ? $this->_receive['MsgId'] : false;
}
/**
* Get the received message text
* Through the speech recognition interface, the voice sent by the user will also be given the text content recognized by the speech recognition. (You need to apply for the advanced interface permission of the service account)
*/
public function getRevText()
{
if(isset($this->_receive['Content'])) return trim($this->_receive['Content']);
elseif(isset($this->_receive['Recognition'])) return trim($this->_receive['Recognition']);
else return false;
}
/**
* Get and receive picture messages
*/
public function getRevImage()
{
if(isset($this->_receive['PicUrl'])){
return array(
'picUrl' => $this->_receive['PicUrl'], //Picture link
'mediaId' => $this->_receive['MediaId'] // Picture message media id, you can call the multimedia file download interface to pull data.
);
}
return false;
}
/**
* Get and receive voice messages
*/
public function getRevVoice()
{
if(isset($this->_receive['MediaId'])){
return array(
'mediaId' => $this->_receive['MediaId'], //Voice message Media ID, you can call the multimedia file download interface to pull data.
'format' => $this->_receive['Format'] //Voice format, such as amr, speex, etc.
);
}
return false;
}
/**
* Get and receive video messages
*/
public function getRevVideo()
{
if(isset($this->_receive['MediaId'])){
return array(
'mediaId' => $this->_receive['MediaId'], //Video message media id, you can call the multimedia file download interface to pull the data.
'thumbMediaId' = > $this->_receive['ThumbMediaId'] //The media ID of the video message thumbnail, you can call the multimedia file download interface to pull the data
);
}
return false;
}
/**
* Get the user’s geographical location
*/
public function getRevLocation()
{
if(isset($this->_receive['Location_X']) ){
return array(
'locationX' => $this->_receive['Location_X'], //Geographical location dimension
'locationY' => $this->_receive[ 'Location_Y'], //Location longitude
'scale' => $this->_receive['Scale'], //Map zoom size
'label' => $this-> _receive['Label'] //Geographical location information
);
}
//The public account that reports the geographic location interface has been opened. When the user enters the public account session after following it, a pop-up box will pop up to let the user Confirm whether the official account is allowed to use its geographical location.
//The pop-up box only appears once after following it. Users can operate on the official account details page in the future.
elseif(isset($this->_receive['Latitude']))
{
return array(
'latitude' => $this->_receive['Latitude'] , //Latitude of geographical location
'longitude' => $this->_receive['Longitude'], //Longitude of geographical location
'precision' => $this->_receive['Precision '] // Geolocation accuracy
);
}
return false;
}
/**
* Get the receiving link message
*/
public function getRevLink( )
{
if(isset($this->_receive['Title'])){
return array(
'title' => $this->_receive['Title '], //Message title
'description' => $this->_receive['Description'], //Message description
'url' => $this->_receive['Url '] //Message link
);
}
return false;
}
/**
* Get the receiving event type
* Event types such as: subscribe, unsubscribe, click
*/
public function getRevEvent()
{
if(isset($this->_receive['Event']))
{
return array(
'event' => strtolower($this-> _receive['Event']),
'key'=> isset($this->_receive['EventKey']) ? $this->_receive['EventKey'] : ''
) ;
}
return false;
}
/**
* Set reply text message
* @param string $content
* @param string $openid
*/
public function text($content='')
{
$textTpl = "
$this->_reply = sprintf($textTpl,
$ this-& gt; getrevfrom (),
$ this-& gt; getrevto (),
date :: gettimestAmp (),
'Text',
$ Content
); return $this;
}
/**
* Set reply music information
* @param string $title
* @param string $desc
* @param string $musicurl
* @param string $hgmusicurl
*/
public function music($title, $desc, $musicurl, $hgmusicurl='')
{
$textTpl = '
//
$this->_reply = sprintf($textTpl,
$this->getRevFrom(),
$this->getRevTo(),
Date::getTimeStamp(),
'music',
$title,
$desc,
$musicurl,
$hgmusicurl
);
return $this;
}
/**
* Reply to graphic message
* @param array
*/
public function news($data)
{
$count = count($data);
$subText = '';
if($count > 0)
{
foreach($data as $v)
{
$tmpText = '
$subText .= sprintf(
$tmpText, $v['title'],
isset($v['description']) ? $v['description'] : '',
isset($v['picUrl']) ? $v['picUrl'] : '',
isset($v['url']) ? $v['url'] : ''
);
}
}
$textTpl = '
$this->_reply = sprintf(
$textTpl,
$this->getRevFrom(),
$this->getRevTo(),
Date::getTimeStamp(),
$count,
$subText
);
return $this;
}
/**
* Reply message
* @param array $msg
* @param bool $return
*/
public function reply()
{
header('Content-Type:text/xml');
echo $this->_reply;
exit;
}
/**
* Custom menu creation
* @param array menu data
*/
public function createMenu($data)
{
if(!$this->access_token && !$this->checkAuth()) return false;
$result = curlRequest(self::API_URL_PREFIX.self::MENU_CREATE_URL.'access_token='.$this->access_token, $this->jsonEncode($data), 'post');
if($result)
{
$jsonArr = json_decode($result, true);
if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
else return true;
}
return false;
}
/**
* Custom menu query
*/
public function getMenu()
{
if(!$this->access_token && !$this->checkAuth()) return false;
$result = curlRequest(self::API_URL_PREFIX.self::MENU_GET_URL.'access_token='.$this->access_token);
if($result)
{
$jsonArr = json_decode($result, true);
if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
else return $jsonArr;
}
return false;
}
/**
* Custom menu deleted
*/
public function deleteMenu()
{
if(!$this->access_token && !$this->checkAuth()) return false;
$result = curlRequest(self::API_URL_PREFIX.self::MENU_DELETE_URL.'access_token='.$this->access_token);
if($result)
{
$jsonArr = json_decode($result, true);
if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
else return true;
}
return false;
}
/**
* Get basic user information
* @param string $openid The identification of an ordinary user, unique to the current official account
*/
public function getUserInfo($openid)
{
if(!$this->access_token && !$this->checkAuth()) return false;
$result = curlRequest(self::API_URL_PREFIX.self::USER_INFO_URL.'access_token='.$this->access_token.'&openid='.$openid);
if($result)
{
$jsonArr = json_decode($result, true);
if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
else return $jsonArr;
}
return false;
}
/**
* Get the follower list
* @param string $next_openid The first OPENID to pull, if not filled in, it will start pulling from the beginning by default
*/
public function getUserList($next_openid='')
{
if(!$this->access_token && !$this->checkAuth()) return false;
$result = curlRequest(self::API_URL_PREFIX.self::USER_GET_URL.'access_token='.$this->access_token.'&next_openid='.$next_openid);
if($result)
{
$jsonArr = json_decode($result, true);
if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
else return $jsonArr;
}
return false;
}
/**
* Query grouping
*/
public function getGroup()
{
if(!$this->access_token && !$this->checkAuth()) return false;
$result = curlRequest(self::API_URL_PREFIX.self::GROUPS_GET_URL.'access_token='.$this->access_token);
if($result)
{
$jsonArr = json_decode($result, true);
if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
else return $jsonArr;
}
return false;
}
/**
* Create a group
* @param string $name Group name (within 30 characters)
*/
public function createGroup($name)
{
if(!$this->access_token && !$this->checkAuth()) return false;
$data = array('group' => array('name' => $name));
$result = curlRequest(self::API_URL_PREFIX.self::GROUPS_CREATE_URL.'access_token='.$this->access_token, $this->jsonEncode($data), 'post');
if($result)
{
$jsonArr = json_decode($result, true);
if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
else return true;
}
return false;
}
/**
* Modify group name
* @param int $id Group id, assigned by WeChat
* @param string $name Group name (within 30 characters)
*/
public function updateGroup($id, $name)
{
if(!$this->access_token && !$this->checkAuth()) return false;
$data = array('group' => array('id' => $id, 'name' => $name));
$result = curlRequest(self::API_URL_PREFIX.self::GROUPS_UPDATE_URL.'access_token='.$this->access_token, $this->jsonEncode($data), 'post');
if($result)
{
$jsonArr = json_decode($result, true);
if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
else return true;
}
return false;
}
/**
* Mobile user group
*
* @param string $openid User unique identifier
* @param int $to_groupid group id
*/
public function updateGroupMembers($openid, $to_groupid)
{
if(!$this->access_token && !$this->checkAuth()) return false;
$data = array('openid' => $openid, 'to_groupid' => $to_groupid);
$result = curlRequest(self::API_URL_PREFIX.self::GROUPS_MEMBERS_UPDATE_URL.'access_token='.$this->access_token, $this->jsonEncode($data), 'post');
if($result)
{
$jsonArr = json_decode($result, true);
if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
else return true;
}
return false;
}
/**
* 发送客服消息
* 当用户主动发消息给公众号的时候(包括发送信息、点击自定义菜单clike事件、订阅事件、扫描二维码事件、支付成功事件、用户维权),
* 微信将会把消息数据推送给开发者,开发者在一段时间内(目前为24小时)可以调用客服消息接口,通过POST一个JSON数据包来发送消息给普通用户,在24小时内不限制发送次数。
* 此接口主要用于客服等有人工消息处理环节的功能,方便开发者为用户提供更加优质的服务。
*
* @param string $touser ordinary user openid
*/
public function sendCustomMessage($touser, $data, $msgType = 'text')
{
$arr = array();
$arr['touser'] = $touser;
$arr['msgtype'] = $msgType;
switch ($msgType)
{
case ' text': // Send a text message
$arr['text']['content'] = $data;
break;
case 'image': // Send an image message
$arr['image']['media_id'] = $data;
break;
case 'voice': // Send voice message
$arr['voice'][' media_id'] = $data;
break;
case 'video': // Send video message
$arr['video']['media_id'] = $data['media_id' ]; // Media ID of the video sent
$arr['video']['thumb_media_id'] = $data['thumb_media_id']; // Media ID of the video thumbnail
break;
case 'music': // Send music message
$arr['music']['title'] = $data['title'];// Music title
$arr['music' ]['description'] = $data['description'];//Music description
$arr['music']['musicurl'] = $data['musicurl'];//Music link
$arr['music']['hqmusicurl'] = $data['hqmusicurl'];// High-quality music link, the wifi environment prefers to use this link to play music
$arr['music']['thumb_media_id' ] = $data['title'];// Thumbnail media ID
break;
case 'news': // Send graphic message
$arr['news'][ 'articles'] = $data; // title, description, url, picurl
break;
}
if(!$this->access_token && !$this->checkAuth( )) return false;
$result = curlRequest(self::API_URL_PREFIX.self::MESSAGE_CUSTOM_SEND_URL.'access_token='.$this->access_token, $this->jsonEncode($arr), ' post');
if($result)
{
$jsonArr = json_decode($result, true);
if(!$jsonArr || (isset($jsonArr['errcode'] ) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
else return true;
}
return false;
}
/**
* Get access_token
*/
public function checkAuth()
{
// Get access_token from cache
$cache_flag = 'weixin_access_token';
$access_token = cache($cache_flag);
if($access_token)
{
$this->access_token = $access_token;
return true;
}
// Request the WeChat server to obtain access_token
$result = curlRequest(self::API_URL_PREFIX.self::AUTH_URL.'appid='.$this->appid.'&secret='.$ this->appsecret);
if($result)
{
$jsonArr = json_decode($result, true);
if(!$jsonArr || (isset($jsonArr[' errcode']) && $jsonArr['errcode'] > 0))
{
$this->error($jsonArr);
}
else
{
$this->access_token = $jsonArr['access_token'];
$expire = isset($jsonArr['expires_in']) ? intval($jsonArr['expires_in'])-100 : 3600;
// Save access_token to cache
cache($cache_flag, $this->access_token, $expire, Cache::FILE);
return true;
}
}
return false;
}
/**
* WeChat oauth login-> Step 1: The user agrees to the authorization and obtains the code
* Application authorization scope, snsapi_base (not The authorization page pops up, jumps directly, you can only get the user's openid),
* snsapi_userinfo (the authorization page pops up, you can get the nickname, gender, and location through openid. Moreover, even if you are not following the user, you can obtain their information as long as the user authorizes it)
* Open the link directly on WeChat, you do not need to fill in this parameter.When doing page 302 redirection, you must bring this parameter
*
* @param string $redirect_uri The callback link address for redirection after authorization
* @param $scope Application authorization scope 0 is snsapi_base, 1 snsapi_userinfo
* @param string $state will bring the state parameter after redirection, developers can fill in any parameter value
*/
public function redirectGetOauthCode($redirect_uri, $scope=0, $state= '')
{
$scope = ($scope == 0) ? 'snsapi_base' : 'snsapi_userinfo';
$url = self::CONNECT_OAUTH_AUTHORIZE_URL.'appid='.$this-> appid.'&redirect_uri='.urlencode($redirect_uri).'&response_type=code&scope='.$scope.'&state='.$state.'#wechat_redirect';
redirect($url);
}
/**
* WeChat oauth login-> Step 2: Exchange webpage authorization access_token through code
*
* @param string $code
*/
public function getSnsAccessToken($code)
{
$result = curlRequest(self::SNS_OAUTH_ACCESS_TOKEN_URL.'appid='.$this ->appid.'&secret='.$this->appsecret.'&code='.$code.'&grant_type=authorization_code');
if($result)
{
$jsonArr = json_decode($result, true);
if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($ jsonArr);
else return $jsonArr;
}
return false;
}
/**
* WeChat oauth login-> Step 3: Refresh access_token (if necessary)
* Since access_token has a short validity period, when access_token times out, you can use refresh_token to refresh,
* refresh_token has a longer validity period Long validity period (7 days, 30 days, 60 days, 90 days), when refresh_token expires, the user needs to re-authorize.
*
* @param string $refresh_token Fill in the refresh_token parameter obtained through access_token
*/
public function referhToken($refresh_token)
{
$result = curlRequest(self::SNS_OAUTH_REFRESH_TOKEN_URL.'appid='.$this->appid.'&grant_type=refresh_token&refresh_token='.$refresh_token);
if( $result)
{
$jsonArr = json_decode($result, true);
if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
else return $jsonArr;
}
return false;
}
/**
* WeChat oauth login-> Step 4: Pull user information (need to have scope snsapi_userinfo)
* If the web page authorization scope is snsapi_userinfo, then developers can pull user information through access_token and openid at this time .
*
* @param string $access_token Web page authorization interface call certificate, note: this access_token is different from the basic supported access_token
* @param string $openid The unique identifier of the user
*/
public function getSnsUserInfo($access_token, $openid)
{
$result = curlRequest(self::SNS_USERINFO_URL.'access_token='.$access_token.'&openid=' .$openid);
if($result)
{
$jsonArr = json_decode($result, true);
if(!$jsonArr || (isset($jsonArr['errcode' ]) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
else return $jsonArr;
}
return false;
}
/**
* Create a QR code ticket
* Each time you create a QR code ticket, you need to provide a parameter (scene_id) set by the developer. The temporary The process of creating QR code tickets and permanent QR codes.
*
* @param int $scene_id Scene value ID, a 32-bit integer for temporary QR code, the maximum value for permanent QR code is 1000
* @param int $type QR code type , 0 is temporary, 1 is permanent
* @param int $expire The validity time of the QR code, in seconds. The maximum number does not exceed 1800.
*/
public function createQrcode($scene_id, $type=0, $expire=1800)
{
if(!$this->access_token && !$this->checkAuth( )) return false;
$data = array();
$data['action_info'] = array('scene' => array('scene_id' => $scene_id));
$data['action_name'] = ($type == 0 ? 'QR_SCENE' : 'QR_LIMIT_SCENE');
if($type == 0) $data['expire_seconds'] = $expire;
$result = curlRequest(self::API_URL_PREFIX.self::QRCODE_CREATE_URL.'access_token='.$this->access_token, $this->jsonEncode($data), 'post');
if($result)
{
$jsonArr = json_decode($result, true);
if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr[' errcode'] > 0)) $this->error($jsonArr);
else return $jsonArr;
}
return false;
}
/**
* Exchange tickets for QR codes
* After obtaining a QR code ticket, developers can exchange the ticket for a QR code image. Please note that this interface can be called without logging in.
* Reminder: Remember to UrlEncode TICKET
* When the ticket is correct, the http return code is 200, which is a picture and can be displayed or downloaded directly.
* Returns HTTP error code 404 in error situations (such as illegal ticket).
*
* @param string $ticket
*/
public function getQrcodeUrl($ticket)
{
return self::SHOW_QRCODE_URL.'ticket='.urlencode($ticket);
}
/**
* Record the error log generated by the interface
*/
public function error($data)
{
$this->errCode = $data['errcode'];
$this->errMsg = $data['errmsg'];
Log::info('WEIXIN API errcode:['.$this->errCode.'] errmsg:['.$this->errMsg.']');
}
/**
* Convert Chinese in the array into json data
* @param array $arr
*/
public function jsonEncode($arr) {
$parts = array ();
$is_list = false;
//Find out if the given array is a numerical array
$keys = array_keys ( $arr );
$max_length = count ( $arr ) - 1;
if (($keys [0] === 0) && ($keys [$max_length] === $max_length )) { //See if the first key is 0 and last key is length - 1
$is_list = true;
for($i = 0; $i < count ( $keys ); $i ++) { //See if each key correspondes to its position
if ($i != $keys [$i]) { //A key fails at position check.
$is_list = false; //It is an associative array.
break;
}
}
}
foreach ( $arr as $key => $value ) {
if (is_array ( $value )) { //Custom handling for arrays
if ($is_list)
$parts [] = $this->jsonEncode ( $value ); /* :RECURSION: */
else
$parts [] = '"' . $key . '":' . $this->jsonEncode ( $value ); /* :RECURSION: */
} else {
$str = '';
if (! $is_list)
$str = '"' . $key . '":';
//Custom handling for multiple data types
if (is_numeric ( $value ) && $value<2000000000)
$str .= $value; //Numbers
elseif ($value === false)
$str .= 'false'; //The booleans
elseif ($value === true)
$str .= 'true';
else
$str .= '"' . addslashes ( $value ) . '"'; //All other things
// :TODO: Is there any more datatype we should be in the lookout for? (Object?)
$parts [] = $str;
}
}
$json = implode ( ',', $parts );
if ($is_list)
return '[' . $json . ']'; //Return numerical JSON
return '{' . $json . '}'; //Return associative JSON
}
<>/**
* Verify signature
*/
Public Function CheckSignature ()
{
$ Signature = httprequest :: Signature '); quest: :getGet('timestamp');
$nonce = HttpRequest::getGet('nonce');
$token = $this->token;
$tmpArr = array($token , $timestamp, $nonce);
sort($tmpArr);
$tmpStr = implode($tmpArr);
$tmpStr = sha1($tmpStr);
return ($ tmpStr == $signature ? true : false);
}
/**
* Verify whether the token is valid
*/
public function valid()
{
if($ this->checkSignature()) exit(HttpRequest::getGet('echostr'));
}
}
http://www.bkjia.com/PHPjc/676871.html