自己写的微信公众号开发模型WeChat (回复参考weiphp)

模型:WeChat

<?php
namespace Org;
/**
 * 微信开发工具类
 * Class WeChat
 * Author 陈琼和
 * @package Org
 */
class WeChat
{
    const LOG_NAME  = "PHP_LOG_%s.log.php"; //日志名
    const LOG_DIR   = "./Log/%s/";          //日志目录

    static private $fromUser = ‘‘;  //当前消息的发送者
    static private $toUser = ‘‘;    //当前消息的接收者
    static private $member = ‘‘;    //公众号会员记录

    /**
     * 设置要操作的微信公众号
     * @param $mid  公众号id
     */
    static public function setMember($mid)
    {
        self::$member = M(‘Member‘)->find($mid);
    }
    /**
     * 处理来自微信服务器的消息
     * @param $callback
     * @access public
     * @return void
     */
    static public function process($callback)
    {
        //如果回调函数没有设置,则退出
        if (!is_callable($callback))
        {
            return;
        }
        $postData = $GLOBALS[‘HTTP_RAW_POST_DATA‘];
        if (empty($postData)) return;  //如果没有POST数据,则退出
        $object = simplexml_load_string($postData, ‘SimpleXMLElement‘, LIBXML_NOCDATA);//解析POST数据(XML格式)
        $messgeType = trim($object->MsgType);    //取得消息类型
        self::$fromUser = $object->FromUserName; //记录消息发送方(不是发送者的微信号,而是一个加密后的OpenID)
        self::$toUser = $object->ToUserName;     //记录消息接收方(就是公共平台的OpenID)
        self::addLog($postData,1,$messgeType);       //记录日志

        //根据不同的消息类型,分别处理
        switch($messgeType)
        {
            case "text":   //文本消息
                //调用回调函数
                call_user_func($callback, "Text", array(‘Content‘=>$object->Content));
                break;
            case "image":  //图片消息
                call_user_func($callback, "Image",array(‘PicUrl‘=>$object->PicUrl, ‘MediaId‘=>$object->MediaId));
                break;
            case "voice":  //音频消息
                call_user_func($callback, "Voice",array(‘MediaId‘=>$object->MediaId, ‘Format‘=>$object->Format,‘Recognition‘=>$object->Recognition) );
                break;
            case "video":  //视频消息
                call_user_func($callback, "Video", array(‘MediaId‘=>$object->MediaId, ‘ThumbMediaId‘=>$object->ThumbMediaId));
                break;
            case "shortvideo":  //小视频消息
                call_user_func($callback, "Shortvideo", array(‘MediaId‘=>$object->MediaId, ‘ThumbMediaId‘=>$object->ThumbMediaId));
                break;
            case "location": //定位信息
                call_user_func($callback, "Location", array(‘Label‘=>$object->Label, ‘Location_X‘=>$object->Location_X, ‘Location_Y‘=>$object->Location_Y,‘Scale‘=>$object->Scale));
                break;
            case "link":  //链接信息
                call_user_func($callback, "Link", array(‘Url‘=>$object->Url, ‘Title‘=>$object->Title, ‘Description‘=>$object->Description));
                break;
            case "event":  //事件
                switch ($object->Event)
                {
                    case "subscribe":           //订阅事件
                        call_user_func($callback, "Subscribe",array( ‘EventKey‘=>$object->EventKey, ‘Ticket‘=>$object->Ticket));
                        break;
                    case "unsubscribe":         //取消订阅事件
                        call_user_func($callback, "UnSubscribe", array(‘FromUserName‘=>$object->FromUserName));
                        break;
                    case "CLICK":               //点击菜单拉取消息时的事件
                        call_user_func($callback, "Click", array(‘EventKey‘=>$object->EventKey));
                        break;
                    case "VIEW":                //点击菜单跳转链接时的事件
                        call_user_func($callback, "View",array(‘EventKey‘=> $object->EventKey));
                        break;
                    case "scancode_push":       //扫码推事件的事件推送
                        call_user_func($callback, "ScanPush",array( ‘EventKey‘=>$object->EventKey,‘ScanCodeInfo‘=>$object->ScanCodeInfo,‘ScanType‘=>$object->ScanType,‘ScanResult‘=>$object->ScanResult));
                        break;
                    case "scancode_waitmsg":    //扫码推事件且弹出“消息接收中”提示框的事件推送
                        call_user_func($callback, "ScanWaitmsg",array( ‘EventKey‘=>$object->EventKey,‘ScanCodeInfo‘=>$object->ScanCodeInfo,‘ScanType‘=>$object->ScanType,‘ScanResult‘=>$object->ScanResult));
                        break;
                    case "pic_sysphoto":        //弹出系统拍照发图的事件推送
                        call_user_func($callback, "PicSysPhoto",array( ‘EventKey‘=>$object->EventKey, ‘SendPicsInfo‘=>$object->SendPicsInfo,‘Count‘=>$object->Count,‘PicList‘=>$object->PicList,‘PicMd5Sum‘=>$object->PicMd5Sum));
                        break;
                    case "pic_photo_or_album":  //弹出拍照或者相册发图的事件推送
                        call_user_func($callback, "PicPhotoOrAlbum",array( ‘EventKey‘=>$object->EventKey, ‘SendPicsInfo‘=>$object->SendPicsInfo,‘Count‘=>$object->Count,‘PicList‘=>$object->PicList,‘PicMd5Sum‘=>$object->PicMd5Sum));
                        break;
                    case "pic_weixin":          //弹出微信相册发图器的事件推送
                        call_user_func($callback, "PicWeixin",array( ‘EventKey‘=>$object->EventKey, ‘SendPicsInfo‘=>$object->SendPicsInfo,‘Count‘=>$object->Count,‘PicList‘=>$object->PicList,‘PicMd5Sum‘=>$object->PicMd5Sum));
                        break;
                    case "location_select":     //弹出地理位置选择器的事件推送
                        call_user_func($callback, "LocationSelect",array( ‘EventKey‘=>$object->EventKey, ‘SendLocationInfo‘=>$object->SendLocationInfo,‘Location_X‘=>$object->Location_X,‘Location_Y‘=>$object->Location_Y,‘Scale‘=>$object->Scale,‘Label‘=>$object->Label,‘Poiname‘=>$object->Poiname));
                        break;
                    case ‘LOCATION‘:            //上报地址位置事件
                        call_user_func($callback, "UpLocation",array( ‘Latitude‘=>$object->Latitude, ‘Longitude‘=>$object->Longitude, ‘Precision‘=>$object->Precision));
                        break;
                    default :
                        //Unknow Event
                        break;
                }
                break;
            default:
                //未知消息类型
                break;
        }
    }

    /**
     * 获取access_token
     * $mid 公众号id
     * @access public
     * @return mixed
     */
    static public function getAcctoken ($mid=‘‘)
    {
        if(empty($mid)) {
            $mid = defined(‘MID‘) ? MID : session(‘mid‘);   //如果定义了常量MID说明是微信请求的 ,否则是本地
        }
        $token = S(‘access_token‘.$mid);
        if ($token === false)
        {
            if(empty(self::$member)) {
                self::$member = M(‘Member‘)->find($mid);
            }
            $url = ‘https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=‘.self::$member[‘appid‘].‘&secret=‘.self::$member[‘secret‘];
            $result = self::http_get($url);
            $result = json_decode($result, true);
            $token = $result[‘access_token‘];
            S(‘access_token‘.$mid, $token, $result[‘expires_in‘] - 1000);
        }
        return $token;
    }

    /**
     * 验证签名是否正确
     * @access public
     * @param $token
     */
    static public function checkSignature($token)
    {
        $tmpArr = array($token,$_GET ["timestamp"],$_GET ["nonce"]);
        sort($tmpArr, SORT_STRING );
        $tmpStr = sha1(implode( $tmpArr));
        if ($tmpStr == $_GET ["signature"])
        {
            ob_clean();
            echo $_GET ["echostr"];
        }
        self::addLog($_GET,4,‘微信接入‘);//记录日志
        exit;
    }

    /*************************************************** 发送消息响应微信 begin ***************************************************/
    /**
     * 回复文本消息
     * @param $content 文本内容
     * @access public
     * @return void
     */
    static public function replyText($content)
    {
        $msg [‘Content‘] = $content;
        self::_replyData ( $msg, ‘text‘ );
    }

    /**
     * 回复图片消息
     * @param $media_id MediaId
     */
    static public function replyImage($media_id)
    {
        $msg [‘Image‘] [‘MediaId‘] = $media_id;
        self::_replyData ( $msg, ‘image‘ );
    }

    /**
     * 回复语音消息
     * @param $media_id MediaId
     * @access public
     * @return void
     */
    static public function replyVoice($media_id)
    {
        $msg [‘Voice‘] [‘MediaId‘] = $media_id;
        $msg [‘Voice‘] [‘MediaId‘] = $media_id;
        self::_replyData ( $msg, ‘voice‘ );
    }

    /**
     * 回复视频消息
     * @param $media_id MediaId
     * @param string $title 标题
     * @param string $description 简介
     * @access public
     * @return void
     */
    static public function replyVideo($media_id, $title = ‘‘, $description = ‘‘)
    {
        $msg [‘Video‘] [‘MediaId‘] = $media_id;
        $msg [‘Video‘] [‘Title‘] = $title;
        $msg [‘Video‘] [‘Description‘] = $description;
        self::_replyData ( $msg, ‘video‘ );
    }

    /**
     * 回复音乐消息
     * @param $media_id MediaId
     * @param string $title 标题
     * @param string $description 简介
     * @param $music_url 音乐地址
     * @param $HQ_music_url 高品质音乐地址
     * @access public
     * @return void
     */
    static function replyMusic($media_id, $title = ‘‘, $description = ‘‘, $music_url, $HQ_music_url)
    {
        $msg [‘Music‘] [‘ThumbMediaId‘] = $media_id;
        $msg [‘Music‘] [‘Title‘] = $title;
        $msg [‘Music‘] [‘Description‘] = $description;
        $msg [‘Music‘] [‘MusicURL‘] = $music_url;
        $msg [‘Music‘] [‘HQMusicUrl‘] = $HQ_music_url;
        self::_replyData ( $msg, ‘music‘ );
    }

    /**
     * 回复图文消息 格式如下:
        array(
            array($Title, $Description, $PicUrl , $Url),
            array($Title, $Description, $PicUrl , $Url),
        );
     * @param array $articles
     * @access public
     * @return void
     */
    static public function replyNews($articles)
    {
        foreach($articles as $k=>$v)
        {
            $arr[] = array(‘Title‘=>$v[0],‘Description‘=>$v[1],‘PicUrl‘=>$v[2],‘Url‘=>$v[3]);
        }
        $msg [‘ArticleCount‘] = count ( $articles );
        $msg [‘Articles‘] = $arr;

        self::_replyData ( $msg, ‘news‘ );
    }

    /**
     * 将消息转发给客服
     * @param string $kf_account 指定客服的账号,不传则由微信分配
     * @access public
     * @return void
     */
    static public function replyKefu($kf_account=‘‘)
    {
        if(!empty($kf_account))
        {
            $msg [‘TransInfo‘][] = $kf_account;
        }
        self::_replyData($msg,‘transfer_customer_service‘,‘KfAccount‘);
    }

    /**
     * 发送回复消息到微信平台
     * @param array $msg 消息数组
     * @param $msgType 消息类型
     * @param string $item 包含子元素的元素名
     * @access private
     * @return void
     */
    static private function _replyData($msg, $msgType, $item = ‘item‘)
    {
        $msg [‘ToUserName‘] = strval(self::$fromUser);
        $msg [‘FromUserName‘] = strval(self::$toUser);
        $msg [‘CreateTime‘] = NOW_TIME;
        $msg [‘MsgType‘] = $msgType;
        if($_REQUEST [‘doNotInit‘])
        {
            dump($msg);
            exit;
        }
        $xml = new \SimpleXMLElement ( ‘<xml></xml>‘ );
        self::_data2xml ( $xml, $msg ,$item);
        $str = $xml->asXML ();
        self::addLog($str,2,‘发送消息‘);//记录日志
        echo $str;
    }

    /**
     * 组装xml数据
     * @param $xml xml对象
     * @param $data 要格式化的数组
     * @param string $item 包含子元素的元素名
     * @access public
     * @return void
     */
    static public function _data2xml($xml, $data, $item = ‘item‘)
    {
        foreach ( $data as $key => $value )
        {
            is_numeric ( $key ) && ($key = $item);
            if (is_array ( $value ) || is_object ( $value ))
            {
                $child = $xml->addChild ( $key );
                self::_data2xml ( $child, $value, $item );
            } else
            {
                if (is_numeric ( $value ))
                {
                    $child = $xml->addChild ( $key, $value );
                } else {
                    $child = $xml->addChild ( $key );
                    $node = dom_import_simplexml ( $child );
                    $node->appendChild ( $node->ownerDocument->createCDATASection ( $value ) );
                }
            }
        }
    }
    /*************************************************** 发送消息响应微信 end ***************************************************/

    /*************************************************** 上传下载文件 begin ***************************************************/
    /**
     * 上传临时素材
     * @param $file 要发送的文件
     * @param string $type 文件类型
     * @access public
     * @return mixed
     */
    static public function uploadFile($file, $type = ‘image‘)
    {
        // 媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb)
        $post_data = array(‘meida‘=>"@".$file,‘type‘=>$type);
        $url = "http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token=".self::getAcctoken() ."&type=".$type;
        return self::http_post($url,$post_data);
    }

    /* 上传永久素材*/
    static public function uploadYJFile($file, $type = ‘image‘)
    {
        // 媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb)
        $post_data = array(‘meida‘=>"@".$file,‘type‘=>$type);
        $url = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=".self::getAcctoken();
        return self::http_post($url,$post_data);
    }

    /**
     * 下载多媒体文件
     * @param $media_id MediaId
     * @access public
     * @return void
     */
    static public function downloadFile($media_id)
    {
        $url = ‘‘;
        $filename = date(‘Y-m-d_H_i_s‘,time()).‘.jpg‘;//设置保存的文件名
        $ch = curl_init ();
        curl_setopt ( $ch, CURLOPT_URL, $url );
        curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );
        curl_setopt ( $ch, CURLOPT_TIMEOUT, 60 );
        $temp = curl_exec($ch);
        if(@file_get_contents($filename,$temp) && !curl_errno($ch)) {
            echo $filename;
        }
        else  {
            echo false;
        } // TODO
    }
    /*************************************************** 上传下载文件 end ***************************************************/

    /*************************************************** 执行http请求方法 begin ***************************************************/
    /**
     * 发送GET 请求
     * @param string $url 地址
     * @access public
     * @return mixed
     */
    static public 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_URL, $url );
        curl_setopt ( $oCurl, CURLOPT_RETURNTRANSFER, 1 );
        $sContent = curl_exec ( $oCurl );
        $aStatus = curl_getinfo ( $oCurl );
        curl_close ( $oCurl );
        return intval ( $aStatus ["http_code"] ) == 200 ? $sContent : false;
    }

    /**
     * 发送POST 请求
     * @param string $url 地址
     * @param array $param 参数
     * @access public
     * @return string content
     */
    static public function http_post($url, $param)
    {
        $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_URL, $url );
        curl_setopt ( $oCurl, CURLOPT_RETURNTRANSFER, 1 );
        curl_setopt ( $oCurl, CURLOPT_POST, true );
        curl_setopt ( $oCurl, CURLOPT_POSTFIELDS, $param );
        $sContent = curl_exec ( $oCurl );
        $aStatus = curl_getinfo ( $oCurl );
        curl_close ( $oCurl );
        return intval ( $aStatus ["http_code"] ) == 200 ? $sContent : false;
    }
    /*************************************************** 执行http请求方法 end ***************************************************/

    /*************************************************** 记录日志 begin ***************************************************/
    /**
     * @param $data 要记录的内容
     * @param int $type 日志类型(1:Receive,2:Send,3:Sql,4:Signature)
     * @param string $comment 备注信息
     * @return null
     */
    static public function addLog($data,$type=1,$comment=‘‘)
    {
        //日志存放文件夹名
        $dirName = array(‘1‘ => ‘Receive‘,‘2‘ => ‘Send‘,‘3‘ => ‘Sql‘,‘4‘=>‘Signature‘);

        //构造日志文件名
        $logDir = sprintf(self::LOG_DIR, $dirName[$type]); //格式化文件夹
        $logName = sprintf(self::LOG_NAME,date(‘ymd‘));            //格式化文件名
        if(!is_dir($logDir)) mkdir($logDir,0777,true);             //如果文件夹不存在,创建
        $logFile = $logDir.$logName;                                //日志最终文件名

        //构造日志文件内容
        $separator = str_repeat(‘*‘,42);
        $content[] = "/$separator <- Begin:".date(‘Y-m-d H:i:s‘)." --> $separator/";
        $content[] = trim(var_export($data,true),‘\‘‘);
        if(!empty($comment)) $content[] = ‘备注: ‘.$comment;
        $content[] = "/$separator <------------  End ------------> $separator/";
        $logContent =   PHP_EOL.implode(PHP_EOL,$content);

        //写入日志文件
        $fp = fopen($logFile,"a+");
        flock($fp, LOCK_EX) ;
        fwrite($fp,$logContent);
        flock($fp, LOCK_UN);
        fclose($fp);
    }
    /*************************************************** 记录日志 end ***************************************************/

    /*************************************************** oAuth网页授权获取用户信息 begin ***************************************************/

    /**
     * 网页授权获取用户信息
     * @param $type 类型为openid或者userinfo
     * @return mixed
     */
    public static function oAuthGet($type)
    {
        if (!isset($_GET[‘code‘]))
        {
            //获取code码,以获取openid
            $scopeArr = array(‘openid‘=>‘snsapi_base‘,‘userinfo‘=>‘snsapi_userinfo‘);
            $scope = $scopeArr[$type];
            $redirect_url = urlencode(‘http://‘.$_SERVER[‘HTTP_HOST‘].$_SERVER[‘PHP_SELF‘].$_SERVER[‘QUERY_STRING‘]);
            $url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=".self::$member[‘appid‘]."&redirect_uri=$redirect_url&response_type=code&scope=$scope&state=oAuthInfo#wechat_redirect";
            header ( ‘Location: ‘ . $url );
        }
        else
        {
            /******************* 1.回调页面得到code *******************/
            $code = $_GET[‘code‘];
            /******************* 2.用code去获取access_token和openid *******************/
            $url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=".self::$member[‘appid‘]."&secret=".self::$member[‘secret‘]."&code=$code&grant_type=authorization_code";
            $result = self::http_get($url);
            $result = json_decode($result,true);
            $openid =  $result[‘openid‘];
            if($result[‘scope‘] == ‘snsapi_base‘)   //如果类型是snsapi_base,只返回openid
                return $openid;
            else
            {
                $access_token = $result[‘access_token‘];    //access_token
                /******************* 3.用获取到的openid和access_token获取获取用户详细信息 *******************/
                $url = "https://api.weixin.qq.com/sns/userinfo?access_token=$access_token&openid=$openid&lang=zh_CN";
                $result = self::http_get($url);
                return json_decode($result,true);
            }
        }

    }
    /*************************************************** oAuth网页授权获取用户信息 end ***************************************************/

    /*************************************************** 获取jssdk配置 begin ***************************************************/

    /**
     * 获取 JSSDK 配置
     * @param bool $debug 是否开启调试模式
     * @access public
     * @return array
     */
    public static function getJssdkConf($debug = false) {
        $data = array(
            ‘noncestr‘ => self::createNonceStr(),
            ‘jsapi_ticket‘ => self::getJsApiTicket(),
            ‘timestamp‘ => time(),
            ‘url‘ => SERVER.__SELF__,
        );
        $str = ‘jsapi_ticket=‘.$data[‘jsapi_ticket‘].‘&noncestr=‘.$data[‘noncestr‘].‘&timestamp=‘.$data[‘timestamp‘].‘&url=‘.$data[‘url‘];
        return array(
            ‘debug‘	    => $debug,
            ‘appId‘		=> self::$member[‘appid‘],
            ‘timestamp‘	=> $data[‘timestamp‘],
            ‘nonceStr‘	=> $data[‘noncestr‘],
            ‘signature‘	=> sha1($str),
        );
    }

    private static function getJsApiTicket() {
        $mid = self::$member[‘id‘];
        $ticket = S(‘jsapi_ticket‘.$mid);
        if ($ticket == false) {
            $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=".self::getAcctoken($mid);
            $result =WeChat::http_get($url);
            $result = json_decode($result, true);
            $ticket = $result[‘ticket‘];
            S(‘jsapi_ticket‘.$mid, $ticket, $result[‘expires_in‘] - 1000);
        }
        return $ticket;
    }

    private static function createNonceStr($length = 16) {
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }
    /*************************************************** 获取jssdk配置 end ***************************************************/

}

回复微信控制器:WeChatController

<?php
namespace Manage\Controller;
use Think\Controller;
use \Org\WeChat;
class WeChatController extends Controller
{
    /* 接收微信的消息 */
    public function index()
    {
        $id = intval(I(‘get.id‘));
        $info = M(‘Member‘)->where("status=‘1‘")->find($id);
        if (!is_array($info)) exit(‘请求无效!‘);
        if (!empty ($_GET [‘echostr‘]) && !empty ($_GET ["signature"]) && !empty ($_GET ["nonce"])) {
            WeChat::checkSignature($info[‘token‘]);  //微信接入验证
        }
        define(‘MID‘, $id);                         //定义公众号常量MID
        WeChat::process(array($this, ‘reply‘));    //处理消息
    }

    /* 回复微信消息  */
    public function reply($messageType, $data)
    {
        $controller = ‘Process‘ . ‘\\Controller\\‘ . $messageType . ‘Controller‘;
        $class = new \ReflectionClass($controller);
        $method = $class->getMethod(‘run‘);
        $instance = $class->newInstance();
        $method->invokeArgs($instance, array($data));
    }
}

WeChat控制器,负责将请求分发给Process模块下对应控制器处理, 如Click类型由ClickController处理, Text类型由TextController处理,下面给出一个TextController控制器

<?php
namespace Process\Controller;
use \Org\WeChat;

class TextController extends ProcessController
{
    /* 用户点击菜单 */
    public function run($data)
    {
            WeChat::replyText("您输入的内容是:" .$data[‘Content‘]);
        }
    }

}

oAuth网页授权获取用户信息示例TestController

<?php
namespace Test\Controller;
use Think\Controller;
use \Org\WeChat;
class TestController extends Controller
{
    /* 获取用户openid */
    public function get_openid()
    {
        WeChat::setMember(2);
        $openid =  WeChat::oAuthGet(‘openid‘);
    }

    /* 获取用户信息 */
    public function get_userInfo()
    {
        WeChat::setMember(2);
        $userinfo = WeChat::oAuthGet(‘userinfo‘);
        var_dump($userinfo);
    }
}
时间: 2024-10-04 03:25:01

自己写的微信公众号开发模型WeChat (回复参考weiphp)的相关文章

微信公众号开发模型WeChat

模型:WeChat (回复参考weiphp) <?php namespace Org; /** * 微信开发工具类 * Class WeChat * Author chenqionghe * @package Org */ class WeChat { const LOG_NAME = "PHP_LOG_%s.log.php"; //日志名 const LOG_DIR = "./Log/%s/"; //日志目录 static private $fromUser

微信公众号开发中遇到的几个bug

一.测试自定义菜单接口时中文菜单名显示为null 设置的中文菜单名,中文未经过编码和解码过程,设置的中文菜单名在最后的微信服务器返回的json格式数据中显示为null. 解决办法:将中文先用unecode方法编码,最后再将菜单数组用undecode解码,再传给微信服务器.方法最上面加上header("content-type=text/html;charset=utf-8"),编码方式必须是utf-8,才能在微信公众平台在线测试接口. 二.自定义菜单中的菜单类型type="c

PHP微信公众号开发常用功能

最近学习了关于微信公众号开发的相关知识,为了帮助自己更好的理解,在此重新再梳理一遍 更多关于微信公众号开发的功能可以参考微信公众平台的开发技术文档 完成开发者配置 第一步,需要在微信公众平台配置我们的服务器  在接口的文件需要写入以下代码以完成验证: class Wxapi { public function __construct() { $this->index(); } public function index() { $echostr = isset($_GET['echostr'])

《初识Java微信公众号开发》 学习中遇到的困难

前一段时间无聊的时候,在慕课网上自学了一点点微信公众号开发(受学姐威胁). 慕课网教程的地址:http://www.imooc.com/learn/368 毕竟是免费的课程,不可能讲的那么详细.所以我吧我遇到的问题跟大家分享一下. 这是我照着课程敲的代码(IDE是Eclipse): https://github.com/Zuosy/WeiXin 发到github上面了. 为了这个,我还专门到廖大的网站上学了一遍Git. 廖大的Git教程传送们:https://www.liaoxuefeng.co

利用OpenShift托管Node.js Web服务进行微信公众号开发

最近写了一个微信的翻译机器人.用户只要关注该微信号,发送英文的消息,就能收到中文翻译的回复.后台是用Node.js写的,托管在OpenShift的Paas平台上.翻译过程实际上是调用微软的Bing translation API做的,代码中用到了alexu84的bing-translate和JacksonTian的wechat这两个npm模块.下面把做的过程详细说一下. 1. 微信公众号开发 首先是要到https://mp.weixin.qq.com 申请一个公众号,并申请成为开发者.目前个人只

微信公众号开发系列教程一(调试环境部署)

原文:微信公众号开发系列教程一(调试环境部署) 目录 C#微信公众号开发系列教程一(调试环境部署) C#微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) 微信公众号火了好一阵子了,笔者算是比较早接触微信公众号开发的了,大概做了一年半了,从最开始的到处网上找demo到现在也开发一些公众号.园子里关于微信开发的教程已经数不胜数了,我也准备来凑凑热闹.一是梳理下这段时间开发的经验,二是希望能帮到想做微信开发的小伙伴们,希望大大神们吐槽的时候悠着点,

C#微信公众号开发系列教程二(新手接入指南)

http://www.cnblogs.com/zskbll/p/4093954.html 此系列前面已经更新了两篇博文了,都是微信开发的前期准备工作,现在切入正题,本篇讲解新手接入的步骤与方法,大神可直接跳过,也欢迎大神吐槽. 目录 C#微信公众号开发系列教程一(调试环境部署) C#微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) 微信公众平台消息接口的工作原理大概可以这样理解:从用户端到公众号端一个流程是这样的,用户发送消息到微信服务器,微

微信公众号开发入门笔记(一):知识及技术路线图

注:本系列博客所使用的编程语言为Java,内容主要来自于慕课网课程:初识Java微信公众号开发(课程链接:http://www.imooc.com/learn/368)的学习收获和总结. 因为微信的大规模普及性,微信公众号开发可以开发出跨平台使用的功能,并且使用起来简单方便.个人使用Java作为工作语言,对Java比较熟悉,所以本系列的笔记采用Java语言来进行开发.此外,慕课网的课程"初识Java微信公众号开发"为我带来了很大的启发,很适合想要做微信公众平台开发的朋友们的入门. 那么

微信公众号开发系列教程一(调试环境部署续:vs远程调试)

原文:微信公众号开发系列教程一(调试环境部署续:vs远程调试) 目录 C#微信公众号开发系列教程一(调试环境部署) C#微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) 前几天决定写个微信公众平台开发系列,在发布第一篇博文后,收到了很多园友的反馈和建议,在这里感谢大家的支持,我会坚持写完这个系列,希望能帮助更多的小伙伴.特别要感谢下@ZIP,是他的一个提醒才有了这篇博文.也希望更多的小伙伴能把你的想法反馈给我. 上一篇中主要介绍的是使用花生壳