微信客服消息

<?php

/**
 * 回复用户消息 - 客服消息
 * 2015-3-31 
 */
class WeixinReply {

    /**
     * 回复消息调用接口
     * @var type 
     */
    private $apiReplyUrl;

    /**
     * 获取access token 接口
     * @var type 
     */
    private $apiGetAccessTokenUrl;

    /**
     * access token 获取到的凭证 
     * @var string
     */
    private $accessToken;

    /**
     * accessToken memcache 缓存名称
     * @var type 
     */
    private $accessTokenCacheName;

    const APPID = 'xxxx'; //AppID(应用ID)
    const APPSECRET = 'xxxxxx'; //AppSecret(应用密钥)

    public function __construct() {
        $this->accessTokenCacheName = 'weixin_AccessToken';
        $this->apiGetAccessTokenUrl = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' .
                self::APPID . '&secret=' . self::APPSECRET;

        if (!$this->getAccessToken()) {
            echo "获取AccessToken失败!";
            exit;
        }

        $this->apiReplyUrl = 'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=' . $this->accessToken;
    }

    /**
     * 获取access token
     * @param type $force 是否强制获取access token
     */
    private function getAccessToken($force = 0) {
        $objMemcached = new KIFCacheMemcached();
        $accessToken = $objMemcached->get($this->accessTokenCacheName);
        if ($force)
            $accessToken = '';
        if (!$accessToken) {
            $return = $this->curlGetData($this->apiGetAccessTokenUrl);
            $return = json_decode($return, true);
            $accessToken = $return['access_token'];
            if (!$accessToken) {
                return false;
            }
            $objMemcached->set($this->accessTokenCacheName, $accessToken, $return['expires_in'] - 600);
        }
        $this->accessToken = $accessToken;
        return true;
    }

    /**
     * 回复消息
     * @param type $params
     */
    public function reply($params) {
        $return = null;
        if ($params['type'] == WeixinAutoReply::TYPE_TEXT) {
            $return = $this->textMessage($params);
        }
        if (!$return) {
            return '';
        }
        $return = json_decode($return, true);
        // access_token invalid
        if ($return['errmsg'] == 'invalid credential') {
            $this->getAccessToken(1);
            return '';
        }

        if ($return['errcode']) {
            return $return['errmsg'];
        }
        /**
         * success {
          "errcode": 0,
          "errmsg": "ok"
          }
         */
        return 'ok';
    }

    /**
     * 回复文本消息
     */
    private function textMessage($params) {

        if (!isset($params['openid']) || !$params['openid'] || !isset($params['content']) || !$params['content']) {
            return 'openid 或 content为空';
        }
        $params['content'] = htmlentities($params['content'], ENT_COMPAT, 'utf-8');
        $jsonData = <<<EOF
        {
    "touser":"{$params['openid']}",
    "msgtype":"text",
    "text":
    {
         "content":"{$params['content']}"
    }
}        
EOF;
        $return = $this->curlPostData($jsonData);

        return $return;
    }

    /**
     * 发送数据
     */
    private function curlPostData($jsonData) {
        $ch = curl_init($this->apiReplyUrl);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
        curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonData);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/json',
            'Content-Length: ' . strlen($jsonData))
        );
        $result = curl_exec($ch);
        return $result;
    }

    /**
     * 获取数据 - get
     */
    private function curlGetData($url) {
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array());
        $result = curl_exec($ch);
        return $result;
    }

    /**
     * 对字符串进行加密和解密
     * @param <string> $string
     * @param <string> $operation  DECODE 解密 | ENCODE  加密
     * @param <int> $expiry 有效期,单位秒
     * @return <string>
     */
    static public function authcode($string, $operation = 'DECODE', $expiry = 2592000) {
        $ckey_length = 4;
        $key = '08127b44d5a005a12b6e880';
        $keya = md5(substr($key, 0, 16));
        $keyb = md5(substr($key, 16, 16));
        $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length)) : '';

        $cryptkey = $keya . md5($keya . $keyc);
        $key_length = strlen($cryptkey);

        $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
        $string_length = strlen($string);

        $result = '';
        $box = range(0, 255);

        $rndkey = array();
        for ($i = 0; $i <= 255; $i++) {
            $rndkey[$i] = ord($cryptkey[$i % $key_length]);
        }

        for ($j = $i = 0; $i < 256; $i++) {
            $j = ($j + $box[$i] + $rndkey[$i]) % 256;
            $tmp = $box[$i];
            $box[$i] = $box[$j];
            $box[$j] = $tmp;
        }

        for ($a = $j = $i = 0; $i < $string_length; $i++) {
            $a = ($a + 1) % 256;
            $j = ($j + $box[$a]) % 256;
            $tmp = $box[$a];
            $box[$a] = $box[$j];
            $box[$j] = $tmp;
            $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
        }

        if ($operation == 'DECODE') {
            if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
                return substr($result, 26);
            } else {
                return '';
            }
        } else {
            return $keyc . str_replace('=', '', base64_encode($result));
        }
    }

}

Template

.main{800px; margin:0 auto; position: relative;} .replybox{ display:none; 200px; height:120px; position: absolute; top:200px; right:-240px; background-color: #fff; padding:10px 20px 40px; border:1px solid #ccc; text-align:center; } .replybox textarea{ 200px; height:60px;} .replybox .tips{ display:block; text-align:left; margin-bottom:5px; color:#3c3c3c;} .btnon{ color:#f00;}

<div class="replybox">
    <form action="http://xxxx/message.php" method="post">
        <textarea name="content"></textarea>
        <span class="tips">获得奖品说明 《回车换行》微信试用活动链接</span>
        <input type="button" name="replysubmitbtn" value="提交" />
        <input type="hidden" name="msgid" value="" />
    </form>
</div>
<script type="text/javascript">
    $(function(){
        //root_domain
        $(".replybtn").click(function() {
            $("input[name=msgid]").val($(this).attr('rel'));
            $(".replybox").show();
            $(".replybtn").removeClass('btnon')
            $(this).addClass('btnon');
        });
        // reply submit
        $("input[name=replysubmitbtn]").click(function() {
            var id = $("input[name=msgid]").val();
            if(!id) {
                alert('请选择回复项');
                return false;
            }
            var content =  $("textarea[name=content]").val();
            $.ajax({
               url: root_domain + '/admin/weixin/message.php?action=replymsg',
               data:{id:id, content:content},
               dataType:'json',
               type:'GET',
               success:function(data) {
                   if(data.ok) {
                       $("textarea[name=content]").val(data.msg);
                       alert('回复成功');
                   } else {
                       alert(data.msg);
                   }
               }
            });
        });
        
    });
</script>

Recive

$openid = WeixinReply::authcode(Request::g("e_user"), 'DECODE');

message.php

// ACTION 扩展
if(Request::g('action') == 'replymsg') {
    $id = Request::g('id');
    $content = Request::g('content');
    if(!$content) {
        ajax_fail_exit('回复内容为空');
    }
    
    $message = $objWeixinChatsData->get($id);
    if(!$message) {
        ajax_fail_exit('没有获取到此消息内容');
    }
    // 时间判断, 发布时间两小时内
    if(time() - $message['create_time'] > 86400 * 2) {
        ajax_fail_exit('仅允许在消息发布后48小时内回复');
    }
    
    $objWeixinReply = new WeixinReply();
    $message['openid'] = 'xxxxxx';
    
    if (preg_match('#http://xxx.xxxx.com/weixin/article/w+#i', $content, $match)) {
        $authOpenid = $objWeixinReply->authcode($message['openid'], 'ENCODE');
        $suffix = '?page_type=true' . '&e_user=' . urlencode($authOpenid);
        $content = str_replace($match[0], $match[0]. $suffix, $content);
    }
    
    // 回复
    $params = array(
        'openid' => $message['openid'],
        'content' => $content,
        'type' => 'text',
    );
    
    $return = $objWeixinReply->reply($params);
    if($return == 'ok') {
        // 回复记录... @todo
        
        ajax_success_exit($content);
    } else {
        ajax_fail_exit('回复失败 ' . $return);
    }
    
}
原文地址:https://www.cnblogs.com/bandbandme/p/4390087.html