git wechat.class.php,wechat-php-sdk/qywechat.class.php at master · gitye/wechat-php-sdk · GitHub

养研
2023-12-01

/**

*微信公众平台企业号PHP-SDK, 官方API类库

* @author binsee

* @link https://github.com/binsee/wechat-php-sdk

* @version 1.0

* usage:

* $options = array(

*'token'=>'tokenaccesskey', //填写应用接口的Token

*'encodingaeskey'=>'encodingaeskey', //填写加密用的EncodingAESKey

*'appid'=>'wxdk1234567890', //填写高级调用功能的app id

*'appsecret'=>'xxxxxxxxxxxxxxxxxxx', //填写高级调用功能的密钥

*'agentid'=>'1', //应用的id

*'debug'=>false, //调试开关

*'_logcallback'=>'logg', //调试输出方法,需要有一个string类型的参数

*);

*

*/

class Wechat

{

const MSGTYPE_TEXT = 'text';

const MSGTYPE_IMAGE = 'image';

const MSGTYPE_LOCATION = 'location';

const MSGTYPE_LINK = 'link'; //暂不支持

const MSGTYPE_EVENT = 'event';

const MSGTYPE_MUSIC = 'music'; //暂不支持

const MSGTYPE_NEWS = 'news';

const MSGTYPE_VOICE = 'voice';

const MSGTYPE_VIDEO = 'video';

const API_URL_PREFIX = 'https://qyapi.weixin.qq.com/cgi-bin';

const USER_CREATE_URL = '/user/create?';

const USER_UPDATE_URL = '/user/update?';

const USER_DELETE_URL = '/user/delete?';

const USER_GET_URL = '/user/get?';

const USER_LIST_URL = '/user/simplelist?';

const USER_GETINFO_URL = '/user/getuserinfo?';

const DEPARTMENT_CREATE_URL = '/department/create?';

const DEPARTMENT_UPDATE_URL = '/department/update?';

const DEPARTMENT_DELETE_URL = '/department/delete?';

const DEPARTMENT_MOVE_URL = '/department/move?';

const DEPARTMENT_LIST_URL = '/department/list?';

const TAG_CREATE_URL = '/tag/create?';

const TAG_UPDATE_URL = '/tag/update?';

const TAG_DELETE_URL = '/tag/delete?';

const TAG_GET_URL = '/tag/get?';

const TAG_ADDUSER_URL = '/tag/addtagusers?';

const TAG_DELUSER_URL = '/tag/deltagusers?';

const TAG_LIST_URL = '/tag/list?';

const MEDIA_UPLOAD_URL = '/media/upload?';

const MEDIA_GET_URL = '/media/get?';

const AUTHSUCC_URL = '/user/authsucc?';

const MASS_SEND_URL = '/message/send?';

const MENU_CREATE_URL = '/menu/create?';

const MENU_GET_URL = '/menu/get?';

const MENU_DELETE_URL = '/menu/delete?';

const TOKEN_GET_URL = '/gettoken?';

const OAUTH_PREFIX = 'https://open.weixin.qq.com/connect/oauth2';

const OAUTH_AUTHORIZE_URL = '/authorize?';

private $token;

private $encodingAesKey;

private $appid; //也就是企业号的CorpID

private $appsecret;

private $access_token;

private $agentid; //应用id AgentID

private $postxml;

private $agentidxml; //接收的应用id AgentID

private $_msg;

private $_receive;

private $_sendmsg; //主动发送消息的内容

private $_text_filter = true;

public $debug = false;

public $errCode = 40001;

public $errMsg = "no access";

private $_logcallback;

public function __construct($options)

{

$this->token = isset($options['token'])?$options['token']:'';

$this->encodingAesKey = isset($options['encodingaeskey'])?$options['encodingaeskey']:'';

$this->appid = isset($options['appid'])?$options['appid']:'';

$this->appsecret = isset($options['appsecret'])?$options['appsecret']:'';

$this->agentid = isset($options['agentid'])?$options['agentid']:'';

$this->debug = isset($options['debug'])?$options['debug']:false;

$this->_logcallback = isset($options['logcallback'])?$options['logcallback']:false;

}

private function log($log){

if ($this->debug && function_exists($this->_logcallback)) {

if (is_array($log)) $log = print_r($log,true);

return call_user_func($this->_logcallback,$log);

}

}

/**

* 数据XML编码

* @param mixed $data 数据

* @return string

*/

public static function data_to_xml($data) {

$xml = '';

foreach ($data as $key => $val) {

is_numeric($key) && $key = "item id=\"$key\"";

$xml .= "";

$xml .= ( is_array($val) || is_object($val)) ? self::data_to_xml($val) : self::xmlSafeStr($val);

list($key, ) = explode(' ', $key);

$xml .= "$key>";

}

return $xml;

}

public static function xmlSafeStr($str)

{

return '';

}

/**

* XML编码

* @param mixed $data 数据

* @param string $root 根节点名

* @param string $item 数字索引的子节点名

* @param string $attr 根节点属性

* @param string $id 数字索引子节点key转换的属性名

* @param string $encoding 数据编码

* @return string

*/

public function xml_encode($data, $root='xml', $item='item', $attr='', $id='id', $encoding='utf-8') {

if(is_array($attr)){

$_attr = array();

foreach ($attr as $key => $value) {

$_attr[] = "{$key}=\"{$value}\"";

}

$attr = implode(' ', $_attr);

}

$attr = trim($attr);

$attr = empty($attr) ? '' : " {$attr}";

$xml = "";

$xml .= self::data_to_xml($data, $item, $id);

$xml .= "{$root}>";

return $xml;

}

/**

* 微信api不支持中文转义的json结构

* @param array $arr

*/

static function json_encode($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 [] = self::json_encode ( $value ); /* :RECURSION: */

else

$parts [] = '"' . $key . '":' . self::json_encode ( $value ); /* :RECURSION: */

} else {

$str = '';

if (! $is_list)

$str = '"' . $key . '":';

//Custom handling for multiple data types

if (!is_string ( $value ) && 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

}

/**

* 过滤文字回复\r\n换行符

* @param string $text

* @return string|mixed

*/

private function _auto_text_filter($text) {

if (!$this->_text_filter) return $text;

return str_replace("\r\n", "\n", $text);

}

/**

* GET 请求

* @param string $url

*/

private function http_get($url){

$oCurl = curl_init();

if(stripos($url,"https://")!==FALSE){

curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);

curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, FALSE);

curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1

}

curl_setopt($oCurl, CURLOPT_URL, $url);

curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 );

$sContent = curl_exec($oCurl);

$aStatus = curl_getinfo($oCurl);

curl_close($oCurl);

if(intval($aStatus["http_code"])==200){

return $sContent;

}else{

return false;

}

}

/**

* POST 请求

* @param string $url

* @param array $param

* @param boolean $post_file 是否文件上传

* @return string content

*/

private function http_post($url,$param,$post_file=false){

$oCurl = curl_init();

if(stripos($url,"https://")!==FALSE){

curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);

curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false);

curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1

}

if (is_string($param) || $post_file) {

$strPOST = $param;

} else {

$aPOST = array();

foreach($param as $key=>$val){

$aPOST[] = $key."=".urlencode($val);

}

$strPOST = join("&", $aPOST);

}

curl_setopt($oCurl, CURLOPT_URL, $url);

curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 );

curl_setopt($oCurl, CURLOPT_POST,true);

curl_setopt($oCurl, CURLOPT_POSTFIELDS,$strPOST);

$sContent = curl_exec($oCurl);

$aStatus = curl_getinfo($oCurl);

curl_close($oCurl);

if(intval($aStatus["http_code"])==200){

return $sContent;

}else{

return false;

}

}

/**

* For weixin server validation

*/

private function checkSignature($str)

{

$signature = isset($_GET["msg_signature"])?$_GET["msg_signature"]:'';

$timestamp = isset($_GET["timestamp"])?$_GET["timestamp"]:'';

$nonce = isset($_GET["nonce"])?$_GET["nonce"]:'';

$tmpArr = array($str,$this->token, $timestamp, $nonce);//比普通公众平台多了一个加密的密文

sort($tmpArr, SORT_STRING);

$tmpStr = implode($tmpArr);

$shaStr = sha1($tmpStr);

if( $shaStr == $signature ){

return true;

}else{

return false;

}

}

/**

* 微信验证,包括post来的xml解密

* @param bool $return 是否返回

*/

public function valid($return=false)

{

$encryptStr="";

if ($_SERVER['REQUEST_METHOD'] == "POST") {

$postStr = file_get_contents("php://input");

$array = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);

$this->log($postStr);

if (isset($array['Encrypt'])) {

$encryptStr = $array['Encrypt'];

$this->agentidxml = isset($array['AgentID']) ? $array['AgentID']: '';

}

} else {

$encryptStr = isset($_GET["echostr"]) ? $_GET["echostr"]: '';

}

if ($encryptStr) {

$ret=$this->checkSignature($encryptStr);

}

if (!isset($ret) || !$ret) {

if (!$return) {

die('no access');

} else {

return false;

}

}

$pc = new Prpcrypt($this->encodingAesKey);

$array = $pc->decrypt($encryptStr,$this->appid);

if (!isset($array[0]) || ($array[0] != 0)) {

if (!$return) {

die('解密失败!');

} else {

return false;

}

}

if ($_SERVER['REQUEST_METHOD'] == "POST") {

$this->postxml = $array[1];

//$this->log($array[1]);

return ($this->postxml!="");

} else {

$echoStr = $array[1];

if ($return) {

return $echoStr;

} else {

die($echoStr);

}

}

return false;

}

/**

* 获取微信服务器发来的信息

*/

public function getRev()

{

if ($this->_receive) return $this;

$postStr = $this->postxml;

$this->log($postStr);

if (!empty($postStr)) {

$this->_receive = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);

if (!isset($this->_receive['AgentID'])) {

$this->_receive['AgentID']=$this->agentidxml; //当前接收消息的应用id

}

}

return $this;

}

/**

* 获取微信服务器发来的信息

*/

public function getRevData()

{

return $this->_receive;

}

/**

* 获取微信服务器发来的原始加密信息

*/

public function getRevPostXml()

{

return $this->postxml;

}

/**

* 获取消息发送者

*/

public function getRevFrom() {

if (isset($this->_receive['FromUserName']))

return $this->_receive['FromUserName'];

else

return false;

}

/**

* 获取消息接受者

*/

public function getRevTo() {

if (isset($this->_receive['ToUserName']))

return $this->_receive['ToUserName'];

else

return false;

}

/**

* 获取接收消息的应用id

*/

public function getRevAgentID() {

if (isset($this->_receive['AgentID']))

return $this->_receive['AgentID'];

else

return false;

}

/**

* 获取接收消息的类型

*/

public function getRevType() {

if (isset($this->_receive['MsgType']))

return $this->_receive['MsgType'];

else

return false;

}

/**

* 获取消息ID

*/

public function getRevID() {

if (isset($this->_receive['MsgId']))

return $this->_receive['MsgId'];

else

return false;

}

/**

* 获取消息发送时间

*/

public function getRevCtime() {

if (isset($this->_receive['CreateTime']))

return $this->_receive['CreateTime'];

else

return false;

}

/**

* 获取接收消息内容正文

*/

public function getRevContent(){

if (isset($this->_receive['Content']))

return $this->_receive['Content'];

else

return false;

}

/**

* 获取接收消息图片

*/

public function getRevPic(){

if (isset($this->_receive['PicUrl']))

return array(

'mediaid'=>$this->_receive['MediaId'],

'picurl'=>(string)$this->_receive['PicUrl'], //防止picurl为空导致解析出错

);

else

return false;

}

/**

* 获取接收地理位置

*/

public function getRevGeo(){

if (isset($this->_receive['Location_X'])){

return array(

'x'=>$this->_receive['Location_X'],

'y'=>$this->_receive['Location_Y'],

'scale'=>(string)$this->_receive['Scale'],

'label'=>(string)$this->_receive['Label']

);

} else

return false;

}

/**

* 获取上报地理位置事件

*/

public function getRevEventGeo(){

if (isset($this->_receive['Latitude'])){

return array(

'x'=>$this->_receive['Latitude'],

'y'=>$this->_receive['Longitude'],

'precision'=>$this->_receive['Precision'],

);

} else

return false;

}

/**

* 获取接收事件推送

*/

public function getRevEvent(){

if (isset($this->_receive['Event'])){

$array['event'] = $this->_receive['Event'];

}

if (isset($this->_receive['EventKey'])){

$array['key'] = $this->_receive['EventKey'];

}

if (isset($array) && count($array) > 0) {

return $array;

} else {

return false;

}

}

/**

* 获取自定义菜单的扫码推事件信息

*

* 事件类型为以下两种时则调用此方法有效

* Event 事件类型,scancode_push

* Event 事件类型,scancode_waitmsg

*

* @return: array | false

* array (

* 'ScanType'=>'qrcode',

* 'ScanResult'=>'123123'

* )

*/

public function getRevScanInfo(){

if (isset($this->_receive['ScanCodeInfo'])){

if (!is_array($this->_receive['SendPicsInfo'])) {

$array=(array)$this->_receive['ScanCodeInfo'];

$this->_receive['ScanCodeInfo']=$array;

}else {

$array=$this->_receive['ScanCodeInfo'];

}

}

if (isset($array) && count($array) > 0) {

return $array;

} else {

return false;

}

}

/**

* 获取自定义菜单的图片发送事件信息

*

* 事件类型为以下三种时则调用此方法有效

* Event 事件类型,pic_sysphoto 弹出系统拍照发图的事件推送

* Event 事件类型,pic_photo_or_album 弹出拍照或者相册发图的事件推送

* Event 事件类型,pic_weixin 弹出微信相册发图器的事件推送

*

* @return: array | false

* array (

* 'Count' => '2',

* 'PicList' =>array (

* 'item' =>array (

* 0 =>array ('PicMd5Sum' => 'aaae42617cf2a14342d96005af53624c'),

* 1 =>array ('PicMd5Sum' => '149bd39e296860a2adc2f1bb81616ff8'),

* ),

* ),

* )

*

*/

public function getRevSendPicsInfo(){

if (isset($this->_receive['SendPicsInfo'])){

if (!is_array($this->_receive['SendPicsInfo'])) {

$array=(array)$this->_receive['SendPicsInfo'];

if (isset($array['PicList'])){

$array['PicList']=(array)$array['PicList'];

$item=$array['PicList']['item'];

$array['PicList']['item']=array();

foreach ( $item as $key => $value ){

$array['PicList']['item'][$key]=(array)$value;

}

}

$this->_receive['SendPicsInfo']=$array;

} else {

$array=$this->_receive['SendPicsInfo'];

}

}

if (isset($array) && count($array) > 0) {

return $array;

} else {

return false;

}

}

/**

* 获取自定义菜单的地理位置选择器事件推送

*

* 事件类型为以下时则可以调用此方法有效

* Event 事件类型,location_select 弹出系统拍照发图的事件推送

*

* @return: array | false

* array (

* 'Location_X' => '33.731655000061',

* 'Location_Y' => '113.29955200008047',

* 'Scale' => '16',

* 'Label' => '某某市某某区某某路',

* 'Poiname' => '',

* )

*

*/

public function getRevSendGeoInfo(){

if (isset($this->_receive['SendLocationInfo'])){

if (!is_array($this->_receive['SendLocationInfo'])) {

$array=(array)$this->_receive['SendLocationInfo'];

if (empty($array['Poiname'])) {

$array['Poiname']="";

}

if (empty($array['Label'])) {

$array['Label']="";

}

$this->_receive['SendLocationInfo']=$array;

} else {

$array=$this->_receive['SendLocationInfo'];

}

}

if (isset($array) && count($array) > 0) {

return $array;

} else {

return false;

}

}

/**

* 获取接收语音推送

*/

public function getRevVoice(){

if (isset($this->_receive['MediaId'])){

return array(

'mediaid'=>$this->_receive['MediaId'],

'format'=>$this->_receive['Format'],

);

} else

return false;

}

/**

* 获取接收视频推送

*/

public function getRevVideo(){

if (isset($this->_receive['MediaId'])){

return array(

'mediaid'=>$this->_receive['MediaId'],

'thumbmediaid'=>$this->_receive['ThumbMediaId']

);

} else

return false;

}

/**

* 设置回复消息

* Example: $obj->text('hello')->reply();

* @param string $text

*/

public function text($text='')

{

$msg = array(

'ToUserName' => $this->getRevFrom(),

'FromUserName'=>$this->getRevTo(),

'MsgType'=>self::MSGTYPE_TEXT,

'Content'=>$this->_auto_text_filter($text),

'CreateTime'=>time(),

);

$this->Message($msg);

return $this;

}

/**

* 设置回复消息

* Example: $obj->image('media_id')->reply();

* @param string $mediaid

*/

public function image($mediaid='')

{

$msg = array(

'ToUserName' => $this->getRevFrom(),

'FromUserName'=>$this->getRevTo(),

'MsgType'=>self::MSGTYPE_IMAGE,

'Image'=>array('MediaId'=>$mediaid),

'CreateTime'=>time(),

);

$this->Message($msg);

return $this;

}

/**

* 设置回复消息

* Example: $obj->voice('media_id')->reply();

* @param string $mediaid

*/

public function voice($mediaid='')

{

$msg = array(

'ToUserName' => $this->getRevFrom(),

'FromUserName'=>$this->getRevTo(),

'MsgType'=>self::MSGTYPE_IMAGE,

'Voice'=>array('MediaId'=>$mediaid),

'CreateTime'=>time(),

);

$this->Message($msg);

return $this;

}

/**

* 设置回复消息

* Example: $obj->video('media_id','title','description')->reply();

* @param string $mediaid

*/

public function video($mediaid='',$title='',$description='')

{

$msg = array(

'ToUserName' => $this->getRevFrom(),

'FromUserName'=>$this->getRevTo(),

'MsgType'=>self::MSGTYPE_IMAGE,

'Video'=>array(

'MediaId'=>$mediaid,

'Title'=>$title,

'Description'=>$description

),

'CreateTime'=>time(),

);

$this->Message($msg);

return $this;

}

/**

* 设置回复图文

* @param array $newsData

* 数组结构:

* array(

* "0"=>array(

* 'Title'=>'msg title',

* 'Description'=>'summary text',

* 'PicUrl'=>'http://www.domain.com/1.jpg',

* 'Url'=>'http://www.domain.com/1.html'

* ),

* "1"=>....

* )

*/

public function news($newsData=array())

{

$count = count($newsData);

$msg = array(

'ToUserName' => $this->getRevFrom(),

'FromUserName'=>$this->getRevTo(),

'MsgType'=>self::MSGTYPE_NEWS,

'CreateTime'=>time(),

'ArticleCount'=>$count,

'Articles'=>$newsData,

);

$this->Message($msg);

return $this;

}

/**

* 设置发送消息

* @param array $msg 消息数组

* @param bool $append 是否在原消息数组追加

*/

public function Message($msg = '',$append = false){

if (is_null($msg)) {

$this->_msg =array();

}elseif (is_array($msg)) {

if ($append)

$this->_msg = array_merge($this->_msg,$msg);

else

$this->_msg = $msg;

return $this->_msg;

} else {

return $this->_msg;

}

}

/**

*

* 回复微信服务器, 此函数支持链式操作

* Example: $this->text('msg tips')->reply();

* @param string $msg 要发送的信息, 默认取$this->_msg

* @param bool $return 是否返回信息而不抛出到浏览器 默认:否

*/

public function reply($msg=array(),$return = false)

{

if (empty($msg))

$msg = $this->_msg;

$xmldata= $this->xml_encode($msg);

$this->log($xmldata);

$pc = new Prpcrypt($this->encodingAesKey);

$array = $pc->encrypt($xmldata, $this->appid);

$ret = $array[0];

if ($ret != 0) {

$this->log('encrypt err!');

return false;

}

$timestamp = time();

$nonce = rand(77,999)*rand(605,888)*rand(11,99);

$encrypt = $array[1];

$tmpArr = array($this->token, $timestamp, $nonce,$encrypt);//比普通公众平台多了一个加密的密文

sort($tmpArr, SORT_STRING);

$signature = implode($tmpArr);

$signature = sha1($signature);

$smsg = $this->generate($encrypt, $signature, $timestamp, $nonce);

$this->log($smsg);

if ($return)

return $smsg;

elseif ($smsg){

echo $smsg;

return true;

}else

return false;

}

private function generate($encrypt, $signature, $timestamp, $nonce)

{

//格式化加密信息

$format = "

%s

";

return sprintf($format, $encrypt, $signature, $timestamp, $nonce);

}

/**

* 通用auth验证方法

* @param string $appid

* @param string $appsecret

* @param string $token 手动指定access_token,非必要情况不建议用

*/

public function checkAuth($appid='',$appsecret='',$token=''){

if (!$appid || !$appsecret) {

$appid = $this->appid;

$appsecret = $this->appsecret;

}

if ($token) { //手动指定token,优先使用

$this->access_token=$token;

return $this->access_token;

}

//TODO: get the cache access_token

$result = $this->http_get(self::API_URL_PREFIX.self::TOKEN_GET_URL.'corpid='.$appid.'&corpsecret='.$appsecret);

if ($result)

{

$json = json_decode($result,true);

if (!$json || isset($json['errcode'])) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

$this->access_token = $json['access_token'];

$expire = $json['expires_in'] ? intval($json['expires_in'])-100 : 3600;

//TODO: cache access_token

return $this->access_token;

}

return false;

}

/**

* 删除验证数据

* @param string $appid

*/

public function resetAuth($appid=''){

if (!$appid) $appid = $this->appid;

$this->access_token = '';

//TODO: remove cache

return true;

}

/**

* 创建菜单

* @param array $data 菜单数组数据

* example:

* array (

* 'button' => array (

* 0 => array (

* 'name' => '扫码',

* 'sub_button' => array (

* 0 => array (

* 'type' => 'scancode_waitmsg',

* 'name' => '扫码带提示',

* 'key' => 'rselfmenu_0_0',

* ),

* 1 => array (

* 'type' => 'scancode_push',

* 'name' => '扫码推事件',

* 'key' => 'rselfmenu_0_1',

* ),

* ),

* ),

* 1 => array (

* 'name' => '发图',

* 'sub_button' => array (

* 0 => array (

* 'type' => 'pic_sysphoto',

* 'name' => '系统拍照发图',

* 'key' => 'rselfmenu_1_0',

* ),

* 1 => array (

* 'type' => 'pic_photo_or_album',

* 'name' => '拍照或者相册发图',

* 'key' => 'rselfmenu_1_1',

* )

* ),

* ),

* 2 => array (

* 'type' => 'location_select',

* 'name' => '发送位置',

* 'key' => 'rselfmenu_2_0'

* ),

* ),

* )

* type可以选择为以下几种,会收到相应类型的事件推送。请注意,3到8的所有事件,仅支持微信iPhone5.4.1以上版本,

* 和Android5.4以上版本的微信用户,旧版本微信用户点击后将没有回应,开发者也不能正常接收到事件推送。

* 1、click:点击推事件

* 2、view:跳转URL

* 3、scancode_push:扫码推事件

* 4、scancode_waitmsg:扫码推事件且弹出“消息接收中”提示框

* 5、pic_sysphoto:弹出系统拍照发图

* 6、pic_photo_or_album:弹出拍照或者相册发图

* 7、pic_weixin:弹出微信相册发图器

* 8、location_select:弹出地理位置选择器

*/

public function createMenu($data,$agentid=''){

if ($agentid=='') {

$agentid=$this->agentid;

}

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_post(self::API_URL_PREFIX.self::MENU_CREATE_URL.'access_token='.$this->access_token.'&agentid='.$agentid,self::json_encode($data));

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return true;

}

return false;

}

/**

* 获取菜单

* @return array('menu'=>array(....s))

*/

public function getMenu($agentid=''){

if ($agentid=='') {

$agentid=$this->agentid;

}

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_get(self::API_URL_PREFIX.self::MENU_GET_URL.'access_token='.$this->access_token.'&agentid='.$agentid);

if ($result)

{

$json = json_decode($result,true);

if (!$json || isset($json['errcode']) || $json['errcode']!=0) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 删除菜单

* @return boolean

*/

public function deleteMenu($agentid=''){

if ($agentid=='') {

$agentid=$this->agentid;

}

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_get(self::API_URL_PREFIX.self::MENU_DELETE_URL.'access_token='.$this->access_token.'&agentid='.$agentid);

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode'])) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return true;

}

return false;

}

/**

* 上传多媒体文件 (只有三天的有效期,过期自动被删除)

* 注意:数组的键值任意,但文件名前必须加@,使用单引号以避免本地路径斜杠被转义

* @param array $data {"media":'@Path\filename.jpg'}

* @param type 媒体文件类型:图片(image)、语音(voice)、视频(video),普通文件(file)

* @return boolean|array

* {

* "type": "image",

* "media_id": "0000001",

* "created_at": "1380000000"

* }

*/

public function uploadMedia($data, $type){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_post(self::API_URL_PREFIX.self::MEDIA_UPLOAD.'access_token='.$this->access_token.'&type='.$type,$data,true);

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode'])) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 根据媒体文件ID获取媒体文件

* @param string $media_id 媒体文件id

* @return raw data

*/

public function getMedia($media_id){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_get(self::API_URL_PREFIX.self::MEDIA_GET_URL.'access_token='.$this->access_token.'&media_id='.$media_id);

if ($result)

{

$json = json_decode($result,true);

if (isset($json['errcode'])) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $result;

}

return false;

}

/**

* 创建部门

* @param array $data 结构体为:

* array (

* "name" => "邮箱产品组", //部门名称

* "parentid" => "1" //父部门id

* "order" => "1", //(非必须)在父部门中的次序。从1开始,数字越大排序越靠后

* )

* @return boolean|array

* 成功返回结果

* {

* "errcode": 0, //返回码

* "errmsg": "created", //对返回码的文本描述内容

* "id": 2 //创建的部门id。

* }

*/

public function createDepartment($data){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_post(self::API_URL_PREFIX.self::DEPARTMENT_CREATE_URL.'access_token='.$this->access_token,self::json_encode($data));

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 更新部门

* @param array $data 结构体为:

* array(

* "id" => "1" //(必须)部门id

* "name" => "邮箱产品组", //(非必须)部门名称

* "parentid" => "1", //(非必须)父亲部门id。根部门id为1

* "order" => "1", //(非必须)在父部门中的次序。从1开始,数字越大排序越靠后

* )

* @return boolean|array 成功返回结果

* {

* "errcode": 0, //返回码

* "errmsg": "updated" //对返回码的文本描述内容

* }

*/

public function updateDepartment($data){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_post(self::API_URL_PREFIX.self::DEPARTMENT_UPDATE_URL.'access_token='.$this->access_token,self::json_encode($data));

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 删除部门

* @param $id

* @return boolean|array 成功返回结果

* {

* "errcode": 0, //返回码

* "errmsg": "deleted" //对返回码的文本描述内容

* }

*/

public function deleteDepartment($id){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_get(self::API_URL_PREFIX.self::DEPARTMENT_DELETE_URL.'access_token='.$this->access_token.'&id='.$id);

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 移动部门

* @param $data

* array(

* "department_id" => "5",//所要移动的部门

* "to_parentid" => "2",//想移动到的父部门节点,根部门为1

* "to_position" => "1"//(非必须)想移动到的父部门下的位置,1表示最上方,往后位置为2,3,4,以此类推,默认为1

* )

* @return boolean|array 成功返回结果

* {

* "errcode": 0, //返回码

* "errmsg": "ok" //对返回码的文本描述内容

* }

*/

public function moveDepartment($data){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_get(self::API_URL_PREFIX.self::DEPARTMENT_MOVE_URL.'access_token='.$this->access_token,self::json_encode($data));

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 获取部门列表

* @return boolean|array 成功返回结果

* {

* "errcode": 0,

* "errmsg": "ok",

* "department": [ //部门列表数据。以部门的order字段从小到大排列

* {

* "id": 1,

* "name": "广州研发中心",

* "parentid": 0

* },

* {

* "id": 2

* "name": "邮箱产品部",

* "parentid": 1

* }

* ]

* }

*/

public function getDepartment(){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_get(self::API_URL_PREFIX.self::DEPARTMENT_LIST_URL.'access_token='.$this->access_token);

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode'])) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 创建成员

* @param array $data 结构体为:

* array(

* "userid" => "zhangsan",

* "name" => "张三",

* "department" => [1, 2],

* "position" => "产品经理",

* "mobile" => "15913215421",

* "gender" => 1, //性别。gender=0表示男,=1表示女

* "tel" => "62394",

* "email" => "zhangsan@gzdev.com",

* "weixinid" => "zhangsan4dev"

* )

* @return boolean|array

* 成功返回结果

* {

* "errcode": 0, //返回码

* "errmsg": "created", //对返回码的文本描述内容

* }

*/

public function createUser($data){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_post(self::API_URL_PREFIX.self::USER_CREATE_URL.'access_token='.$this->access_token,self::json_encode($data));

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 更新成员

* @param array $data 结构体为:

* array(

* "userid" => "zhangsan",

* "name" => "张三",

* "department" => [1, 2],

* "position" => "产品经理",

* "mobile" => "15913215421",

* "gender" => 1, //性别。gender=0表示男,=1表示女

* "tel" => "62394",

* "email" => "zhangsan@gzdev.com",

* "weixinid" => "zhangsan4dev"

* )

* @return boolean|array 成功返回结果

* {

* "errcode": 0, //返回码

* "errmsg": "updated" //对返回码的文本描述内容

* }

*/

public function updateUser($data){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_post(self::API_URL_PREFIX.self::USER_UPDATE_URL.'access_token='.$this->access_token,self::json_encode($data));

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 删除成员

* @param $userid 员工UserID。对应管理端的帐号

* @return boolean|array 成功返回结果

* {

* "errcode": 0, //返回码

* "errmsg": "deleted" //对返回码的文本描述内容

* }

*/

public function deleteUser($userid){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_get(self::API_URL_PREFIX.self::USER_DELETE_URL.'access_token='.$this->access_token.'&userid='.$userid);

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 获取成员信息

* @param $userid 员工UserID。对应管理端的帐号

* @return boolean|array 成功返回结果

* {

* "errcode": 0,

* "errmsg": "ok",

* "userid": "zhangsan",

* "name": "李四",

* "department": [1, 2],

* "position": "后台工程师",

* "mobile": "15913215421",

* "gender": 1, //性别。gender=0表示男,=1表示女

* "tel": "62394",

* "email": "zhangsan@gzdev.com",

* "weixinid": "lisifordev", //微信号

* "avatar": "http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3W..../0", //头像url。注:如果要获取小图将url最后的"/0"改成"/64"即可

* "status": 1 //关注状态: 1=已关注,2=已冻结,4=未关注

* }

*/

public function getUserInfo($userid){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_get(self::API_URL_PREFIX.self::USER_GET_URL.'access_token='.$this->access_token.'&userid='.$userid);

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 获取部门成员

* @param $department_id 部门id

* @param $fetch_child 1/0:是否递归获取子部门下面的成员

* @param $status 0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加

* @return boolean|array 成功返回结果

* {

* "errcode": 0,

* "errmsg": "ok",

* "userlist": [

* {

* "userid": "zhangsan",

* "name": "李四"

* }

* ]

* }

*/

public function getUserList($department_id,$fetch_child=0,$status=0){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_get(self::API_URL_PREFIX.self::USER_LIST_URL.'access_token='.$this->access_token

.'&department_id='.$department_id.'&fetch_child='.$fetch_child.'&status='.$status);

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 根据code获取成员信息

* 通过Oauth2.0或者设置了二次验证时获取的code,用于换取成员的UserId和DeviceId

*

* @param $code Oauth2.0或者二次验证时返回的code值

* @param $agentid 跳转链接时所在的企业应用ID,未填则默认为当前配置的应用id

* @return boolean|array 成功返回数组

* array(

* 'UserId' => 'USERID', //员工UserID

* 'DeviceId' => 'DEVICEID' //手机设备号(由微信在安装时随机生成)

* )

*/

public function getUserId($code,$agentid=0){

if (!$agentid) $agentid=$this->agentid;

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_get(self::API_URL_PREFIX.self::USER_GETINFO_URL.'access_token='.$this->access_token.'&code='.$code.'&agentid'.$agentid);

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 创建标签

* @param array $data 结构体为:

* array(

* "tagname" => "UI"

* )

* @return boolean|array

* 成功返回结果

* {

* "errcode": 0, //返回码

* "errmsg": "created", //对返回码的文本描述内容

* "tagid": "1"

* }

*/

public function createTag($data){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_post(self::API_URL_PREFIX.self::TAG_CREATE_URL.'access_token='.$this->access_token,self::json_encode($data));

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 更新标签

* @param array $data 结构体为:

* array(

* "tagid" => "1",

* "tagname" => "UI design"

* )

* @return boolean|array 成功返回结果

* {

* "errcode": 0, //返回码

* "errmsg": "updated" //对返回码的文本描述内容

* }

*/

public function updateTag($data){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_post(self::API_URL_PREFIX.self::TAG_UPDATE_URL.'access_token='.$this->access_token,self::json_encode($data));

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 删除标签

* @param $tagid 标签TagID

* @return boolean|array 成功返回结果

* {

* "errcode": 0, //返回码

* "errmsg": "deleted" //对返回码的文本描述内容

* }

*/

public function deleteTag($tagid){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_get(self::API_URL_PREFIX.self::TAG_DELETE_URL.'access_token='.$this->access_token.'&tagid='.$tagid);

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 获取标签成员

* @param $tagid 标签TagID

* @return boolean|array 成功返回结果

* {

* "errcode": 0,

* "errmsg": "ok",

* "userlist": [

* {

* "userid": "zhangsan",

* "name": "李四"

* }

* ]

* }

*/

public function getTag($tagid){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_get(self::API_URL_PREFIX.self::TAG_GET_URL.'access_token='.$this->access_token.'&tagid='.$tagid);

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 增加标签成员

* @param array $data 结构体为:

* array (

* "tagid" => "1",

* "userlist" => array( //企业员工ID列表

* "user1",

* "user2"

* )

* )

* @return boolean|array

* 成功返回结果

* {

* "errcode": 0, //返回码

* "errmsg": "ok", //对返回码的文本描述内容

* "invalidlist":"usr1|usr2|usr" //若部分userid非法,则会有此段。不在权限内的员工ID列表,以“|”分隔

* }

*/

public function addTagUser($data){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_post(self::API_URL_PREFIX.self::TAG_ADDUSER_URL.'access_token='.$this->access_token,self::json_encode($data));

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 删除标签成员

* @param array $data 结构体为:

* array (

* "tagid" => "1",

* "userlist" => array( //企业员工ID列表

* "user1",

* "user2"

* )

* )

* @return boolean|array

* 成功返回结果

* {

* "errcode": 0, //返回码

* "errmsg": "deleted", //对返回码的文本描述内容

* "invalidlist":"usr1|usr2|usr" //若部分userid非法,则会有此段。不在权限内的员工ID列表,以“|”分隔

* }

*/

public function delTagUser($data){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_post(self::API_URL_PREFIX.self::TAG_DELUSER_URL.'access_token='.$this->access_token,self::json_encode($data));

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 获取标签列表

* @return boolean|array 成功返回数组结果,这里附上json样例

* {

* "errcode": 0,

* "errmsg": "ok",

* "taglist":[

* {"tagid":1,"tagname":"a"},

* {"tagid":2,"tagname":"b"}

* ]

* }

*/

public function getTagList(){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_get(self::API_URL_PREFIX.self::TAG_LIST_URL.'access_token='.$this->access_token);

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode'])) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 主动发送信息接口

* @param array $data 结构体为:

* array(

* "touser" => "UserID1|UserID2|UserID3",

* "toparty" => "PartyID1|PartyID2 ",

* "totag" => "TagID1|TagID2 ",

* "safe":"0"//是否为保密消息,对于news无效

* "agentid" => "001",//应用id

* "msgtype" => "text", //根据信息类型,选择下面对应的信息结构体

*

* "text" => array(

* "content" => "Holiday Request For Pony(http://xxxxx)"

* ),

*

* "image" => array(

* "media_id" => "MEDIA_ID"

* ),

*

* "voice" => array(

* "media_id" => "MEDIA_ID"

* ),

*

* " video" => array(

* "media_id" => "MEDIA_ID",

* "title" => "Title",

* "description" => "Description"

* ),

*

* "file" => array(

* "media_id" => "MEDIA_ID"

* ),

*

* "news" => array(//不支持保密

* "articles" => array( //articles 图文消息,一个图文消息支持1到10个图文

* array(

* "title" => "Title", //标题

* "description" => "Description", //描述

* "url" => "URL", //点击后跳转的链接。可根据url里面带的code参数校验员工的真实身份。

* "picurl" => "PIC_URL", //图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图640*320,

* //小图80*80。如不填,在客户端不显示图片

* ),

* )

* ),

*

* "mpnews" => array(

* "articles" => array( //articles 图文消息,一个图文消息支持1到10个图文

* array(

* "title" => "Title", //图文消息的标题

* "thumb_media_id" => "id", //图文消息缩略图的media_id

* "author" => "Author", //图文消息的作者(可空)

* "content_source_url" => "URL", //图文消息点击“阅读原文”之后的页面链接(可空)

* "content" => "Content" //图文消息的内容,支持html标签

* "digest" => "Digest description", //图文消息的描述

* "show_cover_pic" => "0" //是否显示封面,1为显示,0为不显示(可空)

* ),

* )

* )

* )

* 请查看官方开发文档中的 发送消息 -> 消息类型及数据格式

*

* @return boolean|array

* 如果对应用或收件人、部门、标签任何一个无权限,则本次发送失败;

* 如果收件人、部门或标签不存在,发送仍然执行,但返回无效的部分。

* {

* "errcode": 0,

* "errmsg": "ok",

* "invaliduser": "UserID1",

* "invalidparty":"PartyID1",

* "invalidtag":"TagID1"

* }

*/

public function sendMessage($data){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_post(self::API_URL_PREFIX.self::MASS_SEND_URL.'access_token='.$this->access_token,self::json_encode($data));

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* 二次验证

* 企业在开启二次验证时,必须填写企业二次验证页面的url。

* 当员工绑定通讯录中的帐号后,会收到一条图文消息,

* 引导员工到企业的验证页面验证身份,企业在员工验证成功后,

* 调用如下接口即可让员工关注成功。

*

* @param $userid

* @return boolean|array 成功返回结果

* {

* "errcode": 0, //返回码

* "errmsg": "ok" //对返回码的文本描述内容

* }

*/

public function authSucc($userid){

if (!$this->access_token && !$this->checkAuth()) return false;

$result = $this->http_get(self::API_URL_PREFIX.self::AUTHSUCC_URL.'access_token='.$this->access_token.'&userid='.$userid);

if ($result)

{

$json = json_decode($result,true);

if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {

$this->errCode = $json['errcode'];

$this->errMsg = $json['errmsg'];

return false;

}

return $json;

}

return false;

}

/**

* oauth 授权跳转接口

* @param string $callback 回调URI

* @param string $state 重定向后会带上state参数,企业可以填写a-zA-Z0-9的参数值

* @return string

*/

public function getOauthRedirect($callback,$state='STATE',$scope='snsapi_base'){

return self::OAUTH_PREFIX.self::OAUTH_AUTHORIZE_URL.'appid='.$this->appid.'&redirect_uri='.urlencode($callback).'&response_type=code&scope='.$scope.'&state='.$state.'#wechat_redirect';

}

}

/**

* PKCS7Encoder class

*

* 提供基于PKCS7算法的加解密接口.

*/

class PKCS7Encoder

{

public static $block_size = 32;

/**

* 对需要加密的明文进行填充补位

* @param $text 需要进行填充补位操作的明文

* @return 补齐明文字符串

*/

function encode($text)

{

$block_size = PKCS7Encoder::$block_size;

$text_length = strlen($text);

//计算需要填充的位数

$amount_to_pad = PKCS7Encoder::$block_size - ($text_length % PKCS7Encoder::$block_size);

if ($amount_to_pad == 0) {

$amount_to_pad = PKCS7Encoder::block_size;

}

//获得补位所用的字符

$pad_chr = chr($amount_to_pad);

$tmp = "";

for ($index = 0; $index < $amount_to_pad; $index++) {

$tmp .= $pad_chr;

}

return $text . $tmp;

}

/**

* 对解密后的明文进行补位删除

* @param decrypted 解密后的明文

* @return 删除填充补位后的明文

*/

function decode($text)

{

$pad = ord(substr($text, -1));

if ($pad < 1 || $pad > PKCS7Encoder::$block_size) {

$pad = 0;

}

return substr($text, 0, (strlen($text) - $pad));

}

}

/**

* Prpcrypt class

*

* 提供接收和推送给公众平台消息的加解密接口.

*/

class Prpcrypt

{

public $key;

function Prpcrypt($k)

{

$this->key = base64_decode($k . "=");

}

/**

* 对明文进行加密

* @param string $text 需要加密的明文

* @return string 加密后的密文

*/

public function encrypt($text, $appid)

{

try {

//获得16位随机字符串,填充到明文之前

$random = $this->getRandomStr();//"aaaabbbbccccdddd";

$text = $random . pack("N", strlen($text)) . $text . $appid;

// 网络字节序

$size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);

$module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');

$iv = substr($this->key, 0, 16);

//使用自定义的填充方式对明文进行补位填充

$pkc_encoder = new PKCS7Encoder;

$text = $pkc_encoder->encode($text);

mcrypt_generic_init($module, $this->key, $iv);

//加密

$encrypted = mcrypt_generic($module, $text);

mcrypt_generic_deinit($module);

mcrypt_module_close($module);

//print(base64_encode($encrypted));

//使用BASE64对加密后的字符串进行编码

return array(ErrorCode::$OK, base64_encode($encrypted));

} catch (Exception $e) {

//print $e;

return array(ErrorCode::$EncryptAESError, null);

}

}

/**

* 对密文进行解密

* @param string $encrypted 需要解密的密文

* @return string 解密得到的明文

*/

public function decrypt($encrypted, $appid)

{

try {

//使用BASE64对需要解密的字符串进行解码

$ciphertext_dec = base64_decode($encrypted);

$module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');

$iv = substr($this->key, 0, 16);

mcrypt_generic_init($module, $this->key, $iv);

//解密

$decrypted = mdecrypt_generic($module, $ciphertext_dec);

mcrypt_generic_deinit($module);

mcrypt_module_close($module);

} catch (Exception $e) {

return array(ErrorCode::$DecryptAESError, null);

}

try {

//去除补位字符

$pkc_encoder = new PKCS7Encoder;

$result = $pkc_encoder->decode($decrypted);

//去除16位随机字符串,网络字节序和AppId

if (strlen($result) < 16)

return "";

$content = substr($result, 16, strlen($result));

$len_list = unpack("N", substr($content, 0, 4));

$xml_len = $len_list[1];

$xml_content = substr($content, 4, $xml_len);

$from_appid = substr($content, $xml_len + 4);

} catch (Exception $e) {

//print $e;

return array(ErrorCode::$IllegalBuffer, null);

}

if ($from_appid != $appid)

return array(ErrorCode::$ValidateAppidError, null);

return array(0, $xml_content);

}

/**

* 随机生成16位字符串

* @return string 生成的字符串

*/

function getRandomStr()

{

$str = "";

$str_pol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";

$max = strlen($str_pol) - 1;

for ($i = 0; $i < 16; $i++) {

$str .= $str_pol[mt_rand(0, $max)];

}

return $str;

}

}

/**

* error code

* 仅用作类内部使用,不用于官方API接口的errCode码

*/

class ErrorCode

{

public static $OK = 0;

public static $ValidateSignatureError = 40001;

public static $ParseXmlError = 40002;

public static $ComputeSignatureError = 40003;

public static $IllegalAesKey = 40004;

public static $ValidateAppidError = 40005;

public static $EncryptAESError = 40006;

public static $DecryptAESError = 40007;

public static $IllegalBuffer = 40008;

public static $EncodeBase64Error = 40009;

public static $DecodeBase64Error = 40010;

public static $GenReturnXmlError = 40011;

public static $errCode=array(

'0'=>'无问题',

'40001'=>'签名验证错误',

'40002'=>'xml解析失败',

'40003'=>'sha加密生成签名失败',

'40004'=>'encodingAesKey 非法',

'40005'=>'appid 校验错误',

'40006'=>'aes 加密失败',

'40007'=>'aes 解密失败',

'40008'=>'解密后得到的buffer非法',

'40009'=>'base64加密失败',

'40010'=>'base64解密失败',

'40011'=>'生成xml失败',

);

public static function getErrText($err) {

if (isset(self::$errCode[$err])) {

return self::$errCode[$err];

}else {

return false;

};

}

}

 类似资料: