文档
环境要求:
- PHP >= 7.0
- PHP cURL 扩展
- PHP OpenSSL 扩展
- PHP SimpleXML 扩展
- PHP fileinfo 拓展
使用 composer:
$ composer require overtrue/wechat:~4.0 -vvv
Laravel 5 拓展包: overtrue/laravel-wechat
公众号的各模块相对比较统一,用法如下:
use EasyWeChat\Factory;
$config = [
'app_id' => 'wx3cf0f39249eb0exx',
'secret' => 'f1c242f4f28f735d4687abb469072axx',
// 指定 API 调用返回结果的类型:array(default)/collection/object/raw/自定义类名
'response_type' => 'array',
//...
];
$app = Factory::officialAccount($config);
$app
在所有相关公众号的文档都是指 Factory::officialAccount
实例,就不在每个页面单独写了。
安装完成后,即可很快的开始使用它了。
以服务器端验证与接收响应用户消息为例,首先要了解下微信交互的运行流程:
+------+ +---------------+ +-------------+
| |--->| |-post/get/put->| |
| user | | wechat server | | your server |
| |<---| |<--------------| |
+------+ +---------------+ +-------------+
那要做的就是图中微信服务器把用户消息转到自有服务器(虚线返回部分)后的处理过程。
在微信接入开始有个 “服务器验证” 的过程,这一步就是微信服务器向自有服务器发起个请求(上图实线部分),传了个名称为 echostr
字符串过来,只需原样返回就好了。
微信后台只能填写一个服务器地址,所以 服务器验证与消息的接收与回复,都在这个链接内完成交互。
考虑到这些,把验证这步给封装到 SDK 里,可完全忽略这步。
下面来配置个基本的服务端,假设自有服务器域名叫 easywechat.com
,在服务器上准备个文件server.php
:
// server.php
use EasyWeChat\Factory;
$config = [
'app_id' => 'wx3cf0f39249eb0xxx',
'secret' => 'f1c242f4f28f735d4687abb469072xxx',
'token' => 'TestToken',
'response_type' => 'array',
//...
];
$app = Factory::officialAccount($config);
$response = $app->server->serve();
// 将响应输出
$response->send();exit; // Laravel 里请使用:return $response;
❤ 安全模式下一定要配置
aes_key
一个服务端带验证功能的代码已完成,对消息的处理后面再讲。
先分析上面代码:
// 引入我们的主项目工厂类。
use EasyWeChat\Factory;
// 一些配置
$config = [...];
// 使用配置来初始化一个公众号应用实例。
$app = Factory::officialAccount($config);
$response = $app->server->serve();
// 将响应输出
$response->send(); exit; // Laravel 请用:return $response;
最后这行有必要详细讲一下:
$app->server->serve()
是执行服务端业务,它的返回值是个Symfony\Component\HttpFoundation\Response
实例。- 这里是直接调用它的
send()
方法,即直接输出(echo),在一些框架不能直接输出,那就直接拿到 Response 实例后做相应的操作即可,如 Laravel 可直接return $app->server->serve();
有了上面代码,按 微信官方的接入指引 在公众号后台完成配置并启用,并相应修改上面的 $config
的相关配置。
URL 是
http://easywechat.com/server.php
,这里我是举例哦。
这样,点击提交验证就OK了。
一定要将微信后台的开发者模式 “启用” ,看到红色 “停用” 才真正启用。 最后,不要用浏览器访问这个地址,它是给微信服务器访问的。
服务端验证通过了,就来试下接收消息吧。
上面代码最后一行
$app->server->serve()->send();
前面调用$app->server
的push()
来注册消息处理器,这里用了 PHP 闭包 。
// ...
$app->server->push(function ($message) {
return "您好!欢迎使用 EasyWeChat!";
});
$response = $app->server->serve();
// 将响应输出
$response->send(); // Laravel 里请使用:return $response;
注意:send() 方法已包含 echo ,请不要再加 echo 在前面。
打开你的微信客户端,向你的公众号发送任意一条消息,会收到回复:您好!欢迎使用 EasyWeChat!
。
没收到回复?看到“你的公众号暂时无法提供服务” ?那检查下日志吧,配置里写了日志路径了(
__DIR__.'/wechat.log'
)。{warning} 注意:在 Laravel 框架应用时,因 POST 请求默认有 CSRF 验证,所以要在
App\Http\Middleware\VerifyCsrfToken
的except
数组中添加微信请求,否则会提示“你的公众号暂时无法提供服务”。
一个基本的服务端验证就完成了。
所有的应用服务都通过主入口 EasyWeChat\Factory
类来创建:
// 公众号
$app = Factory::officialAccount($config);
// 小程序
$app = Factory::miniProgram($config);
// 开放平台
$app = Factory::openPlatform($config);
// 企业微信
$app = Factory::work($config);
// 企业微信开放平台
$app = Factory::openWork($config);
// 微信支付
$app = Factory::payment($config);
常用的配置参数较少,因为除非有特别的定制,否则基本上默认值就可以:
use EasyWeChat\Factory;
$config = [
'app_id' => 'wx3cf0f39249eb0exx',
'secret' => 'f1c242f4f28f735d4687abb469072axx',
'response_type' => 'array', // 指定 API 调用返回结果的类型:array(default)/collection/object/raw/自定义类名
//...
];
$app = Factory::officialAccount($config);
下面是个完整的配置样例:
不建议在配置时弄这么多,因为大部分用默认值即可。
return [
/**
* 账号基本信息,请从微信公众平台/开放平台获取
*/
'app_id' => 'your-app-id', // AppID
'secret' => 'your-app-secret', // AppSecret
'token' => 'your-token', // Token
'aes_key' => '', // EncodingAESKey,兼容与安全模式下请一定要填写!!!
/**
* 指定 API 调用返回结果的类型:array(default)/collection/object/raw/自定义类名
* 使用自定义类名时,构造函数将会接收一个 `EasyWeChat\Kernel\Http\Response` 实例
*/
'response_type' => 'array',
/**
* 日志配置
* level: 日志级别, 可选为:debug/info/notice/warning/error/critical/alert/emergency
* path:日志文件位置(绝对路径!!!),要求可写权限
*/
'log' => [
'default' => 'dev', // 默认 channel,生产环境可改为下面的 prod
'channels' => [
// 测试环境
'dev' => [
'driver' => 'single',
'path' => '/tmp/easywechat.log',
'level' => 'debug',
],
// 生产环境
'prod' => [
'driver' => 'daily',
'path' => '/tmp/easywechat.log',
'level' => 'info',
],
],
],
/**
* 接口请求相关配置,超时时间等,具体参数请参考:
* http://docs.guzzlephp.org/en/stable/request-config.html
*
* - retries: 重试次数,默认 1,当 http 请求失败时重试次数。
* - retry_delay: 重试延迟间隔(单位:ms),默认 500
* - log_template: 指定 HTTP 日志模板,请参考:https://github.com/guzzle/guzzle/blob/master/src/MessageFormatter.php
*/
'http' => [
'max_retries' => 1,
'retry_delay' => 500,
'timeout' => 5.0,
// 'base_uri' => 'https://api.weixin.qq.com/', // 如果在国外想覆盖默认的 url 时才用,根据不同的模块配置不同的 uri
],
/**
* OAuth 配置
*
* scopes:公众平台(snsapi_userinfo / snsapi_base),开放平台:snsapi_login
* callback:OAuth授权完成后的回调页地址
*/
'oauth' => [
'scopes' => ['snsapi_userinfo'],
'callback' => '/examples/oauth_callback.php',
],
];
❤ 安全模式下请一定要填写
aes_key
可配置多个日志的 channel,每个 channel 的 driver
对应不同的日志驱动,内置可用 driver
如下表:
名称 | 描述 |
---|---|
stack |
复合型,可包含下面多种驱动的混合模式 |
single |
基于 StreamHandler 单一文件日志,参数有 path ,level |
daily |
基于 RotatingFileHandler 按日期生成日志文件,参数有 path ,level ,days (默认 7 天) |
slack |
基于 SlackWebhookHandler 的 Slack 组件,参数请参考源码:LogManager.php |
syslog |
基于 SyslogHandler Monolog 驱动,参数有 facility 默认为 LOG_USER ,level |
errorlog |
记录日志到系统错误日志,基于 ErrorLogHandler ,参数有 type ,默认 ErrorLogHandler::OPERATING_SYSTEM |
由于日志用的 Monolog,所以除默认文件式日志外,可自定义日志处理器:
use Monolog\Logger;
use Monolog\Handler\RotatingFileHandler;
// 注册自定义日志
$app->logger->extend('mylog', function($app, $config){
return new Logger($this->parseChannel($config), [
$this->prepareHandler(new RotatingFileHandler(
$config['path'], $config['days'], $this->level($config)
)),
]);
});
在自定义的闭包函数中,可用
EasyWeChat\Kernel\Log\LogManager
的方法,具体查看 SDK 源代码。
配置文件中在 driver
部分即可使用自定义的驱动:
'log' => [
'default' => 'dev', // 默认使用的 channel,生产环境可以改为下面的 prod
'channels' => [
// 测试环境
'dev' => [
'driver' => 'mylog',
'path' => '/tmp/easywechat.log',
'level' => 'debug',
'days' => 5,
],
//...
],
],
此接口官方有每月调用限制,不可随意调用
$app->base->clearQuota();
$app->base->getValidIps();
在入门小教程一节以服务端为例讲解了一个基本的消息的处理。
服务端的作用,在整个微信开发中主要是负责 接收用户发送过来的消息,还有 用户触发的一系列事件。
首先得理清消息与事件的回复逻辑,当收到用户消息后(消息由微信服务器推送到自有服务器),在对消息进行处理后,不管是选择回复消息还是什么不都回给用户,也应给微信服务器一个 “答复”,如果是选择回复一条消息,就直接返回一个消息xml,如果选择不作任何回复,也得回复个空字符串或字符串 SUCCESS
(不然用户会看到 该公众号暂时无法提供服务
)。
在 SDK 中用 $app->server->push(callable $callback)
设置消息处理器:
$app->server->push(function ($message) {
// $message['FromUserName'] // 用户的 openid
// $message['MsgType'] // 消息类型:event, text....
return "您好!欢迎使用 EasyWeChat";
});
// 在 laravel 中:
$response = $app->server->serve();
// $response 为 `Symfony\Component\HttpFoundation\Response` 实例
// 对于需要直接输出响应的框架,或原生 PHP 环境下
$response->send();
// 而 laravel 中直接返回即可:
return $response;
这里用 push
传入个 闭包(Closure),该闭包接收个参数 $message
为消息对象(类型取决于配置中 response_type
),可在全局消息处理器中对消息类型筛选:
$app->server->push(function ($message) {
switch ($message['MsgType']) {
case 'event':
return '收到事件消息';
break;
case 'text':
return '收到文字消息';
break;
case 'image':
return '收到图片消息';
break;
case 'voice':
return '收到语音消息';
break;
case 'video':
return '收到视频消息';
break;
case 'location':
return '收到坐标消息';
break;
case 'link':
return '收到链接消息';
break;
case 'file':
return '收到文件消息';
// ... 其它消息
default:
return '收到其它消息';
break;
}
// ...
});
因为这里 push
接收个 callable
的参数,所以不一定要传入个 Closure 闭包,可选择传入个函数名,一个 [$class, $method]
或 Foo::bar
类型。
某些情况,需直接用 $message
参数,那怎么在 push
的闭包外调用呢?
$message = $server->getMessage();
注意:
$message
类型取决于配置中response_type
有时要对消息记日志,或一系列的自定义操作,可注册多个 handler:
$app->server->push(MessageLogHandler::class);
$app->server->push(MessageReplyHandler::class);
$app->server->push(OtherHandler::class);
$app->server->push(...);
注意:
- 最后个非空返回值将作为最终应答给用户的消息内容,如果中间某 handler 返回 false, 则终止整个调用链,不调用后续 handlers。
- 传入自定义 Handler 类需实现
\EasyWeChat\Kernel\Contracts\EventHandlerInterface
。
对特定类型的消息应用不同的处理器,可在第二个参数传入类型筛选:
注意:参数二是
\EasyWeChat\Kernel\Messages\Message
类的常量。
use EasyWeChat\Kernel\Messages\Message;
$app->server->push(ImageMessageHandler::class, Message::IMAGE); // 图片消息
$app->server->push(TextMessageHandler::class, Message::TEXT); // 文本消息
// 同时处理多种类型的处理器
$app->server->push(MediaMessageHandler::class, Message::VOICE|Message::VIDEO|Message::SHORT_VIDEO); // 当消息为 三种中任意一种都可触发
当接收到用户的消息时,可能会提取消息中的相关属性,参考:
请求消息基本属性(以下所有消息都有的基本属性):
ToUserName
接收方帐号(该公众号 ID)FromUserName
发送方帐号(OpenID, 代表用户的唯一标识)CreateTime
消息创建时间(时间戳)MsgId
消息 ID(64位整型)
MsgType
textContent
文本消息内容
MsgType
imageMediaId
图片消息媒体id,可调用多媒体文件下载接口拉数据PicUrl
图片链接
MsgType
voiceMediaId
语音消息媒体id,可调用多媒体文件下载接口拉数据Format
语音格式,如 amr,speex 等Recognition
开通语音识别后才有注意,开通语音识别后,用户每次发送语音给公众号时,微信会在推送的语音消息XML数据包中,增加一个
Recongnition
字段
MsgType
videoMediaId
视频消息媒体id,可调用多媒体文件下载接口拉数据ThumbMediaId
视频消息缩略图的媒体id,可调用多媒体文件下载接口拉数据
MsgType
shortvideoMediaId
视频消息媒体id,可调用多媒体文件下载接口拉数据ThumbMediaId
视频消息缩略图的媒体id,可调用多媒体文件下载接口拉数据
MsgType
eventEvent
事件类型 (如:subscribe(订阅)、unsubscribe(取消订阅) …, CLICK 等)
EventKey
事件KEY值,如:qrscene_123123,qrscene_为前缀,后面为二维码的参数值Ticket
二维码的 ticket,可用来换取二维码图片
Latitude
23.137466 地理位置纬度Longitude
113.352425 地理位置经度Precision
119.385040 地理位置精度
EventKey
事件KEY值,与自定义菜单接口中KEY值对应,如:CUSTOM_KEY_001, www.qq.com
MsgType
locationLocation_X
地理位置纬度Location_Y
地理位置经度Scale
地图缩放大小Label
地理位置信息
MsgType
linkTitle
消息标题Description
消息描述Url
消息链接
MsgType
file Title
文件名 Description
文件描述,可能为null FileKey
文件KEY FileMd5
文件MD5值 FileTotalLen
文件大小,单位字节
回复的消息可为 null
,此时 SDK 会返回给微信一个 “SUCCESS”,也可回复个普通字符串,如:欢迎关注 overtrue.
,此时 SDK 会对它进行封装,产生个 EasyWeChat\Kernel\Messages\Text
类型消息并在最后的 $app->server->serve();
时生成对应的消息 XML 格式。
如果想返回手动拼的原生 XML 格式消息,请返回个 EasyWeChat\Kernel\Messages\Raw
实例。
参见:多客服消息转发
关于消息的使用,请参考 消息
章节。
把微信的 API 里的所有“消息”都按类型抽象出来,即不用区分它是回消息还是推送消息,免去手动拼装微信的 XML 及乱七八糟命名不统一的 JSON。
在阅读以下内容时请忽略是 接收消息 还是 回复消息,后面会讲它们的区别。
消息分:文本
、图片
、视频
、声音
、链接
、坐标
、图文
、文章
和特殊的 原始消息
。
另外还有种特殊的消息类型:素材消息,用于群发或客服时发送已有素材。
注意:回复消息与客服消息里的图文类型为:图文,群发与素材中的图文为文章
消息类都在 EasyWeChat\Kernel\Messages
命名空间下, 下面分开讲解:
属性列表:
content
文本内容
use EasyWeChat\Kernel\Messages\Text;
$text = new Text('您好!overtrue。');
// or
$text = new Text();
$text->content = '您好!overtrue。';
// or
$text = new Text();
$text->setAttribute('content', '您好!overtrue。');
属性列表:
- media_id 媒体资源 ID
use EasyWeChat\Kernel\Messages\Image;
$image = new Image($mediaId);
属性列表:
title
标题description
描述media_id
媒体资源 IDthumb_media_id
封面资源 ID
use EasyWeChat\Kernel\Messages\Video;
$video = new Video($mediaId, [
'title' => $title,
'description' => '...',
]);
属性列表:
media_id
媒体资源 ID
use EasyWeChat\Kernel\Messages\Voice;
$voice = new Voice($mediaId);
微信目前不支持回复链接消息
微信目前不支持回复坐标消息
图文消息分: NewsItem
与 News
,NewsItem
为图文内容条目。
10月12日起,被动回复消息与客服消息接口的图文消息类型中图文数目只能为一条
NewsItem
属性:
title
标题description
描述image
图片链接url
链接 URL
use EasyWeChat\Kernel\Messages\News;
use EasyWeChat\Kernel\Messages\NewsItem;
$items = [
new NewsItem([
'title' => $title,
'description' => '...',
'url' => $url,
'image' => $image,
// ...
]),
];
$news = new News($items);
属性列表:
title
标题author
作者content
具体内容thumb_media_id
图文消息的封面图片素材id(必须是永久mediaID)digest
图文消息的摘要,仅单图文消息才有摘要,多图文为空source_url
来源 URLshow_cover
是否显示封面,0 为 false不显示,1 为 true显示
use EasyWeChat\Kernel\Messages\Article;
$article = new Article([
'title' => 'EasyWeChat',
'author' => 'overtrue',
'content' => 'EasyWeChat 是一个开源的微信 SDK',
// ...
]);
// or
$article = new Article();
$article->title = 'EasyWeChat';
$article->author = 'overtrue';
$article->content = '微信 SDK ...';
// ...
素材消息用于群发与客服消息时使用。
素材消息不支持被动回复,如需被动回复素材消息,首先组装后,再 News 方法返回。
属性就一个:media_id
。
在构造时有两个参数:
$type
素材类型,支持:mpnews
、mpvideo
、voice
、image
等。
$mediaId
素材 ID,从接口查询或者上传后得到。
use EasyWeChat\Kernel\Messages\Media;
$media = new Media($mediaId, 'mpnews');
以上是所有微信支持的基本消息类型。
注意,无需关心微信的消息字段叫啥,因为这里用了更标准的命名,然后最终在中间做了转换。
原始消息是种特殊的消息,它的场景是:不想使用其它消息类型,想自己手动拼消息。如,回复消息时,自己拼 XML,那就直接用它就可以了:
use EasyWeChat\Kernel\Messages\Raw;
$message = new Raw('
12345678
');
如,要用于客服消息(客服消息是JSON结构):
use EasyWeChat\Kernel\Messages\Raw;
$message = new Raw('{
"touser":"OPENID",
"msgtype":"text",
"text":
{
"content":"Hello World"
}
}');
总之,直接写微信接口要求的格式内容就好,此类型消息在 SDK 中不存在转换行为,所以请注意不要写错格式。
在 服务端 一节中,讲了回复消息的写法:
// ... 前面部分省略
$app->server->push(function ($message) {
return "您好!欢迎关注我!";
});
$response = $server->serve();
上面 return
一句普通的文本内容,这里只为方便大家,实际上最后会有个隐式转换为 Text
类型的动作。
如果要回复其它类型消息,需返回个具体的实例,如回复个图片类型的消息:
use EasyWeChat\Kernel\Messages\Image;
// ...
$app->server->push(function ($message) {
return new Image('media-id');
});
// ...
10月12日起,被动回复消息与客服消息接口的图文消息类型中图文数目只能为一条
多图文消息就是单图文消息的一个数组而已了:
use EasyWeChat\Kernel\Messages\News;
use EasyWeChat\Kernel\Messages\NewsItem;
// ...
$app->server->push(function ($message) {
$news = new NewsItem(...);
return new News([$news]);
});
// ...
在客服消息里的使用也一样,都是直接传入消息实例即可:
use EasyWeChat\Kernel\Messages\Text;
$message = new Text('Hello world!');
$result = $app->customer_service->message($message)->to($openId)->send();
//...
10月12日起,被动回复消息与客服消息接口的图文消息类型中图文数目只能为一条
多图文消息其实就是单图文消息组成的一个 News 对象而已:
$news1 = new NewsItem(...);
$news = new News([$news1]);
$app->customer_service->message($news)->to($openId)->send();
请参考:群发消息
参见:多客服消息转发
多客服的消息转发绝对是超级的简单,转发的消息类型为 transfer
:
use EasyWeChat\Kernel\Messages\Transfer;
// 转发收到的消息给客服
$app->server->push(function($message) {
return new Transfer();
});
$response = $app->server->serve();
当然,也可指定转发给某个客服:
use EasyWeChat\Kernel\Messages\Transfer;
$app->server->push(function($message) {
return new Transfer($account);
});
微信的群发消息接口有各种注意事项及限制,具体请阅读微信官方文档。
以下所有方法均有第二个参数 $to
用于指定接收对象:
- 当
$to
为整型时为标签 id- 当
$to
为数组时为用户 openid 列表(至少两个用户的 openid)- 当
$to
为null
时表示全部用户
$app->broadcasting->sendMessage(Message $message, array | int $to = null);
下面的别名方法 sendXXX
是基于上面 sendMessage
方法的封装。
$app->broadcasting->sendText("大家好!欢迎使用 EasyWeChat。");
// 指定目标用户
// 至少两个用户的 openid,必须是数组。
$app->broadcasting->sendText("大家好!欢迎使用 EasyWeChat。", [$openid1, $openid2]);
// 指定标签组用户
$app->broadcasting->sendText("大家好!欢迎使用 EasyWeChat。", $tagId); // $tagId 必须是整型数字
$app->broadcasting->sendNews($mediaId);
$app->broadcasting->sendNews($mediaId, [$openid1, $openid2]);
$app->broadcasting->sendNews($mediaId, $tagId);
$app->broadcasting->sendImage($mediaId);
$app->broadcasting->sendImage($mediaId, [$openid1, $openid2]);
$app->broadcasting->sendImage($mediaId, $tagId);
$app->broadcasting->sendVoice($mediaId);
$app->broadcasting->sendVoice($mediaId, [$openid1, $openid2]);
$app->broadcasting->sendVoice($mediaId, $tagId);
用于群发的视频消息,需先创建消息对象,
// 1. 先上传视频素材用于群发:
$video = '/path/to/video.mp4';
$videoMedia = $app->media->uploadVideoForBroadcasting($video, '视频标题', '视频描述');
// 结果如下:
//{
// "type":"video",
// "media_id":"IhdaAQXuvJtGzwwc0abfXnzeezfO0NgPK6AQYShD8RQYMTtfzbLdBIQkQziv2XJc",
// "created_at":1398848981
//}
// 2. 使用上面得到的 media_id 群发视频消息
$app->broadcasting->sendVideo($videoMedia['media_id']);
$app->broadcasting->sendCard($cardId);
$app->broadcasting->sendCard($cardId, [$openid1, $openid2]);
$app->broadcasting->sendCard($cardId, $tagId);
openId
用户$app->broadcasting->previewText($text, $openId);
$app->broadcasting->previewNews($mediaId, $openId);
$app->broadcasting->previewVoice($mediaId, $openId);
$app->broadcasting->previewImage($mediaId, $openId);
$app->broadcasting->previewVideo($message, $openId);
$app->broadcasting->previewCard($cardId, $openId);
$wxanme 是用户微信号,如:notovertrue
$app->broadcasting->previewTextByName($text, $wxname);
$app->broadcasting->previewNewsByName($mediaId, $wxname);
$app->broadcasting->previewVoiceByName($mediaId, $wxname);
$app->broadcasting->previewImageByName($mediaId, $wxname);
$app->broadcasting->previewVideoByName($message, $wxname);
$app->broadcasting->previewCardByName($cardId, $wxname);
$app->broadcasting->delete($msgId);
$app->broadcasting->status($msgId);
模板消息仅用于公众号向用户发送重要的服务通知,只能用于符合其要求的服务场景中,如信用卡刷卡通知,商品购买成功通知等。不支持广告等营销类消息及其它所有可能对用户造成骚扰的消息。
$app->template_message->setIndustry($industryId1, $industryId2);
$app->template_message->getIndustry();
在公众号后台获取 $shortId
并添加到账户。
$app->template_message->addTemplate($shortId);
$app->template_message->getPrivateTemplates();
$app->template_message->deletePrivateTemplate($templateId);
$app->template_message->send([
'touser' => 'user-openid',
'template_id' => 'template-id',
'url' => 'https://easywechat.org',
'miniprogram' => [
'appid' => 'xxxxxxx',
'pagepath' => 'pages/xxx',
],
'data' => [
'key1' => 'VALUE',
'key2' => 'VALUE2',
...
],
]);
如果 url 和 miniprogram 字段都传,会优先跳转小程序。
$app->template_message->sendSubscription([
'touser' => 'user-openid',
'template_id' => 'template-id',
'url' => 'https://easywechat.org',
'scene' => 1000,
'data' => [
'key1' => 'VALUE',
'key2' => 'VALUE2',
...
],
]);
如果想为发送的内容字段指定颜色,可将 “data” 部分写成下面 4 种不同样式,不写
color
将默认黑色:
'data' => [
'foo' => '你好', // 不需要指定颜色
'bar' => ['你好', '#F00'], // 指定为红色
'baz' => ['value' => '你好', 'color' => '#550038'], // 与第二种一样
'zoo' => ['value' => '你好'], // 与第一种一样
]
用户信息的获取是微信开发中较常用的功能,以下所有的用户信息的获取与更新,都基于微信的 openid
,且是已关注当前账号,其它情况可能无法使用。
获取单个:
$user = $app->user->get($openId);
获取多个:
$users = $app->user->select([$openId1, $openId2, ...]);
$app->user->list($nextOpenId = null); // $nextOpenId 可选
示例:
$users = $app->user->list();
// result
{
"total": 2,
"count": 2,
"data": {
"openid": [
"OPENID1",
"OPENID2"
]
},
"next_openid": "NEXT_OPENID"
}
$app->user->remark($openId, $remark); // 成功返回boolean
示例:
$app->user->remark($openId, "僵尸粉");
$app->user->block('openidxxxxx');
// 或多个用户
$app->user->block(['openid1', 'openid2', 'openid3', ...]);
$app->user->unblock('openidxxxxx');
// 或多个用户
$app->user->unblock(['openid1', 'openid2', 'openid3', ...]);
$app->user->blacklist($beginOpenid = null); // $beginOpenid 可选
账号迁移从这里了解:https://kf.qq.com/product/weixinmp.html#hid=2488
微信用户关注不同的公众号,对应 OpenID 不一样,迁移成功后,粉丝的 OpenID 以目标帐号(即新公众号)对应的 OpenID 为准。但开发者可通过开发接口转换 OpenID,开发文档参考: 提供个 openid 转换的 API 接口,当帐号迁移后,可通过该接口:
原帐号:准备迁移的帐号,当审核完成且管理员确认后即被回收。
新帐号:接纳粉丝的帐号。新帐号在整个流程中均能正常使用。
一定要按照下面的步骤操作。
一定要在原帐号被冻结前,最好准备提交审核前,获取原帐号的用户列表。如果没有原帐号的用户列表,用不了转换工具。如果原账号被回收,这时也没办法调用接口获取用户列表。
{info} 如何获取用户列表见这里:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140840
转换 openid 的 API 接口如下,可在帐号迁移审核完成后开始调用,并最多保留15天。若帐号迁移没完成,调用时无返回结果或报错。帐号迁移15天后,该转换接口将会失效、无法拉取到数据。
$app->user->changeOpenid($oldAppId, $openidList);
返回值样例:
{
"errcode":0,
"errmsg":"ok",
"result_list":[
{
"ori_openid":"oEmYbwN-n24jxvk4Sox81qedINkQ",
"new_openid":"o2FwqwI9xCsVadFah_HtpPfaR-X4",
"err_msg":"ok"
},
{
"ori_openid":"oEmYbwH9uVd4RKJk7ZZg6SzL6tTo",
"err_msg":"ori_openid error"
}
]
}
$app->user_tag->list();
示例:
$tags = $app->user_tag->list();
// {
// "tags": [
// {
// "id": 0,
// "name": "标签1",
// "count": 72596
// },
// {
// "id": 1,
// "name": "标签2",
// "count": 36
// },
// ...
// ]
// }
$app->user_tag->create($name);
示例:
$app->user_tag->create('测试标签');
$app->user_tag->update($tagId, $name);
示例:
$app->user_tag->update(12, "新的名称");
$app->user_tag->delete($tagId);
$userTags = $app->user_tag->userTags($openId);
// {
// "tagid_list":["标签1","标签2"]
// }
$app->user_tag->usersOfTag($tagId, $nextOpenId = '');
// $nextOpenId:第一个拉取的OPENID,不填默认从头开始拉取
// {
// "count":2, // 这次获取的粉丝数量
// "data":{ // 粉丝列表
// "openid":[
// "ocYxcuAEy30bX0NXmGn4ypqx3tI0",
// "ocYxcuBt0mRugKZ7tGAHPnUaOW7Y"
// ]
// },
// "next_openid":"ocYxcuBt0mRugKZ7tGAHPnUaOW7Y"//拉取列表最后一个用户的openid
// }
$openIds = [$openId1, $openId2, ...];
$app->user_tag->tagUsers($openIds, $tagId);
$openIds = [$openId1, $openId2, ...];
$app->user_tag->untagUsers($openIds, $tagId);
OAuth是个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前版本是2.0版。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存直接上传(img-xvHNyPrS-1601215335631)(https://user-images.githubusercontent.com/1472352/29310178-5a7a91cc-81df-11e7-9468-b66e150bfba1.png)]
步骤解释:
(A)用户打开客户端以后,客户端要求用户给予授权。
(B)用户同意给予客户端授权。
(C)客户端使用上一步获得的授权,向认证服务器申请令牌。
(D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。
(E)客户端使用令牌,向资源服务器申请获取资源。
(F)资源服务器确认令牌无误,同意向客户端开放资源。
关于 OAuth 协议,请参考 Google 相关资料
微信的 OAuth 有两种:公众平台网页授权获取用户信息、开放平台网页登录。
它们区别有两处,授权地址不同,scope
不同。
公众平台网页授权获取用户信息 授权 URL:
https://open.weixin.qq.com/connect/oauth2/authorize
Scopes:snsapi_base
与snsapi_userinfo
开放平台网页登录 授权 URL:
https://open.weixin.qq.com/connect/qrconnect
Scopes:snsapi_login
他们的逻辑都一样:
/user/profile
scope
为 snsapi_base
时不显示)callback.php
并带上 code
: ?code=CODE&state=STATE
。callback.php
得到 code
后,通过 code
再次向微信服务器请求得到 网页授权 access_token 与 openid
openid
去请求 API 得到用户信息(可选)target_url
页面(/user/profile
)。看懵了?没事,使用 SDK,你不用管这么多。
注意,上面第3步:redirect_uri=callback.php在
callback.php
后会带上授权目标页面user/profile
,所以完整的redirect_uri
如下:'redirect_uri='.urlencode('callback.php?target=user/profile')
结果:redirect_uri=callback.php%3Ftarget%3Duser%2Fprofile
从上面描述的授权流程来看,至少有3个页面:
在开始前一定要记住,先登录公众号后台,找到边栏 “开发” 模块下的 “接口权限”,点击 “网页授权获取用户基本信息” 后的修改,添加网页授权域名。
如果授权地址为:
http://www.abc.com/xxxxx
,那请填写www.abc.com
,即请填写与网址匹配的域名,前者如果填写abc.com
是通过不了的。
在 SDK 中,用 oauth
模块来完成授权服务,主要用到以下两个 API:
$response = $app->oauth->scopes(['snsapi_userinfo'])
->redirect();
当应用是分布式架构且没有会话保持时,需自行设置请求对象以实现会话共享。如在 Laravel 框架中支持Session储存在Redis中,需这样:
$response = $app->oauth->scopes(['snsapi_userinfo'])
->setRequest($request)
->redirect();
//回调后获取user时也要设置$request对象
//$user = $app->oauth->setRequest($request)->user();
当然也可在发起授权时指定回调URL,如设置回调URL为当前页面:
$response = $app->oauth->scopes(['snsapi_userinfo'])
->redirect($request->fullUrl());
它的返回值 $response
是个 Symfony\Component\HttpFoundation\RedirectResponse 实例。
可选择在框架中做些正确响应,如在 Laravel 框架中控制器方法是要求返回响应值的:
return $response;
在有的框架 (如yii2) 中是直接 echo
或 $this->display()
时,就直接:
$response->send(); // Laravel 里请使用:return $response;
$user = $app->oauth->user();
// $user 可以用的方法:
// $user->getId(); // 对应微信的 OPENID
// $user->getNickname(); // 对应微信的 nickname
// $user->getName(); // 对应微信的 nickname
// $user->getAvatar(); // 头像网址
// $user->getOriginal(); // 原始API返回的结果
// $user->getToken(); // access_token, 比如用于地址共享时使用
$user
是 Overtrue\Socialite\User 对象,可从该对象拿到更多的信息。
注意:
$user
里没有openid
,$user->id
是openid
. 如果想拿微信返回的原样信息,请用:$user->getOriginal();
当 scope
为 snsapi_base
时 $oauth->user();
对象里只有 id
。
这里用原生 PHP 举例,oauth_callback
是授权回调URL (未urlencode编码的URL), user/profile
是需授权才能访问的页面,PHP 代码如下:
// http://easywechat.org/user/profile
use EasyWeChat\Factory;
$config = [
// ...
'oauth' => [
'scopes' => ['snsapi_userinfo'],
'callback' => '/oauth_callback',
],
// ..
];
$app = Factory::officialAccount($config);
$oauth = $app->oauth;
// 未登录
if (empty($_SESSION['wechat_user'])) {
$_SESSION['target_url'] = 'user/profile';
return $oauth->redirect();
// 这里不一定return,如果框架action不是返回内容就得用 $oauth->redirect()->send();
}
// 已登录过
$user = $_SESSION['wechat_user'];
授权回调页:
// http://easywechat.org/oauth_callback
use EasyWeChat\Factory;
$config = [
// ...
];
$app = Factory::officialAccount($config);
$oauth = $app->oauth;
// 获取 OAuth 授权结果用户信息
$user = $oauth->user();
$_SESSION['wechat_user'] = $user->toArray();
$targetUrl = empty($_SESSION['target_url']) ? '/' : $_SESSION['target_url'];
header('location:'. $targetUrl); // 跳转到 user/profile
上面例子都是基于 $_SESSION
保持会话,在微信客户端中,可结合 COOKIE 存储,但有效期平台不一样时间也不一样,Android 失效会快一些,不过基本也够用了。
微信 JSSDK 官方文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115
$app->jssdk->buildConfig(array $APIs, $debug = false, $beta = false, $json = true);
默认返回 JSON 字符串,当 $json
为 false
时返回数组,可直接用到网页中
$app->jssdk->setUrl($url)
如果不想用默认读取的URL,可用此方法手动设置,通常不需要。
示例
//可生成js配置文件:
<script src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
wx.config(<?php echo $app->jssdk->buildConfig(array('updateAppMessageShareData', 'updateTimelineShareData'), true) ?>);
</script>
结果如下:
<script src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
wx.config({
debug: true, // 请在上线前删除它
appId: 'wx3cf0f39249eb0e60',
timestamp: 1430009304,
nonceStr: 'qey94m021ik',
signature: '4F76593A4245644FAE4E1BC940F6422A0C3EC03E',
jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData']
});
</script>
上传的临时多媒体文件有格式和大小限制,如下:
图片(image): 2M,支持
JPG
格式语音(voice):2M,播放长度不超过
60s
,支持AMR\MP3
格式视频(video):10MB,支持
MP4
格式缩略图(thumb):64KB,支持
JPG
格式
注意:微信图片上传服务有敏感检测系统,图片内容如含有敏感内容,如色情,商品推广,虚假信息等,上传可能失败。
$app->media->uploadImage($path);
$app->media->uploadVoice($path);
$app->media->uploadVideo($path, $title, $description);
用于视频封面或音乐封面。
$app->media->uploadThumb($path);
上传视频获取 media_id
用以创建群发消息用。
$app->media->uploadVideoForBroadcasting($path, $title, $description);
//{
// "media_id": "rF4UdIMfYK3efUfyoddYRMU50zMiRmmt_l0kszupYh_SzrcW5Gaheq05p_lHuOTQ",
// "title": "TITLE",
// "description": "Description"
//}
不要与 上传群发视频 搞混了,上面是上传视频得到 media_id
,这个是用该 media_id
加标题描述 创建条消息素材 发送给用户。详情参见:消息群发
$app->media->createVideoForBroadcasting($mediaId, $title, $description);
//{
// "type":"video",
// "media_id":"IhdaAQXuvJtGzwwc0abfXnzeezfO0NgPK6AQYShD8RQYMTtfzbLdBIQkQziv2XJc",
// "created_at":1398848981
//}
如图片、语音等二进制流内容,响应为 EasyWeChat\Kernel\Http\StreamResponse
实例。
$stream = $app->media->get($mediaId);
if ($stream instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
// 以内容 md5 为文件名存到本地
$stream->save('保存目录');
// 自定义文件名,不需要带后缀
$stream->saveAs('保存目录', '文件名');
}
$stream = $app->media->getJssdkMedia($mediaId);
$stream->saveAs('保存目录', 'custom-name.speex');
目前有 2 种类型的二维码:
$result = $app->qrcode->temporary('foo', 6 * 24 * 3600);
// Array
// (
// [ticket] => gQFD8TwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyTmFjVTRWU3ViUE8xR1N4ajFwMWsAAgS2uItZAwQA6QcA
// [expire_seconds] => 518400
// [url] => http://weixin.qq.com/q/02NacU4VSubPO1GSxj1p1k
// )
$result = $app->qrcode->forever(56);// 或者 $app->qrcode->forever("foo");
// Array
// (
// [ticket] => gQFD8TwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyTmFjVTRWU3ViUE8xR1N4ajFwMWsAAgS2uItZAwQA6QcA
// [url] => http://weixin.qq.com/q/02NacU4VSubPO1GSxj1p1k
// )
$url = $app->qrcode->url($ticket);
// https://api.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET
$url = $app->qrcode->url($ticket);
$content = file_get_contents($url); // 得到二进制图片内容
file_put_contents(__DIR__ . '/code.jpg', $content); //写文件
使用场景: 开发者用于生成二维码的原链接(商品、支付二维码等)太长导致扫码速度和成功率下降,将原长链接通过此接口转成短链接再生成二维码将大大提升扫码速度和成功率。
$shortUrl = $app->url->shorten('https://easywechat.com');
//
(
[errcode] => 0
[errmsg] => ok
[short_url] => https://w.url.cn/s/Aq7jWrd
)
微信里的图片,音乐,视频等都需先上传到微信服务器作为素材才可在消息中使用。
注意:微信图片上传服务有敏感检测系统,图片内容如果含有敏感内容,如色情,商品推广,虚假信息等,上传可能失败。
$result = $app->material->uploadImage("/path/to/your/image.jpg");
// {
// "media_id":MEDIA_ID,
// "url":URL
// }
url
只有上传图片素材有返回值。
语音 大小不超 5M,长度不超 60 秒,支持 mp3/wma/wav/amr
格式。
$result = $app->material->uploadVoice("/path/to/your/voice.mp3");
// {
// "media_id":MEDIA_ID,
// }
$result = $app->material->uploadVideo("/path/to/your/video.mp4", "视频标题", "视频描述");
// {
// "media_id":MEDIA_ID,
// }
用于视频封面或者音乐封面。
$result = $app->material->uploadThumb("/path/to/your/thumb.jpg");
// {
// "media_id":MEDIA_ID,
// }
use EasyWeChat\Kernel\Messages\Article;
// 上传单篇图文
$article = new Article([
'title' => 'xxx',
'thumb_media_id' => $mediaId,
//...
]);
$app->material->uploadArticle($article);
// 或多篇图文
$app->material->uploadArticle([$article, $article2, ...]);
有三个参数:
$mediaId
更新文章的mediaId
$article
文章内容,Article
实例或 全字段数组$index
要更新的文章在图文消息中的位置(多图文消息时,此字段才有意义,单图片忽略此参数),第一篇为 0;
$result = $app->material->updateArticle($mediaId, new Article(...));
// or
$result = $app->material->updateArticle($mediaId, [
'title' => 'EasyWeChat 4.0 发布了!',
'thumb_media_id' => 'qQFxUQGO21Li4YrSn3MhnrqtRp9Zi3cbM9uBsepvDmE', // 封面图 mediaId
'author' => 'overtrue', // 作者
'show_cover' => 1, // 是否在文章内容显示封面图片
'digest' => '这里是文章摘要',
'content' => '这里是文章内容,你可以放很长的内容',
'source_url' => 'https://www.easywechat.com',
]);
// 指定更新多图文中的第 2 篇
$result = $app->material->updateArticle($mediaId, new Article(...), 1); // 第 2 篇
返回值中 url 是上传图片的 URL,可用于后续群发中,放置到图文消息中。
$result = $app->material->uploadArticleImage($path);
//{
// "url": "http://mmbiz.qpic.cn/mmbiz/gLO17UPS6FS2xsypf378iaNhWacZ1G1UplZYWEYfwvuU6Ont96b1roYsCNFwaRrSaKTPCUdBK9DgEHicsKwWCBRQ/0"
//}
$resource = $app->material->get($mediaId);
如果请求的素材为图文消息,则响应如下:
{
"news_item": [
{
"title":TITLE,
"thumb_media_id"::THUMB_MEDIA_ID,
"show_cover_pic":SHOW_COVER_PIC(0/1),
"author":AUTHOR,
"digest":DIGEST,
"content":CONTENT,
"url":URL,
"content_source_url":CONTENT_SOURCE_URL
},
//多图文消息有多篇文章
]
}
如果返回的是视频消息素材,则内容如下:
{
"title":TITLE,
"description":DESCRIPTION,
"down_url":DOWN_URL,
}
其他类型的素材消息,则响应为 EasyWeChat\Kernel\Http\StreamResponse
实例,开发者可自行保存为文件。如
$stream = $app->material->get($mediaId);
if ($stream instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
// 以内容 md5 为文件名
$stream->save('保存目录');
// 自定义文件名,不需要带后缀
$stream->saveAs('保存目录', '文件名');
}
$type
素材的类型,图片(image
)、视频(video
)、语音 (voice
)、图文(news
)$offset
从全部素材的该偏移位置开始返回,可选,默认0
,0 表示从第一个素材 返回$count
返回素材的数量,可选,默认20
, 取值在 1 到 20 间
$app->material->list($type, $offset, $count);
示例:
$list = $app->material->list('image', 0, 10);
图片、语音、视频 等类型的返回如下
{
"total_count": TOTAL_COUNT,
"item_count": ITEM_COUNT,
"item": [{
"media_id": MEDIA_ID,
"name": NAME,
"update_time": UPDATE_TIME,
"url":URL
},
//可能会有多个素材
]
}
永久图文消息素材列表的响应如下:
{
"total_count": TOTAL_COUNT,
"item_count": ITEM_COUNT,
"item": [{
"media_id": MEDIA_ID,
"content": {
"news_item": [{
"title": TITLE,
"thumb_media_id": THUMB_MEDIA_ID,
"show_cover_pic": SHOW_COVER_PIC(0 / 1),
"author": AUTHOR,
"digest": DIGEST,
"content": CONTENT,
"url": URL,
"content_source_url": CONTETN_SOURCE_URL
},
//多图文消息会在此处有多篇文章
]
},
"update_time": UPDATE_TIME
},
//可能有多个图文消息item结构
]
}
$stats = $app->material->stats();
// {
// "voice_count":COUNT,
// "video_count":COUNT,
// "image_count":COUNT,
// "news_count":COUNT
// }
$app->material->delete($mediaId);
文章预览请参阅 “消息群发” 章节。
$list = $app->menu->list();
$current = $app->menu->current();
$buttons = [
[
"type" => "click",
"name" => "今日歌曲",
"key" => "V1001_TODAY_MUSIC"
],
[
"name" => "菜单",
"sub_button" => [
[
"type" => "view",
"name" => "搜索",
"url" => "http://www.soso.com/"
],
[
"type" => "view",
"name" => "视频",
"url" => "http://v.qq.com/"
],
[
"type" => "click",
"name" => "赞一下我们",
"key" => "V1001_GOOD"
],
],
],
];
$app->menu->create($buttons);
以上会创建一个普通菜单。
与普通菜单不同,需在 create()
方法中将个性化匹配规则作为第二个参数:
$buttons = [
// ...
];
$matchRule = [
"tag_id" => "2",
"sex" => "1",
"country" => "中国",
"province" => "广东",
"city" => "广州",
"client_platform_type" => "2",
"language" => "zh_CN"
];
$app->menu->create($buttons, $matchRule);
有两种删除方式,一种是全部删除,另一种是根据菜单 ID 来删除(删除个性化菜单时用,ID 从查询接口获取):
$app->menu->delete(); // 全部
$app->menu->delete($menuId);
$app->menu->match($userId);
$userId
可是粉丝的 OpenID,也可是粉丝微信号。
返回 $menu
与指定的 $userId
匹配的菜单项。
$card = $app->card;
$card->colors();
$card->categories();
创建卡券接口,用于创建新卡券,获取card_id,创建成功并通过审核后,商家可通过接口将卡券下发给用户,每次成功领取,库存数量相应扣除。
$card->create($cardType = 'member_card', array $attributes);
attributes
array 卡券信息
示例:
$cardType = 'GROUPON';
$attributes = [
'base_info' => [
'brand_name' => '微信餐厅',
'code_type' => 'CODE_TYPE_TEXT',
'title' => '132元双人火锅套餐',
//...
],
'advanced_info' => [
'use_condition' => [
'accept_category' => '鞋类',
'reject_category' => '阿迪达斯',
'can_use_with_other_discount' => true,
],
//...
],
];
$result = $card->create($cardType, $attributes);
$cardInfo = $card->get($cardId);
$card->list($offset = 0, $count = 10, $statusList = 'CARD_STATUS_VERIFY_OK');
offset
int - 查询卡列表的起始偏移量,从0开始
count
int - 需要查询的卡片的数量
statusList
- 支持开发者拉出指定状态的卡券列表,详见 example
示例:
// CARD_STATUS_NOT_VERIFY, 待审核;
// CARD_STATUS_VERIFY_FAIL, 审核失败;
// CARD_STATUS_VERIFY_OK, 通过审核;
// CARD_STATUS_USER_DELETE,卡券被商户删除;
// CARD_STATUS_DISPATCH,在公众平台投放过的卡券;
$result = $card->list($offset, $count, 'CARD_STATUS_NOT_VERIFY');
支持更新所有卡券类型的部分通用字段及特殊卡券中特定字段的信息。
$card->update($cardId, $type, $attributes = []);
type
string - 卡券类型
示例:
$cardId = 'pdkJ9uCzKWebwgNjxosee0ZuO3Os';
$type = 'groupon';
$attributes = [
'base_info' => [
'logo_url' => 'http://mmbiz.qpic.cn/mmbiz/2aJY6aCPatSeibYAyy7yct9zJXL9WsNVL4JdkTbBr184gNWS6nibcA75Hia9CqxicsqjYiaw2xuxYZiaibkmORS2oovdg/0',
'center_title' => '顶部居中按钮',
'center_sub_title' => '按钮下方的wording',
'center_url' => 'http://www.easywechat.com',
'custom_url_name' => '立即使用',
'custom_url' => 'http://www.qq.com',
'custom_url_sub_title' => '6个汉字tips',
'promotion_url_name' => '更多优惠',
'promotion_url' => 'http://www.qq.com',
],
//...
];
$result = $card->update($cardId, $type, $attributes);
$card->delete($cardId);
开发者可调用该接口生成一张卡券二维码供用户扫码后添加卡券到卡包。
自定义 Code 码的卡券调用接口时,POST 数据需指定 code,非自定义 code 不需指定,指定 openid 同理。指定后的二维码只能被用户扫描领取一次。
$card->createQrCode($cards);
cards
array - 卡券相关信息
示例:
// 领取单张卡券
$cards = [
'action_name' => 'QR_CARD',
'expire_seconds' => 1800,
'action_info' => [
'card' => [
'card_id' => 'pdkJ9uFS2WWCFfbbEfsAzrzizVyY',
'is_unique_code' => false,
'outer_id' => 1,
],
],
];
$result = $card->createQrCode($cards);
// 领取多张卡券
$cards = [
'action_name' => 'QR_MULTIPLE_CARD',
'action_info' => [
'multiple_card' => [
'card_list' => [
['card_id' => 'pdkJ9uFS2WWCFfbbEfsAzrzizVyY'],
],
],
],
];
$result = $card->createQrCode($cards);
请求成功返回值示例:
{
"errcode": 0,
"errmsg": "ok",
"ticket": "gQHB8DoAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL0JIV3lhX3psZmlvSDZmWGVMMTZvAAIEsNnKVQMEIAMAAA==",//获取ticket后需调用换取二维码接口获取二维码图片,详情见字段说明。
"expire_seconds": 1800,
"url": "http://weixin.qq.com/q/BHWya_zlfioH6fXeL16o ",
"show_qrcode_url": "https://mp.weixin.qq.com/cgi-bin/showqrcode? ticket=gQH98DoAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL0czVzRlSWpsamlyM2plWTNKVktvAAIE6SfgVQMEgDPhAQ%3D%3D"
}
获取二维码 ticket 后,开发者可用 ticket 换取二维码图片。
$card->getQrCode($ticket);
ticket
string> - 获取的二维码 ticket,凭借此 ticket 可在有效时间内换取二维码。
示例:
$ticket = 'gQFF8DoAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL01VTzN0T0hsS1BwUlBBYUszbVN5AAIEughxVwMEAKd2AA==';
$result = $card->getQrCode($ticket);
$card->getQrCodeUrl($ticket);
示例:
$ticket = 'gQFF8DoAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL01VTzN0T0hsS1BwUlBBYUszbVN5AAIEughxVwMEAKd2AA==';
$card->getQrCodeUrl($ticket);
开发者需调用该接口创建货架链接,用于卡券投放。创建货架时需填写投放路径的场景字段。
$card->createLandingPage($banner, $pageTitle, $canShare, $scene, $cards);
banner
string -页面的 banner 图;pageTitle
string - 页面的 titlecanShare
bool - 页面是不是可以分享,true 或 falsescene
string - 投放页面的场景值,具体请参考下面的 examplecards
array - 卡券列表,每个元素有两个字段
示例:
$banner = 'http://mmbiz.qpic.cn/mmbiz/iaL1LJM1mF9aRKPZJkmG8xXhiaHqkKSVMMWeN3hLut7X7hicFN';
$pageTitle = '惠城优惠大派送';
$canShare = true;
//SCENE_NEAR_BY 附近
//SCENE_MENU 自定义菜单
//SCENE_QRCODE 二维码
//SCENE_ARTICLE 公众号文章
//SCENE_H5 h5页面
//SCENE_IVR 自动回复
//SCENE_CARD_CUSTOM_CELL 卡券自定义cell
$scene = 'SCENE_NEAR_BY';
$cardList = [
['card_id' => 'pdkJ9uLRSbnB3UFEjZAgUxAJrjeY', 'thumb_url' => 'http://test.digilinx.cn/wxApi/Uploads/test.png'],
['card_id' => 'pdkJ9uJ37aU-tyRj4_grs8S45k1c', 'thumb_url' => 'http://test.digilinx.cn/wxApi/Uploads/aa.jpg'],
];
$result = $card->createLandingPage($banner, $pageTitle, $canShare, $scene, $cardList);
注意:目前该接口仅支持填入非自定义 code 的卡券,自定义 code 的卡券需先进行 code 导入后调用。
$card->getHtml($cardId);
示例:
$cardId = 'pdkJ9uLCEF_HSKO7JdQOUcZ-PUzo';
$result = $card->getHtml($cardId);
同时支持“openid”、“username”两种字段设置白名单,总数上限为10个。
$card->setTestWhitelist($openids); // 使用 openid
$card->setTestWhitelistByName($usernames); // 使用 username
openids
array - 测试的openid列表usernames
array> - 测试的微信号列表
示例:
// by openid
$openids = [$openId, $openId2, $openid3...];
$result = $card->setTestWhitelist($openids);
// by username
$usernames = ['tianye0327', 'iovertrue'];
$result = $card->setTestWhitelistByName($usernames);
获取用户卡包里属于该appid下所有可用卡券,包括正常状态和未生效状态。
$card->getUserCards($openid, $cardId);
示例:
$openid = 'odkJ9uDUz26RY-7DN1mxkznfo9xU';
$cardId = ''; // 卡券ID。不填写时默认查询当前 appid 下的卡券。
$result = $card->getUserCards($openid, $cardId);
$card->setPayCell($cardId, $isOpen = true);
isOpen
string - 是否开启买单功能,填 true/false,默认 true
示例:
$cardId = 'pdkJ9uH7u11R-Tu1kilbaW_zDFow';
$result = $card->setPayCell($cardId); // isOpen = true
$result = $card->setPayCell($cardId, $isOpen);
$card->increaseStock($cardId, $amount); // 增加库存
$card->reductStock($cardId, $amount); // 减少库存
cardId
string - 卡券 IDamount
int - 修改多少库存
示例:
$cardId = 'pdkJ9uLRSbnB3UFEjZAgUxAJrjeY';
$result = $card->increaseStock($cardId, 100);
在自定义code卡券成功创建且通过审核后,必须将自定义code按照与发券方的约定数量调用导入code接口导入微信后台。
$card->code->deposit($cardId, $codes);
cardId
string - 要导入code的卡券IDcodes
array - 要导入微信卡券后台的自定义 code,最多100个
示例:
$cardId = 'pdkJ9uLCEF_HSKO7JdQOUcZ-PUzo';
$codes = ['11111', '22222', '33333'];
$result = $card->code->deposit($cardId, $codes);
$card->code->getDepositedCount($cardId); // 要导入 code 的卡券 ID
示例:
$cardId = 'pdkJ9uLCEF_HSKO7JdQOUcZ-PUzo';
$result = $card->code->getDepositedCount($cardId);
为避免出现导入差错,强烈建议开发者在查询完 code 数目时核查 code 接口校验 code 导入微信后台的情况。
$card->code->check($cardId, $codes);
示例:
$cardId = 'pdkJ9uLCEF_HSKO7JdQOUcZ-PUzo';
$codes = ['807732265476', '22222', '33333'];
$result = $card->code->check($cardId, $codes);
$card->code->get($code, $cardId, $checkConsume = true);
- checkConsume 是否校验code核销状态,true和false
示例:
$code = '736052543512';
$cardId = 'pdkJ9uDgnm0pKfrTb1yV0dFMO_Gk';
$result = $card->code->get($code, $cardId);
$result = $card->code->get($code, $cardId, false); // check_consume = false
$card->code->consume($code);
// 或指定 cardId
$card->code->consume($code, $cardId);
示例:
$code = '789248558333';
$cardId = 'pdkJ9uDmhkLj6l5bm3cq9iteQBck';
$result = $card->code->consume($code);
// 或
$result = $card->code->consume($code, $cardId);
$card->code->decrypt($encryptedCode);
示例:
$encryptedCode = 'XXIzTtMqCxwOaawoE91+VJdsFmv7b8g0VZIZkqf4GWA60Fzpc8ksZ/5ZZ0DVkXdE';
$result = $card->code->decrypt($encryptedCode);
$card->code->update($code, $newCode, $cardId);
newCode
string - 变更后的有效 Code 码
示例:
$code = '148246271394';
$newCode = '659266965266';
$cardId = '';
$result = $card->code->update($code, $newCode, $cardId);
$card->code->disable($code, $cardId);
示例:
$code = '736052543512';
$cardId = '';
$result = $card->code->disable($code, $cardId);
$result = $card->general_card->activate($info);
$result = $card->general_card->deactivate(string $cardId, string $code);
$result = $card->general_card->updateUser(array $info);
$result = $card->member_card->activate($info);
info
- 需激活的会员卡信息
示例:
$info = [
'membership_number' => '357898858', //会员卡编号,由开发者填入,作为序列号显示在用户的卡包里。可与Code码保持等值。
'code' => '916679873278', //创建会员卡时获取的初始code。
'activate_begin_time' => '1397577600', //激活后的有效起始时间。若不填写默认以创建时的 data_info 为准。Unix时间戳格式
'activate_end_time' => '1422724261', //激活后的有效截至时间。若不填写默认以创建时的 data_info 为准。Unix时间戳格式。
'init_bonus' => '持白金会员卡到店消费,可享8折优惠。', //初始积分,不填为0。
'init_balance' => '持白金会员卡到店消费,可享8折优惠。', //初始余额,不填为0。
'init_custom_field_value1' => '白银', //创建时字段custom_field1定义类型的初始值,限制为4个汉字,12字节。
'init_custom_field_value2' => '9折', //创建时字段custom_field2定义类型的初始值,限制为4个汉字,12字节。
'init_custom_field_value3' => '200', //创建时字段custom_field3定义类型的初始值,限制为4个汉字,12字节。
];
$result = $card->member_card->activate($info);
$card->member_card->setActivationForm($cardId, $settings);
settings
array - 会员卡激活时的选项
示例:
$cardId = 'pdkJ9uJYAyfLXsUCwI2LdH2Pn1AU';
$settings = [
'required_form' => [
'common_field_id_list' => [
'USER_FORM_INFO_FLAG_MOBILE',
'USER_FORM_INFO_FLAG_LOCATION',
'USER_FORM_INFO_FLAG_BIRTHDAY',
],
'custom_field_list' => [
'喜欢的食物',
],
],
'optional_form' => [
'common_field_id_list' => [
'USER_FORM_INFO_FLAG_EMAIL',
],
'custom_field_list' => [
'喜欢的食物',
],
],
];
$result = $card->member_card->setActivationForm($cardId, $settings);
$card->member_card->getUser($cardId, $code);
示例:
$cardId = 'pbLatjtZ7v1BG_ZnTjbW85GYc_E8';
$code = '916679873278';
$result = $card->member_card->getUser($cardId, $code);
$card->member_card->updateUser($info);
info
array - 可更新的会员信息
示例:
$info = [
'code' => '916679873278', //卡券Code码。
'card_id' => 'pbLatjtZ7v1BG_ZnTjbW85GYc_E8', //卡券ID。
'record_bonus' => '消费30元,获得3积分', //商家自定义积分消耗记录,不超过14个汉字。
'bonus' => '100', //需要设置的积分全量值,传入的数值会直接显示,如果同时传入add_bonus和bonus,则前者无效。
'balance' => '持白金会员卡到店消费,可享8折优惠。', //需要设置的余额全量值,传入的数值会直接显示,如果同时传入add_balance和balance,则前者无效。
'record_balance' => '持白金会员卡到店消费,可享8折优惠。', //商家自定义金额消耗记录,不超过14个汉字。
'custom_field_value1' => '100', //创建时字段custom_field1定义类型的最新数值,限制为4个汉字,12字节。
'custom_field_value2' => '200', //创建时字段custom_field2定义类型的最新数值,限制为4个汉字,12字节。
'custom_field_value3' => '300', //创建时字段custom_field3定义类型的最新数值,限制为4个汉字,12字节。
];
$result = $card->member_card->updateUser($info);
$card->sub_merchant->create(array $attributes);
示例:
$attributes = [
'brand_name' => 'overtrue',
'logo_url' => 'http://mmbiz.qpic.cn/mmbiz/iaL1LJM1mF9aRKPZJkmG8xXhiaHqkKSVMMWeN3hLut7X7hicFNjakmxibMLGWpXrEXB33367o7zHN0CwngnQY7zb7g/0',
'protocol' => 'qIqwTfzAdJ_1-VJFT0fIV53DSY4sZY2WyhkzZzbV498Qgdp-K5HJtZihbHLS0Ys0',
'end_time' => '1438990559',
'primary_category_id' => 1,
'secondary_category_id' => 101,
'agreement_media_id' => '',
'operator_media_id' => '',
'app_id' => '',
];
$result = $card->sub_merchant->create($attributes);
$card->sub_merchant->update(int $merchantId, array $info);
$merchantId
int - 子商户 ID$info
array - 参数与创建子商户参数一样
示例:
$info = [
//...
];
$result = $card->sub_merchant->update('12', $info);
$card->boarding_pass->checkin(array $params);
$card->meeting_ticket->updateUser(array $params);
$card->movie_ticket->updateUser(array $params);
$cards = [
['card_id' => 'pdkJ9uLRSbnB3UFEjZAgUxAJrjeY', 'outer_id' => 2],
['card_id' => 'pdkJ9uJ37aU-tyRj4_grs8S45k1c', 'outer_id' => 3],
];
$json = $card->jssdk->assign($cards); // 返回 json 格式
返回 json,在模板里的用法:
wx.addCard({
cardList: = $json ?>, // 需要打开的卡券列表
success: function (res) {
var cardList = res.cardList; // 添加的卡券列表信息
}
});
$card->jssdk->getTicket();
// 强制刷新
$card->jssdk->getTicket(true);
用 POI 接口新建门店时所用的图片 url 必须为微信自己域名的 url,因此需先用上传图片接口上传图片并获取 url,再创建门店。上传的图片限制文件大小限制 1MB,支持 JPG 格式,图片接口请参考:临时素材
$app->poi->create($baseInfo);
$baseInfo
为门店的基本信息数组
示例:
$info = array(
"sid" => "33788392",
"business_name" => "麦当劳",
"branch_name" => "艺苑路店",
"province" => "广东省",
"city" => "广州市",
"district" => "海珠区",
"address" => "艺苑路 11 号",
"telephone" => "020-12345678",
"categories" => array("美食,快餐小吃"),
"offset_type" => 1,
"longitude" => 115.32375,
"latitude" => 25.097486,
"photo_list" => array(
array("photo_url" => "https://XXX.com"),
array("photo_url" => "https://XXX.com"),
),
"recommend" => "麦辣鸡腿堡套餐,麦乐鸡,全家桶",
"special" => "免费 wifi,外卖服务",
"introduction" => "麦当劳是全球大型跨国连锁餐厅,1940 年创立于美国,在世界上大约拥有 3 万间分店。主要售卖汉堡包,以及薯条、炸鸡、汽水、冰品、沙拉、水果等 快餐食品",
"open_time" => "8:00-20:00",
"avg_price" => 35,
);
$result = $app->poi->create($info); // true or exception
注意:新创建的门店在审核通过后,会以事件形式推送给商户填写的回调 URL
$app->poi->get($poiId);
$poiId
为门店ID
示例:
$info = $app->poi->get(271262077);
$app->poi->list($begin, $limit);// begin:0, limit:10
$begin
就是查询起点,MySQL
里的offset
;$limit
查询条数,同MySQL
里的limit
;两参数均可选
示例:
$pois = $app->poi->list(0, 2);// 取2条记录
//
//[
// {
// "sid": "100",
// "poi_id": "271864249",
// "business_name": "麦当劳",
// "branch_name": "艺苑路店",
// "address": "艺苑路 11 号",
// "available_state": 3
// },
// {
// "sid": "101",
// "business_name": "麦当劳",
// "branch_name": "赤岗路店",
// "address": "赤岗路 102 号",
// "available_state": 4
// }
//]
商户可通过该接口,修改门店的服务信息,包括:图片列表、营业时间、推荐、特色服务、简 介、人均价格、电话 7 个字段。目前基础字段包括(名称、坐标、地址等不可修改)。
$app->poi->update($poiId, $data);
$poiId
为门店ID
$data
需更新的部分数据,若有填写内容则为覆盖更新,反之不修改,维持原内容。photo_list 字段为全列表覆盖,若要增加图片,需将之前图片放入 list 中,在其后增加新增图片。如:已有 A、B、C 三张图,又要增加 D、E 两张,则需调 用该接口,photo_list 传入 A、B、C、D、E 五张图片的链接。
示例:
$data = array(
"telephone" => "020-12345678",
"recommend" => "麦辣鸡腿堡套餐,麦乐鸡,全家桶",
//...
);
$res = $app->poi->update(271262077, $data); //true or exception
$app->poi->delete($poiId);
示例:
$app->poi->delete(271262077);// true or exception
使用客服系统可向用户发送消息及群发消息,客服的管理等功能。
$app->customer_service->list();
$app->customer_service->online();
$app->customer_service->create('foo@test', '客服1');
$app->customer_service->update('foo@test', '客服1');
$app->customer_service->delete('foo@test');
$app->customer_service->setAvatar('foo@test', $avatarPath); // $avatarPath 为本地图片路径,非 URL
$app->customer_service->messages($startTime, $endTime, $msgId = 1, $number = 10000);
示例:
$records = $app->customer_service->messages('2015-06-07', '2015-06-21', 1, 20000);
$app->customer_service->message($message)->to($openId)->send();
$message
为消息对象或文本,请参考:消息
示例:
$app->customer_service->message('hello')
> ->to('oV-gpwdOIwSI958m9osAhGBFxxxx')
> ->send();
$app->customer_service->message($message)
> ->from('account@test')
> ->to($openId)
> ->send();
$message
为消息对象或文本,请参考:消息
示例:
$app->customer_service->message('hello')
> ->from('kf2001@gh_176331xxxx')
> ->to('oV-gpwdOIwSI958m9osAhGBFxxxx')
> ->send();
以账号 foo@test
邀请 微信号 为 xxxx
的微信用户加入客服。
$app->customer_service->invite('foo@test', 'xxxx');
$app->customer_service_session->create('test1@test', 'OPENID');
$app->customer_service_session->close('test1@test', 'OPENID');
$app->customer_service_session->get('OPENID');
$app->customer_service_session->list('test1@test');
$app->customer_service_session->waiting();
摇一摇周边是微信在线下的全新功能, 为线下商户提供近距离连接用户的能力, 并支持线下商户向周边用户提供个性化营销、互动及信息推荐等服务。
$shakearound = $app->shake_around;
提醒: 1、下述接口调用的方法参数都要严格按照方法参数前的类型传入相应类型的实参,否则会得到非预期的结果。 2、涉及要传入设备id( d e v i c e I d e n t i f i e r ) 的 参 数 时 , 该 参 数 是 个 以 ‘ d e v i c e i d ‘ 或 含 ‘ u u i d ‘ ‘ m a j o r ‘ ‘ m i n o r ‘ 为 k e y 的 关 联 数 组 。 3 、 涉 及 要 传 入 设 备 i d 列 表 ( deviceIdentifier)的参数时,该参数是个以 `device_id` 或含 `uuid` `major` `minor` 为key的关联数组。 3、涉及要传入设备id列表( deviceIdentifier)的参数时,该参数是个以‘deviceid‘或含‘uuid‘‘major‘‘minor‘为key的关联数组。3、涉及要传入设备id列表(deviceIdentifiers)的参数时,该参数是个二维数组,第一层为索引类型,第二层为关联类型($deviceIdentifier)。
// 参数 $deviceIdentifier 的实参形式:
['device_id' => 10097]
// 或
[
'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825',
'major' => 10001,
'minor' => 12102,
]
// 参数$deviceIdentifiers的实参形式:
[
['device_id' => 10097],
['device_id' => 10098],
]
// 或
[
[
'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825',
'major' => 10001,
'minor' => 12102,
],
[
'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825',
'major' => 10001,
'minor' => 12103,
]
]
提示: 若不是做 公众号第三方平台 开发,建议直接在微信管理后台申请开通摇一摇周边功能。
申请开通摇一摇周边功能。成功提交申请请求后,工作人员会在三个工作日内完成审核。若审核不通过,可重新提交申请请求。若是审核中,请耐心等待工作人员审核,在审核中状态不能再提交申请请求。
方法
$shakearound->register($data)
注意: 1、相关资质文件的图片是使用本页面下方的素材管理的接口上传的,切勿和另一个 素材管理 接口混淆。 2、行业代码请务必传入字符串类型的实参,否则以数字0开头的行业代码将会被当成八进制数处理(将转换为十进制数),这可能不是期望的。
查询已提交的开通摇一摇周边功能申请的审核状态。在申请提交后,工作人员会在三个工作日内完成审核。
方法
$shakearound->status()
获取设备信息,包括UUID、major、minor,以及距离、openID等信息。
方法
$shakearound->user($ticket);
// 或者需要返回门店poi_id
$shakearound->user($ticket, true);
申请配置设备所需的UUID、Major、Minor。申请成功后返回批次ID,可用返回的批次ID通过“查询设备ID申请状态”接口查询目前申请的审核状态。 一个公众账号最多可申请100000个设备ID,如需申请的设备ID数超过最大限额,请邮件至[email protected],邮件格式如下:
标题:申请提升设备ID额度 内容: 1、公众账号名称及appid(wx开头的字符串,在mp平台可查看) 2、用途 3、预估需要多少设备ID
方法
$shakearound->device->apply($data)
查询设备ID申请的审核状态。若单次申请的设备ID数量小于等于500个,系统会快速审核;若单次申请的设备ID数量大于500个,则在三日内完成审核。
方法
$shakearound->device->status($applyId) // $applyId 批次ID,申请设备ID时所返回的批次ID
仅能修改设备的备注信息。
方法
$shakearound->device->update(array $deviceIdentifier, string $comment)
参数
$deviceIdentifier 设备id,设备编号device_id或UUID、major、minor的关联数组,若二者都填,则以设备编号为优先 $comment 设备的备注信息,不超过15个汉字或30个英文字母
示例
$result = $shakearound->device->update(['device_id' => 10011], 'test');
// 或
$result = $shakearound->device->update(['uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825',
'major' => 1002,
'minor' => 1223,
], 'test');
/* 返回结果
{
"data": {
},
"errcode": 0,
"errmsg": "success."
}
*/
var_dump($result['errcode']) // 0
关联本公众账号门店时,支持创建门店后直接关联在设备上,无需为审核通过状态,摇周边后台自动更新门店的最新信息和状态。 关联其他公众账号门店时,支持设备关联其他公众账号的门店,门店需为审核通过状态。
因为第三方门店不归属本公众账号,所以未保存到设备详情中,查询设备列表接口与获取摇周边的设备及用户信息接口不会返回第三方门店。
方法
$shakearound->device->bindPoi(array $deviceIdentifier, $poiId)
//或者 绑定第三方
$shakearound->device->bindThirdPoi(array $deviceIdentifier, $poiId, $poiAppId)
参数
$deviceIdentifier 设备 id,设备编号 device_id 或 UUID、major、minor 的关联数组,若二者都填,则以设备编号为优先 $poiId 设备关联的门店 ID,关联门店后,在门店 1KM 的范围内有优先摇出信息的机会。当值为0时,将清除设备已关联的门店 ID $poiAppId 关联门店所归属的公众账号的 APP ID
示例
// 关联本公众账号门店
$result = $shakearound->device->bindLocation(['device_id' => 10011], 1231);
// 或
$result = $shakearound->device->bindLocation([
'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825',
'major' => 1002,
'minor' => 1223,
], 1231);
// 关联其他公众账号门店
// wxappid 为关联门店所归属的公众账号的 APP ID
$result = $shakearound->device->bindThirdPoi(['device_id' => 10011], 1231, 'wxappid');
// 或
$result = $shakearound->device->bindThirdPoi([
'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825',
'major' => 1002,
'minor' => 1223,
], 1231, 'wxappid');
/* 返回结果
{
"data": {
},
"errcode": 0,
"errmsg": "success."
}
*/
查询已有设备 ID、UUID、Major、Minor、激活状态、备注信息、关联门店、关联页面等信息。
方法
$shakearound->device->listByIds(array $deviceIdentifiers)
参数
$deviceIdentifiers 设备id列表
示例
$result = $shakearound->device->listByIds([
['device_id' => 10097],
['device_id' => 10098],
]);
// 或
$result = $shakearound->device->listByIds([
[
'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825',
'major' => 10001,
'minor' => 12102,
],
[
'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825',
'major' => 10001,
'minor' => 12103,
]
]);
/* 返回结果
{
"data": {
"devices": [
{
"comment": "",
"device_id": 10097,
"major": 10001,
"minor": 12102,
"status": 1,
"last_active_time":1437276018,
"poi_id": 0,
"uuid": "FDA50693-A4E2-4FB1-AFCF-C6EB07647825"
},
{
"comment": "",
"device_id": 10098,
"major": 10001,
"minor": 12103,
"status": 1,
"last_active_time":1437276018,
"poi_appid":"wxe3813f5d8c546fc7"
"poi_id": 123,
"uuid": "FDA50693-A4E2-4FB1-AFCF-C6EB07647825"
}
],
"total_count": 151
},
"errcode": 0,
"errmsg": "success."
}
*/
方法
$shakearound->device->list(int $lastId, int $count)
参数
$lastId 前一次查询列表末尾的设备编号 device_id,第一次查询 lastId 为 0 $count 待查询的设备数量,不能超50个
示例
$result = $shakearound->device->list(10097, 3);
// 返回结果同上
方法
$shakearound->device->listByApplyId(int $applyId, int $lastId, int $count)
参数
$applyId 批次ID,申请设备ID时所返回的批次ID $lastId 前一次查询列表末尾的设备编号device_id,第一次查询 lastId 为 0 $count 待查询的设备数量,不能超50个
示例
$result = $shakearound->device->listByApplyId(1231, 10097, 3);
// 返回结果同上
新增摇一摇的页面信息,包括在摇一摇页面的主标题、副标题、图片和点击进去的超链接。图片必为用素材管理接口上传至微信侧服务器后返回的链接。
注意: 图片用本页下方的素材管理的接口上传的,切勿和另一个 素材管理 接口混淆。
方法
$shakearound->page->create($data)
参数
$title 摇一摇页面展示的主标题,不超6个汉字或12个英文字母 $description 摇一摇页面展示的副标题,不超7个汉字或14个英文字母 $pageUrl 点击进去的超链接 $iconUrl 在摇一摇页面展示的图片。图片需先上传至微信侧服务器,用“素材管理-上传图片素材”接口上传图片,返回的图片URL再配置在此处 $comment 可选,页面的备注信息,不超过15个汉字或30个英文字母
示例
$result = $shakearound->page->create($data);
/* 返回结果
{
"data": {
"page_id": 28840
}
"errcode": 0,
"errmsg": "success."
}
*/
编辑摇一摇的页面信息,包括在摇一摇页面出现的主标题、副标题、图片和点击进去的超链接。
方法
$shakearound->page->update(int $pageId, array $data)
参数
$pageId 摇周边页面唯一ID $data 需要更新的信息
示例
$result = $shakearound->page->update(28840, [
'title' => '主标题',
'description' => '副标题',
//...
]);
查询已有页面,包括在摇一摇页面出现的主标题、副标题、图片和点进去的超链接。
方法
$shakearound->page->listByIds(array $pageIds)
参数
$pageIds 页面的id列表,索引数组
示例
$result = $shakearound->page->listByIds([28840, 28842]);
/* 返回结果
{
"data": {
"pages": [
{
"comment": "just for test",
"description": "test",
"icon_url": "https://www.baidu.com/img/bd_logo1",
"page_id": 28840,
"page_url": "http://xw.qq.com/testapi1",
"title": "测试1"
},
{
"comment": "just for test",
"description": "test",
"icon_url": "https://www.baidu.com/img/bd_logo1",
"page_id": 28842,
"page_url": "http://xw.qq.com/testapi2",
"title": "测试2"
}
],
"total_count": 2
},
"errcode": 0,
"errmsg": "success."
}
*/
方法
$shakearound->page->list(int $begin, int $count)
参数
$begin 页面列表的起始索引值 $count 待查询的页面数,不能超50个
示例
$result = $shakearound->page->list(0,2);
// 返回结果同上
删除已有页面,包括在摇一摇页面的主标题、副标题、图片和点进去的链接。
注意: 只有页面与设备没有关联关系时,才可被删除。
方法
$shakearound->page->delete(int $pageId)
参数
$pageId 页面的id
示例
$result = $shakearound->page->delete(34567);
/* 返回结果
{
"data": {
},
"errcode": 0,
"errmsg": "success."
}
*/
上传在摇一摇功能用到的图片素材,素材保存在微信侧服务器上。图片格式限定为:jpg,jpeg,png,gif。 若图片为在摇一摇页面展示的图片,则其素材为 icon
类型的图片,图片大小建议 120px*120 px
,限制不超过 200 px *200 px
,图片需为 正方形
。 若图片为申请开通摇一摇周边功能需要上传的资质文件图片,则其素材为 license
类型的图片,图片的文件大小不超过 2MB
,尺寸不限,形状不限。
方法
$shakearound->material->uploadImage(string $path [, string $type = ‘icon’])
参数
$path 图片所在路径 $type 可选,值为icon或license
示例
$result = $shakearound->material->uploadImage(__DIR__ . '/stubs/image.jpg');
/* 返回结果
{
"data": {
"pic_url": http://shp.qpic.cn/wechat_shakearound_pic/0/1428377032e9dd2797018cad79186e03e8c5aec8dc/120"
},
"errcode": 0,
"errmsg": "success."
}
*/
通过接口申请的设备ID,需先配置页面,若未配置页面,则摇不出页面信息。
配置完成后,在此设备的信号范围内,即可摇出关联的页面信息。 若设备配置多个页面,则随机出现页面信息。一个设备最多可配置30个关联页面。
注意: 1、配置时传入该设备需关联的页面id列表,该设备原有的关联关系将被直接清除。 2、页面的id列表允许为空(传入空数组),当页面的id列表为空时则会清除该设备的所有关联关系。
方法
$shakearound->relation->bindPage(array $deviceIdentifier, array $pageIds)
参数
$deviceIdentifier 设备id,设备编号device_id或UUID、major、minor的关联数组,若二者都填,则以设备编号为优先 $pageIds 页面的id列表,索引数组
示例
$result = $shakearound->relation->bindPage(['device_id' => 10011], [12345, 23456, 334567]);
// 或
$result = $shakearound->relation->bindPage(['uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825', 'major' => 1002, 'minor' => 1223,], [12345, 23456, 334567]);
/* 返回结果
{
"data": {
},
"errcode": 0,
"errmsg": "success."
}
*/
var_dump($result->errcode) // 0
根据设备ID或完整UUID、Major、Minor查询该设备关联的所有页面信息
方法
$shakearound->relation->listByDeviceId(array $deviceIdentifier [, boolean $raw = false])
注意: 该方法默认对返回的数据处理后返回一个包含页面id的索引数组。若要返回和
getDeviceByPageId
方法类似的数据,请传入true
作为第二个参数。
参数
$deviceIdentifier 设备id,设备编号device_id或UUID、major、minor的关联数组,若二者都填,则以设备编号为优先 $raw 可选,当为true时,返回值和getDeviceByPageId方法类似,否则返回页面的id列表(索引数组,无关联时为空数组)
示例
$result = $shakearound->relation->listByDeviceId(['device_id' => 10011]);
// 或
$result = $shakearound->relation->listByDeviceId([
'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825',
'major' => 1002,
'minor' => 1223,
]);
// 返回结果
var_dump($result) // [50054,50055]
指定页面ID分页查询该页面所关联的所有的设备信息
方法
$shakearound->relation->listByPageId(int $pageId, int $begin, int $count)
参数
$pageId 指定的页面id $begin 关联关系列表的起始索引值 $count 待查询的关联关系数量,不能超过50个
示例
$result = $shakearound->relation->listByPageId(50054, 0, 3);
/* 返回结果
{
"data": {
"relations": [
{
"device_id": 797994,
"major": 10001,
"minor": 10023,
"page_id": 50054,
"uuid": "FDA50693-A4E2-4FB1-AFCF-C6EB07647825"
},
{
"device_id": 797995,
"major": 10001,
"minor": 10024,
"page_id": 50054,
"uuid": "FDA50693-A4E2-4FB1-AFCF-C6EB07647825"
}
],
"total_count": 2
},
"errcode": 0,
"errmsg": "success."
}
*/
此接口无法获取当天数据,最早只能获取前一天数据。 由于系统在凌晨处理前一天的数据,太早调用此接口可能获取不到数据,建议在早上8:00后调用此接口。
查询单个设备进行摇周边操作的人数、次数,点击摇周边消息的人数、次数。
注意: 查询的最长时间跨度为 30 天。只能查询最近 90 天的数据。
方法
$shakearound->stats->deviceSummary(array $deviceIdentifier, int $beginDate, int $endDate)
参数
$deviceIdentifier 设备id,设备编号device_id或UUID、major、minor的关联数组,若二者都填,则以设备编号为优先 $beginDate 起始日期时间戳,最长时间跨度为30天,单位为秒 $endDate 结束日期时间戳,最长时间跨度为30天,单位为秒
示例
$result = $shakearound->stats->deviceSummary(['device_id' => 10011], 1425052800, 1425139200);
// 或
$result = $shakearound->stats->deviceSummary(['uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825', 'major' => 1002, 'minor' => 1223, ], 1425052800, 1425139200);
/* 返回结果
{
"data": [
{
"click_pv": 0,
"click_uv": 0,
"ftime": 1425052800,
"shake_pv": 0,
"shake_uv": 0
},
{
"click_pv": 0,
"click_uv": 0,
"ftime": 1425139200,
"shake_pv": 0,
"shake_uv": 0
}
],
"errcode": 0,
"errmsg": "success."
}
*/
查询指定时间商家帐号下的每个设备进行摇周边操作的人数、次数,点击摇周边消息的人数、次数。
只能查最近90天内的数据,且一次只能查询一天。
注意: 对于摇周边人数、摇周边次数、点击摇周边消息的人数、点击摇周边消息的次数都为0的设备,不在结果列表中返回。
方法
$shakearound->stats->devicesSummary(int $timestamp, int $pageIndex)
参数
$timestamp 指定查询日期时间戳,单位秒 $pageIndex 指定查询的结果页序号,返回结果按摇周边人数降序排序,每50条记录为一页
示例
$result = $shakearound->stats->devicesSummary(1435075200, 1);
/* 返回结果
{
"data": {
"devices": [
{
"device_id": 10097,
"major": 10001,
"minor": 12102,
"uuid": "FDA50693-A4E2-4FB1-AFCF-C6EB07647825"
"shake_pv": 1
"shake_uv": 2
"click_pv": 3
"click_uv": 4
},
{
"device_id": 10098,
"major": 10001,
"minor": 12103,
"uuid": "FDA50693-A4E2-4FB1-AFCF-C6EB07647825"
"shake_pv": 1
"shake_uv": 2
"click_pv": 3
"click_uv": 4
}
],
},
"date":1435075200
"total_count": 151
"page_index":1
"errcode": 0,
"errmsg": "success."
}
*/
查询单个页面通过摇周边摇出来的人数、次数,点击摇周边页面的人数、次数
注意: 查询的最长时间为30天。只能查最近90天的数据。
方法
$shakearound->stats->pageSummary(int $pageId, int $beginDate, int $endDate);
参数
$pageId 指定页面ID $beginDate 起始日期时间戳,最长时间跨度为30天,单位为秒 $endDate 结束日期时间戳,最长跨度为30天,单位秒
示例
$result = $shakearound->stats->pageSummary(12345, 1425052800, 1425139200);
/* 返回结果
{
"data": [
{
"click_pv": 0,
"click_uv": 0,
"ftime": 1425052800,
"shake_pv": 0,
"shake_uv": 0
},
{
"click_pv": 0,
"click_uv": 0,
"ftime": 1425139200,
"shake_pv": 0,
"shake_uv": 0
}
],
"errcode": 0,
"errmsg": "success."
}
*/
查询指定时间商家帐号下的每个页面进行摇周边操作的人数、次数,点击摇周边消息的人数、次数。
注意: 对于摇周边人数、摇周边次数、点击摇周边消息的人数、点击摇周边消息的次数都为0的页面,不在结果列表中返回。
方法
$shakearound->stats->pagesSummary(int $timestamp, int $pageIndex);
参数
$timestamp 指定查询日期时间戳,单位为秒 $pageIndex 指定查询的结果页序号,返回结果按摇周边人数降序排序,每50条记录为一页
示例
$result = $shakearound->stats->pagesSummary(1435075200, 1);
/* 返回结果
{
"data": {
"pages": [
{
"page_id":1234
"click_pv": 1,
"click_uv": 3,
"shake_pv": 0,
"shake_uv": 0
},
{
"page_id":5678
"click_pv": 1,
"click_uv": 2,
"shake_pv": 0,
"shake_uv": 0
},
],
},
"date":1435075200
"total_count": 151
"page_index":1
"errcode": 0,
"errmsg": "success."
}
*/
调用H5页面获取设备信息 JS API接口,需要先把设备分组,微信客户端只会返回已在分组中的设备信息。
新建设备分组,每个帐号下最多只有1000个分组。
方法
$shakearound->group->create(string $name)
//参数
// $name 分组名称,不超过100汉字或200个英文字母
//示例
$result = $shakearound->group->create('test');
/* 返回结果
{
"data": {
"group_id" : 123,
"group_name" : "test"
},
"errcode": 0,
"errmsg": "success."
}
*/
编辑设备分组信息,目前只能改分组名。
方法
$shakearound->group->update(int $groupId, string $name)
参数
$groupId 分组唯一标识,全局唯一 $name 分组名称,不超过100汉字或200个英文字母
示例
$result = $shakearound->group->update(123, 'newName');
/* 返回结果
{
"data": {
},
"errcode": 0,
"errmsg": "success."
}
*/
删除设备分组,若分组中还存在设备,则不能删除成功。需把设备移除以后,才能删除。
在执行删除前,最好先用
get
方法查询分组详情,若分组内有设备,先用removeDevices
方法移除。
方法
$shakearound->group->delete(int $groupId)
参数
$groupId 分组唯一标识,全局唯一
示例
$result = $shakearound->group->delete(123);
/* 返回结果
{
"data": {
},
"errcode": 0,
"errmsg": "success."
}
*/
查询账号下所有的分组。
方法
$shakearound->group->list(int $begin, int $count)
参数
$begin 分组列表的起始索引值 $count 待查询的分组数量,不能超1000个
示例
$result = $shakearound->group->list(0, 2);
/* 返回结果
{
"data": {
"groups":[
{
"group_id" : 123,
"group_name" : "test1"
},
{
"group_id" : 124,
"group_name" : "test2"
}
],
"total_count": 100
},
"errcode": 0,
"errmsg": "success."
}
*/
查询分组详情,包括分组名,分组id,分组里的设备列表。
方法
$shakearound->group->get(int $groupId, int $begin, int $count)
参数
$groupId 分组唯一标识,全局唯一 $begin 分组里设备的起始索引值 $count 待查询的分组里设备的数量,不能超1000个
示例
$result = $shakearound->group->get(123, 0, 2);
/* 返回结果
{
"data": {
"group_id" : 123,
"group_name" : "test",
"total_count": 100,
"devices" :[
{
"device_id" : 123456,
"uuid" : "FDA50693-A4E2-4FB1-AFCF-C6EB07647825",
"major" : 10001,
"minor" : 10001,
"comment" : "test device1",
"poi_id" : 12345,
},
{
"device_id" : 123457,
"uuid" : "FDA50693-A4E2-4FB1-AFCF-C6EB07647825",
"major" : 10001,
"minor" : 10002,
"comment" : "test device2",
"poi_id" : 12345,
}
]
},
"errcode": 0,
"errmsg": "success."
}
*/
添加设备到分组,每个分组能够持有的设备上限为10000,并且每次添加操作的添加上限为1000。
只有在摇周边申请的设备才能添加到分组。
方法
$shakearound->group->addDevices(int $groupId, array $deviceIdentifiers)
参数
$groupId 分组唯一标识,全局唯一 $deviceIdentifiers 设备id列表
示例
$result = $shakearound->group->addDevices(123, [
['device_id' => 10097],
['device_id' => 10098],
]);
// 或
$result = $shakearound->group->addDevices(123, [
[
'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825',
'major' => 10001,
'minor' => 12102,
],
[
'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825',
'major' => 10001,
'minor' => 12103,
]
]);
/* 返回结果
{
"data": {
},
"errcode": 0,
"errmsg": "success."
}
*/
从分组中移除设备,每次删除操作的上限为 1000。
方法
$shakearound->group->removeDevices(int $groupId, array $deviceIdentifiers)
参数
$groupId 分组唯一标识,全局唯一 $deviceIdentifiers 设备id列表
示例
$result = $shakearound->group->removeDevices(123, [
['device_id' => 10097],['device_id' => 10098],]);
// 或
$result = $shakearound->group->removeDevices(123, [
[
'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825',
'major' => 10001,
'minor' => 12102,
],
[
'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825',
'major' => 10001,
'minor' => 12103,
]
]);
用户进入摇一摇界面,在“周边”页卡下摇一摇时,微信会把这个事件推送到开发者填写的URL(登录公众平台开发者中心设置)。推送内容包含摇一摇时“周边”页卡展示出来的页面所对应的设备信息,以及附近最多五个属于该公众账号的设备的信息。当摇出列表时,此事件不推送。
摇一摇事件的事件类型:ShakearoundUserShake
关于事件的处理请移步: 事件
通过数据接口,开发者可以获取与公众平台官网统计模块类似但更灵活的数据,还可根据需要进行高级处理。
- 接口侧的公众号数据的数据库中仅存了 2014年12月1日之后的数据,查不到在此之前的日期,即使查到,也是不可信的脏数据;
- 开发者在调用接口获取数据后,将数据保存在自身数据库中,即加快下次用户的访问速度,也降低微信侧接口调用的损耗。
- 注意,获取图文群发每日数据接口的结果中,只有中间页阅读人数+原文页阅读人数+分享转发人数+分享转发次数+收藏次数 >=3 结果才得到统计,过小的阅读量的图文消息无法统计。
示例
$userSummary = $app->data_cube->userSummary('2014-12-07', '2014-12-08');
var_dump($userSummary);
//[
// {
// "ref_date": "2014-12-07",
// "user_source": 0,
// "new_user": 0,
// "cancel_user": 0
// }
// //后续还有ref_date在begin_date和end_date之间的数据
// ]
API
$from 示例: `2014-02-13` 获取数据的起始日期
$to 示例: `2014-02-18` 获取数据的结束日期,`$to`允许设置的最大值为昨日
`$from` 和 `$to` 的差值需小于 “最大时间跨度”(比如最大时间跨度为 1 时,`$from` 和 `$to` 的差值只能为 0,才能小于 1 ),否则会报错
array userSummary(string $from, string $to)
获取用户增减数据, 最大时间跨度:7;array userCumulate(string $from, string $to)
获取累计用户数据, 最大时间跨度:7;array articleSummary(string $from, string $to)
获取图文群发每日数据, 最大时间跨度:1;array articleTotal(string $from, string $to)
获取图文群发总数据, 最大时间跨度:1;array userReadSummary(string $from, string $to)
获取图文统计数据, 最大时间跨度:3;array userReadHourly(string $from, string $to)
获取图文统计分时数据, 最大时间跨度:1;array userShareSummary(string $from, string $to)
获取图文分享转发数据, 最大时间跨度:7;array userShareHourly(string $from, string $to)
获取图文分享转发分时数据, 最大时间跨度:1;array upstreamMessageSummary(string $from, string $to)
获取消息发送概况数据, 最大时间跨度:7;array upstreamMessageHourly(string $from, string $to)
获取消息发送分时数据, 最大时间跨度:1;array upstreamMessageWeekly(string $from, string $to)
获取消息发送周数据, 最大时间跨度:30;array upstreamMessageMonthly(string $from, string $to)
获取消息发送月数据, 最大时间跨度:30;array upstreamMessageDistSummary(string $from, string $to)
获取消息发送分布数据, 最大时间跨度:15;array upstreamMessageDistWeekly(string $from, string $to)
获取消息发送分布周数据, 最大时间跨度:30;array upstreamMessageDistMonthly(string $from, string $to)
获取消息发送分布月数据, 最大时间跨度:30;array interfaceSummary(string $from, string $to)
获取接口分析数据, 最大时间跨度:30;array interfaceSummaryHourly(string $from, string $to)
获取接口分析分时数据, 最大时间跨度:1;array cardSummary(string $from, string $to, int $condSource = 0)
获取普通卡券分析分时数据, 最大时间跨度:1;array freeCardSummary(string $from, string $to, int $condSource = 0, string $cardId = '')
获取免费券分析分时数据, 最大时间跨度:1;array memberCardSummary(string $from, string $to, int $condSource = 0)
获取会员卡分析分时数据, 最大时间跨度:1;貌似此接口已下线,调用无正确返回值
query($keyword, $categories, $optional = [])
语义理解:
$keyword
为关键字$categories
需要使用的服务类型,多个用 “,” 隔开字符串,不能为空;$optional
为其它属性:latitude
float
纬度坐标,与经度同时传入;与城市二选一传入longitude
float
经度坐标,与纬度同时传入;与城市二选一传入city
string
城市名称,与经纬度二选一传入region
string
区域名称,在城市存在的情况下可省;与经纬度二选一传入uid
string
用户唯一id(非开发者id),用户区分公众号下的不同用户(建议填入用户openid),如果为空,则无法使用上下文理解功能。appid和uid同时存在的情况下,才可以使用上下文理解功能。注:单类别意图比较明确,识别的覆盖率比较大,所以如果只要使用特定某个类别,建议将 category 只设置为该类别。
示例:
$result = $app->semantic->query('查一下明天从北京到上海的南航机票', "flight,hotel", array('city' => '北京', 'uid' => '123456'));
// 查询参数:
// {
// "query":"查一下明天从北京到上海的南航机票",
// "city":"北京",
// "category": "flight,hotel",
// "appid":"wxaaaaaaaaaaaaaaaa",
// "uid":"123456"
// }
返回值示例:
{
"errcode":0,
"query":"查一下明天从北京到上海的南航机票",
"type":"flight",
"semantic":{
"details":{
"start_loc":{
"type":"LOC_CITY",
"city":"北京市",
"city_simple":"北京",
"loc_ori":"北京"
},
"end_loc": {
"type":"LOC_CITY",
"city":"上海市",
"city_simple":"上海",
"loc_ori":"上海"
},
"start_date": {
"type":"DT_ORI",
"date":"2014-03-05",
"date_ori":"明天"
},
"airline":"中国南方航空公司"
},
"intent":"SEARCH"
}
$app->auto_reply->current();
$app->comment->open($msgId, $index = null);
$app->comment->close($msgId, $index = null);
$app->comment->list(string $msgId, int $index, int $begin, int $count, int $type = 0);
$app->comment->markElect(string $msgId, int $index, int $commentId);
$app->comment->unmarkElect(string $msgId, int $index, int $commentId);
$app->comment->delete(string $msgId, int $index, int $commentId);
$app->comment->reply(string $msgId, int $index, int $commentId, string $content);
$app->comment->deleteReply(string $msgId, int $index, int $commentId);
微信文档:https://mp.weixin.qq.com/cgi-bin/announce?action=getannouncement&key=11533749572M9ODP&version=1&lang=zh_CN&platform=2
每次调用支持批量导入不超1000条的商品信息。每分钟单商户全局调用次数不得超200次。每天调用次数不得超100万次。每次请求包大小不超过2M。
$data = [
[
'pid' => 'pid001',
'image_info' => [
'main_image_list' => [
[
'url' => 'http://www.google.com/a.jpg',
],
[
'url' => 'http://www.google.com/b.jpg',
],
],
],
//...
],
//...
];
$result = $app->goods->add($data);
// $result:
//{
// "errcode": 0,
// "errmsg": "ok",
// "status_ticket": "115141102647330200"
//}
status_ticket
用于获取此次导入的详细结果。
更新时,字段不填代表不更新该字段(此处的字段不填,代表无此字段,而不是把字段的值设为空,设为空即代表更新该字段为空)。
对于字符串类型的选填字段,如副标题,若清空不展示,则可设置为空;对于数字类型的选填字段,如原价,若清空不展示,则需设置为0。
基本字段更新中
pid
为必填字段,且无法修改
$data = [
[
'pid' => 'pid001',
'image_info' => [
'main_image_list' => [
[
'url' => 'http://www.baidu.com/c.jpg',
],
[
'url' => 'http://www.baidu.com/d.jpg',
],
],
],
//...
],
//...
];
$result = $app->goods->update($data);
// $result:
//{
// "errcode": 0,
// "errmsg": "ok",
// "status_ticket": "115141102647330200"
//}
说明:导入商品和更新商品使用的是同一个接口。
用于查询导入或更新商品的结果,当导入或更新商品失败时,若为系统错误可进行重试;若为其他错误,请排查解决后进行重试。
$status_ticket = '115141102647330200';
$result = $app->goods->status($status_ticket);
// $result:
//{
// "errcode": 0,
// "errmsg": "ok",
// "result": {
// "succ_cnt": 2,
// "fail_cnt": 0,
// "total_cnt": 2,
// "progress": "100.00%",
// "statuses": [
// {
// "pid": "pid001",
// "ret": 0,
// "err_msg": "success",
// "err_msg_zh_cn": "成功"
// },
// {
// "pid": "pid002",
// "ret": 0,
// "err_msg": "success",
// "err_msg_zh_cn": "成功"
// }
// ]
// }
//}
使用该接口获取已导入的商品信息,供验证信息及抽查导入情况使用。
$pid = 'pid001';
$app->goods->get($pid);
返回结果中的
product
字段与导入商品接口
字段一致,导入时未设置的值有可能获取时仍会返回,但显示为空
使用该接口可获取已导入的全量商品信息,供全量验证信息使用。
$context = ''; // page 为 1 时传空即可。当 page 大于 1 时必填,填入上一次访问本接口返回的 page_context。
$page = 1; // 页码
$size = 10; // 每页数据大小,目前限为100内,注意一次全量验证过程中该参数的值需保持不变
$app->goods->list($context, $page, $size);
返回结果中的
product
字段与导入商品接口
字段一致,导入时未设置的值有可能获取时仍会返回,但显示为空。page_context
字段用于获取下一页数据时使用。
你在阅读本文之前确认你已经仔细阅读了:微信支付 | 商户平台开发文档。
配置在前面的例子中已经提到过了,支付的相关配置如下:
use EasyWeChat\Factory;
$config = [
// 必要配置
'app_id' => 'xxxx',
'mch_id' => 'your-mch-id',
'key' => 'key-for-signature', //API密钥
// 如需使用敏感接口(如退款、发送红包等)需要配置 API 证书路径(登录商户平台下载 API 证书)
'cert_path' => 'path/to/your/cert.pem', //绝对路径!
'key_path' => 'path/to/your/key', //绝对路径!
'notify_url' => '默认的订单回调地址', // 也可在下单时单独设置覆盖它
];
$app = Factory::payment($config);
设置子商户信息
$app->setSubMerchant('sub-merchant-id', 'sub-app-id'); // 子商户 AppID 为可选项
官方文档
$result = $app->pay([
'body' => 'image形象店-深圳腾大- QQ公仔',
'out_trade_no' => '1217752501201407033233368018',
'total_fee' => 888,
'auth_code' => '120061098828009406',
]);
$app->authCodeToOpenid($authCode);
微信支付沙箱环境,是提供给微信支付商户的开发者,用于模拟支付及回调通知。以验证商户是否理解回调通知、账单格式,及是否对异常做正确的处理。EasyWeChat SDK 对于这一功能封装,开发者只需一步即可在沙箱模式和常规模式间切换,方便开发与最终的部署。
// 在实例化的时候传入配置即可
$app = Factory::payment([
// ...
'sandbox' => true, // 设为 false 或注释则关闭沙箱模式
]);
// 判断当前是否为沙箱模式:
bool $app->inSandbox();
注意,沙箱模式对测试用例有严格要求,若使用用例与规定不符,将导致测试失败。具体用例可关注公众号“微信支付商户接入验收助手”(WXPayAssist)查看。
H5 支付,公众号支付,扫码支付,支付中签约,全都用这个接口下单。
参数
appid
,mch_id
,nonce_str
,sign
,sign_type
可不用传入服务商模式下, 需用
sub_openid
, 并传入sub_mch_id
和sub_appid
$result = $app->order->unify([
'body' => '腾讯充值中心-QQ会员充值',
'out_trade_no' => '20150806125346',
'total_fee' => 88,
'spbill_create_ip' => '123.12.12.123', // 可选,如不传该参数,SDK 将会自动获取相应 IP 地址
'notify_url' => 'https://pay.weixin.qq.com/wxpay/pay.action', // 支付结果通知网址,如不设置则会用配置的默认地址
'trade_type' => 'JSAPI', // 请对应换成支付方式对应的值类型
'openid' => 'oUpF8uMuAJO_M2pxb1Q9zNjWeS6o',
]);
// $result:
//{
// "return_code": "SUCCESS",
// "return_msg": "OK",
// "appid": "wx2421b1c4390ec4sb",
// "mch_id": "10000100",
// "nonce_str": "IITRi8Iabbblz1J",
// "openid": "oUpF8uMuAJO_M2pxb1Q9zNjWeSs6o",
// "sign": "7921E432F65EB8ED0CE9755F0E86D72F2",
// "result_code": "SUCCESS",
// "prepay_id": "wx201411102639507cbf6ffd8b0779950874",
// "trade_type": "JSAPI"
//}
第二个参数为是否支付中签约,默认 false
支付中签约相关参数
contract_mchid
,contract_appid
,request_serial
可不用传入
$isContract = true;
$result = $app->order->unify([
'body' => '腾讯充值中心-QQ会员充值',
'out_trade_no' => '20150806125346',
'total_fee' => 88,
'spbill_create_ip' => '123.12.12.123', // 可选,如不传该参数,SDK 将会自动获取相应 IP 地址
'notify_url' => 'https://pay.weixin.qq.com/wxpay/pay.action', // 支付结果通知网址,如果不设置则会使用配置里的默认地址
'trade_type' => 'JSAPI', // 请对应换成你的支付方式对应的值类型
'openid' => 'oUpF8uMuAJO_M2pxb1Q9zNjWeS6o',
'plan_id' => 123,// 协议模板id
'contract_code' => 100001256,// 签约协议号
'contract_display_account' => '腾讯充值中心',// 签约用户的名称
'contract_notify_url' => 'http://easywechat.org/contract_notify'
], $isContract);
//$result:
//{
// "return_code": "SUCCESS",
// "return_msg": "OK",
// "appid": "wx123456",
// "mch_id": "10000100",
// "nonce_str": "CfOcMkDFblzulYvI",
// "sign": "B53F4AFEE7FA6AD5739581486A5CB9C9",
// "result_code": "SUCCESS",
// "prepay_id": "wx08175759731015754a5c13791522969400",
// "trade_type": "JSAPI",
// "plan_id": "123",
// "request_serial": "1565258279",
// "contract_code": "100001256",
// "contract_display_account": "腾讯充值中心",
// "out_trade_no": "201908088195558331565258279",
// "contract_result_code": "SUCCESS"
//}
该接口提供所有微信支付订单的查询,商户可通过该接口主动查询订单状态,完成下步的业务逻辑。
需调用查询接口的情况:
- 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知;
- 调用支付接口后,返回系统错误或未知交易状态情况;
- 调用被扫支付 API,返回 USERPAYING 的状态;
- 调用关单或撤销接口 API 之前,需确认支付状态;
$app->order->queryByOutTradeNumber("商户系统内部的订单号(out_trade_no)");
$app->order->queryByTransactionId("微信订单号(transaction_id)");
注意:订单生成后不能马上调用关单接口,最短调用时间间隔为5分钟
$app->order->close(商户系统内部的订单号(out_trade_no)
当交易发生后一段时间内,由于买家或者卖家原因需退款时,卖家可通过退款接口将支付款退给买家,微信支付将在收到退款请求且验证成功后,按退款规则将支付款按原路退到买家帐号上。
注意:
1、交易时间超一年的订单无法提交退款; 2、微信支付退款支持单笔交易分多次退款,多次退款需提交原支付订单的商户订单号和设置不同的退款单号。一笔退款失败后重新提交,要采用原退款单号。总退款金额不能超过用户实际支付金额。
参考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
// 参数分别为:微信订单号、商户退款单号、订单金额、退款金额、其他参数
$app->refund->byTransactionId(string $transactionId, string $refundNumber, int $totalFee, int $refundFee, array $config = []);
// Example:
$result = $app->refund->byTransactionId('transaction-id-xxx', 'refund-no-xxx', 10000, 10000, [
// 可在此处传入其他参数,详细参数见微信支付文档
'refund_desc' => '商品已售完',
]);
// 参数分别为:商户订单号、商户退款单号、订单金额、退款金额、其他参数
$app->refund->byOutTradeNumber(string $number, string $refundNumber, int $totalFee, int $refundFee, array $config = []);
// Example:
$result = $app->refund->byOutTradeNumber('out-trade-no-xxx', 'refund-no-xxx', 20000, 1000, [
// 可在此处传入其他参数,详细参数见微信支付文档
'refund_desc' => '退运费',
]);
$refundNumber 为商户退款单号,自己生成用于自己识别即可。
提交退款申请后,通过调用该接口查询退款状态。退款有延时,用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。
可通过 4 种不同类型的单号查询:
- 微信订单号 =>
queryByTransactionId($transactionId)
- 商户订单号 =>
queryByOutTradeNumber($outTradeNumber)
- 商户退款单号 =>
queryByOutRefundNumber($outRefundNumber)
- 微信退款单号 =>
queryByRefundId($refundId)
https://github.com/easywechat/docs/edit/4.1/payment/bill.md)
调用参数正确会返回个
EasyWeChat\Kernel\Http\StreamResponse
对象,否则会返回相应错误信息
Example:
$bill = $app->bill->get('20140603'); // type: ALL
// or
$bill = $app->bill->get('20140603', 'SUCCESS'); // type: SUCCESS
// 调用正确,`$bill` 为 csv 格式的内容,保存为文件:
$bill->saveAs('your/path/to', 'file-20140603.csv');
第二个参数为账单类型,参考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6 中 bill_type
,默认为 ALL
在用户成功支付后,微信服务器会向该订单中设置的回调URL 发起 POST 请求,请求内容为 XML。里面包含所有的详细信息,具体请参考:支付结果通知
而对于用户的退款操作,在退款成功后也有个异步回调通知。
本 SDK 内预置了相关方法,以方便开发者处理这些通知,具体用法如下:
只需在控制器中用 handlePaidNotify()
方法,在其中对自己的业务进行处理并向微信服务器发送个响应。
$response = $app->handlePaidNotify(function ($message, $fail) {
// 你的逻辑
return true;
// 或者错误消息
$fail('Order not exists.');
});
$response->send(); // Laravel 里请使用:return $response;
注意:
退款结果通知和扫码支付通知的使用方法均类似。
handlePaidNotify
只接收个 Closure
匿名函数。
该匿名函数接收两个参数,这两个参数分别为:
$message
为微信推送过来的通知信息,为一个数组;
$fail
为一个函数,触发该函数可向微信服务器返回对应的错误信息,微信会稍后重试再通知。
该函数返回值告诉微信 “我是否处理完成”。如果你触发 $fail
函数,那微信会在稍后再次继续通知你,直到明确的告诉它:“我已处理完成”,只有在函数里 return true;
才代表处理完成。
handlePaidNotify
返回值 $response
是个 Response 对象,如果要直接输出,使用 $response->send()
, 在一些框架里(如 Laravel)不是输出而是返回:return $response
。
通常处理逻辑大概是下面这样(以下只是伪代码):
$response = $app->handlePaidNotify(function($message, $fail){
// 使用通知里的 "微信支付订单号" 或 "商户订单号" 去自己数据库找订单
$order = 查询订单($message['out_trade_no']);
if (!$order || $order->paid_at) { // 如果订单不存在 或 订单已支付过
return true; // 告诉微信,已经处理完了,订单没找到,别再通知了
}
// <- 建议在这里调用微信的【订单查询】接口查下该笔订单情况,确认已支付 //
if ($message['return_code'] === 'SUCCESS') { // return_code 表示通信状态,不代表支付状态
// 用户是否支付成功
if (array_get($message, 'result_code') === 'SUCCESS') {
$order->paid_at = time(); //更新支付时间为当前时间
$order->status = 'paid';
// 用户支付失败
} elseif (array_get($message, 'result_code') === 'FAIL') {
$order->status = 'paid_fail';
}
} else {
return $fail('通信失败,请稍后再通知我');
}
$order->save(); // 保存订单
return true; // 返回处理完成
});
$response->send(); // return $response;
注意:请把 “支付成功与否” 与 “是否处理完成” 分开,它俩没必然关系。 如:微信通知用户支付完成,但支付失败了(result_code 为 ‘FAIL’),应更新订单为支付失败,但要告诉微信处理完成。
使用示例:
$response = $app->handleRefundedNotify(function ($message, $reqInfo, $fail) {
// 其中 $message['req_info'] 获取到的是加密信息
// $reqInfo 为 message['req_info'] 解密后的信息
// 你的业务逻辑...
return true; // 返回 true 告诉微信“我已处理完成”
// 或返回错误原因 $fail('参数格式校验错误');
});
$response->send();
扫码支付【模式一】:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
// 扫码支付通知接收第三个参数 `$alert`,如果触发该函数,会返回“业务错误”到微信服务器,触发 `$fail` 则返回“通信错误”
$response = $app->handleScannedNotify(function ($message, $fail, $alert) use ($app) {
// 如:$alert('商品已售空');
// 如业务流程正常,则要调用“统一下单”接口,并返回 prepay_id 字符串,代码如下
$result = $app->order->unify([
'trade_type' => 'NATIVE',
'product_id' => $message['product_id'],
// ...
]);
return $result['prepay_id'];
});
$response->send();
在阅读本文之前确认你已经仔细阅读了:微信支付 | 现金红包文档 。
与支付接口一样,红包接口也要配置如下参数,注意,红包相关的全部接口都要用 SSL 证书,因此cert_path 及 cert_key 必须正确配置。
use EasyWeChat\Factory;
$config = [
'app_id' => 'you-app-id',
'mch_id' => 'your-mch-id',
'key' => 'key-for-signature',
'cert_path' => 'path/to/your/cert.pem',
'key_path' => 'path/to/your/key',
// ...
];
$payment = Factory::payment($config);
$redpack = $payment->redpack;
微信的现金红包分为普通红包和裂变红包两类。SDK 对其分别封装,同时也提供一个统一的调用方法。
默认,通过接口发送的红包金额应该在200元内,但可通过在调用发送接口时传递场景 ID (scene_id)来发送特定场景的红包,不同场景红包可由商户自己登录商户平台设置最大金额。scene_id 的可选值及对应含义可参阅微信支付官方文档。
$redpackData = [
'mch_billno' => 'xy123456',
'send_name' => '测试红包',
're_openid' => 'oxTWIuGaIt6gTKsQRLau2M0yL16E',
'total_num' => 1, //固定为1,可不传
'total_amount' => 100, //单位为分,不小于100
'wishing' => '祝福语',
'client_ip' => '192.168.0.1', //可不传,不传则由 SDK 取当前客户端 IP
'act_name' => '测试活动',
'remark' => '测试备注',
// ...
];
$result = $redpack->sendNormal($redpackData);
$redpackData = [
'mch_billno' => 'xy123456',
'send_name' => '测试红包',
're_openid' => 'oxTWIuGaIt6gTKsQRLau2M0yL16E',
'total_num' => 3, //不小于3
'total_amount' => 300, //单位为分,不小于300
'wishing' => '祝福语',
'act_name' => '测试活动',
'remark' => '测试备注',
'amt_type' => 'ALL_RAND', //可不传
// ...
];
$result = $redpack->sendGroup($redpackData);
红包预下单接口是为摇一摇红包接口配合使用的,在开发摇一摇周边的摇红包相关功能时,需要调用本接口获取红包单号。详情参见官方文档
$redpackData = [
'hb_type' => 'NORMAL', //NORMAL 或 GROUP
'mch_billno' => 'xy123456',
'send_name' => '测试红包',
're_openid' => 'oxTWIuGaIt6gTKsQRLau2M0yL16E',
'total_num' => 1, //普通红包固定为1,裂变红包不小于3
'total_amount' => 100, //单位为分,普通红包不小于100,裂变红包不小于300
'wishing' => '祝福语',
'client_ip' => '192.168.0.1', //可不传,不传则由 SDK 取当前客户端 IP
'act_name' => '测试活动',
'remark' => '测试备注',
'amt_type' => 'ALL_RAND',
// ...
];
$result = $redpack->prepare($redpackData);
用于商户对已发放的红包进行查询红包的具体信息及领取情况 ,普通红包和裂变包均用这一接口查询。
$mchBillNo = "商户系统内部的订单号(mch_billno)";
$redpack->info($mchBillNo);
先熟悉流程:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
$content = $app->scheme($productId); // $productId 为产品/商品ID,用于回调时带回,自己识别即可
//结果示例:weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX
将 $content
生成二维码,SDK 并不内置二维码生成库,使用熟悉的工具创建二维码即可,比如 PHP 部分有以下工具可以选择:
- https://github.com/endroid/qr-code
- https://github.com/SimpleSoftwareIO/simple-qrcode
- https://github.com/aferrandini/PHPQRCode
当用户扫码时,回调接口会收到个通知,调用统一下单接口创建订单后返回 prepay_id
,可用下面的代码处理扫码通知:
// 扫码支付通知接收第三个参数 `$alert`,如果触发该函数,会返回“业务错误”到微信服务器,触发 `$fail` 则返回“通信错误”
$response = $app->handleScannedNotify(function ($message, $fail, $alert) use ($app) {
// 如:$alert('商品已售空');
// 如业务流程正常,调用“统一下单”接口,并返回 prepay_id 字符串
$result = $app->order->unify([
'trade_type' => 'NATIVE',
'product_id' => $message['product_id'], // $message['product_id'] 则为生成二维码时的产品 ID
// ...
]);
return $result['prepay_id'];
});
$response->send();
用户在手机上付完钱以后,会再收到付款结果通知,这时请参考:处理微信支付通知 更新您的订单状态。
请熟悉流程:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5
调用统一下单接口创建订单:
$result = $app->order->unify([
'trade_type' => 'NATIVE',
'product_id' => $message['product_id'], // $message['product_id'] 则为生成二维码时的产品 ID
// ...
]);
版本 4.1.7+ 支持
从上步得到的 $result['code_url']
得到二维码内容:
将 $result['code_url']
生成二维码图片向用户展示即可扫码,生成工具上面找下即可。 SDK 不内置
这种方式的通知就只有付款结果通知了,这时候请参考:处理微信支付通知 更新您的订单状态。
JSSDK 模块用于生成调起微信支付以及共享收货地址的调用所需的配置参数。
use EasyWeChat\Factory;
$config = [
// 前面的appid什么的也得保留哦
'app_id' => 'xxxx',
'mch_id' => 'your-mch-id',
'key' => 'key-for-signature',
'cert_path' => 'path/to/your/cert.pem', // XXX: 绝对路径!!!!
'key_path' => 'path/to/your/key', // XXX: 绝对路径!!!!
'notify_url' => '默认的订单回调地址', // 你也可以在下单时单独设置来想覆盖它
// 'device_info' => '013467007045764',
// 'sub_app_id' => '',
// 'sub_merchant_id' => '',
// ...
];
$payment = Factory::payment($config);
$jssdk = $payment->jssdk;
有三种发起支付的方式:WeixinJSBridge, JSSDK, 小程序
WeixinJSBridge:
$json = $jssdk->bridgeConfig($prepayId); // 返回 json 字符串,如果想返回数组,传第二个参数 false
javascript:
...
WeixinJSBridge.invoke(
'getBrandWCPayRequest', <?= $json ?>,
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ) {
//用以上方式判断前端返回,微信团队郑重提示:
// res.err_msg将在用户支付成功后返回
// ok,但并不保证它绝对可靠。
}
}
);
...
JSSDK:
$config = $jssdk->sdkConfig($prepayId); // 返回数组
javascript:
wx.chooseWXPay({
timestamp: <?= $config['timestamp'] ?>,
nonceStr: '= $config['nonceStr'] ?>',
package: '= $config['package'] ?>',
signType: '= $config['signType'] ?>',
paySign: '= $config['paySign'] ?>', // 支付签名
success: function (res) {
// 支付成功后的回调函数
}
});
小程序:
$config = $jssdk->bridgeConfig($prepayId, false); // 返回数组
javascript:
wx.requestPayment({
timeStamp: <?= $config['timeStamp'] ?>, //注意 timeStamp 的格式
nonceStr: '= $config['nonceStr'] ?>',
package: '= $config['package'] ?>',
signType: '= $config['signType'] ?>',
paySign: '= $config['paySign'] ?>', // 支付签名
success: function (res) {
// 支付成功后的回调函数
}
});
$accessToken
,参考网页授权章节。$accessToken
获取配置$configForPickAddress = $jssdk->shareAddressConfig($token);
// 拿着这个生成好的配置 $configForPickAddress 去订单页(或者直接显示订单页)写 js 调用了
// ...
$config = $jssdk->appConfig($prepayId);
$config
为数组格式,你可以用 API 返回给客户端
你也许需要生成二维码,那么以下这些供参考:
- https://github.com/endroid/QrCode
- https://github.com/Bacon/BaconQrCode
- https://github.com/SimpleSoftwareIO/simple-qrcode (Bacon/BaconQrCode 的 Laravel 版本)
- https://github.com/aferrandini/PHPQRCode
EasyWeChat 4.0.7+
该模块需要用到双向证书,请参考:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=4_3
$app->transfer->toBalance([
'partner_trade_no' => '1233455', // 商户订单号,需保持唯一性(只能是字母或者数字,不能包含有符号)
'openid' => 'oxTWIuGaIt6gTKsQRLau2M0yL16E',
'check_name' => 'FORCE_CHECK', // NO_CHECK:不校验真实姓名, FORCE_CHECK:强校验真实姓名
're_user_name' => '王小帅', // 如果 check_name 设置为FORCE_CHECK,则必填用户真实姓名
'amount' => 10000, // 企业付款金额,单位为分
'desc' => '理赔', // 企业付款操作说明信息。必填
]);
$partnerTradeNo = 1233455;
$app->transfer->queryBalanceOrder($partnerTradeNo);
企业付款到银行卡需要对银行卡号与姓名进行 RSA 加密,所以这里需要先下载 RSA 公钥到本地(服务器),我们提供了一个命令行工具:EasyWeChat/console,请使用 composer 安装完成。
$ composer require easywechat/console -vvv
然后,在项目根目录执行以下命令下载公钥:
$ ./vendor/bin/easywechat payment:rsa_public_key \
> --mch_id=14339221228 \
> --api_key=36YTbDmLgyQ52noqdxgwGiYy \
> --cert_path=/Users/overtrue/www/demo/apiclient_cert.pem \
> --key_path=/Users/overtrue/www/demo/apiclient_key.pem
将在当前目录生成个 ./public-14339221228.pem
文件,可将它移动到敏感目录,然后在支付配置文件中加如以下选项:
use EasyWeChat\Factory;
$config = [
// 必要配置
'app_id' => 'xxxx',
'mch_id' => 'your-mch-id',
'key' => 'key-for-signature', //API 密钥
// 如需用敏感接口(如退款、发送红包等)需配置 API 证书路径(登录商户平台下载 API 证书)
'cert_path' => '/path/to/your/cert.pem', //绝对路径!
'key_path' => '/path/to/your/key', //绝对路径!
// 将上面得到的公钥存放路径填写在这里
'rsa_public_key_path' => '/path/to/your/rsa/publick/key/public-14339221228.pem', // <<<----------
'notify_url' => '默认的订单回调地址', // 也可在下单时单独设置来覆盖
];
$app = Factory::payment($config);
$result = $app->transfer->toBankCard([
'partner_trade_no' => '1229222022',
'enc_bank_no' => '6214830901234564', // 银行卡号
'enc_true_name' => '安正超', // 银行卡对应的用户真实姓名
'bank_code' => '1001', // 银行编号
'amount' => 100, // 单位:分
'desc' => '测试',
]);
$partnerTradeNo = 1233455;
$app->transfer->queryBankCardOrder($partnerTradeNo);
目前只有 刷卡支付 有此功能。
调用支付接口后请勿立即调用撤销订单API,建议支付后至少15s后再调用撤销订单接口。
$app->reverse->byOutTradeNumber("商户系统内部的订单号(out_trade_no)");
$app->reverse->byTransactionId("微信的订单号(transaction_id)");
EasyWeChat 4.0.7+
$result = $app->security->getPublicKey();
// 存成文件
file_put_contents('./public.pem', $result);
将会得到 PKCS#1 格式密钥:
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEArT82k67xybiJS9AD8nNAeuDYdrtCRaxkS6cgs8L9h83eqlDTlrdw
zBVSv5V4imTq/URbXn4K0V/KJ1TwDrqOI8hamGB0fvU13WW1NcJuv41RnJVua0QA
lS3tS1JzOZpMS9BEGeFvyFF/epbi/m9+2kUWG94FccArNnBtBqqvFncXgQsm98JB
3a62NbS1ePP/hMI7Kkz+JNMyYsWkrOUFDCXAbSZkWBJekY4nGZtK1erqGRve8Jbx
TWirAm/s08rUrjOuZFA21/EI2nea3DidJMTVnXVPY2qcAjF+595shwUKyTjKB8v1
REPB3hPF1Z75O6LwuLfyPiCrCTmVoyfqjwIDAQAB
-----END RSA PUBLIC KEY-----
使用 OpenSSL 转换 PKCS#1 为 PKCS#8 格式密钥:
openssl rsa -RSAPublicKey_in -in public.pem -out public.pem
PKCS#8 格式密钥:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArT82k67xybiJS9AD8nNA
euDYdrtCRaxkS6cgs8L9h83eqlDTlrdwzBVSv5V4imTq/URbXn4K0V/KJ1TwDrqO
I8hamGB0fvU13WW1NcJuv41RnJVua0QAlS3tS1JzOZpMS9BEGeFvyFF/epbi/m9+
lkUWG94FccArNnBtBqqvFncXgQsm98JB3a42NbS1ePP/hMI7Kkz+JNMyYsWkrOUF
DCXAbSZkWBJekY4nGZtK1erqGRve8JbxTWirAm/s08rUrjOuZFA21/EI2nea3Did
JMTVnXVPY2qcAjF+595shwUKyTjKB8v1REPB3hPF1Z75O6LwuLfyPiCrCTmVoyfq
jwIDAQAB
-----END PUBLIC KEY-----
use EasyWeChat\Factory;
$config = [
'app_id' => 'wx3cf0f39249eb0exx',
'secret' => 'f1c242f4f28f735d4687abb469072axx',
// 下面为可选项
// 指定 API 调用返回结果的类型:array(default)/collection/object/raw/自定义类名
'response_type' => 'array',
'log' => [
'level' => 'debug',
'file' => __DIR__.'/wechat.log',
],
];
$app = Factory::miniProgram($config);
$app
在所有相关小程序的文档都是指 Factory::miniProgram
实例,就不在每个页面单独写了。
接口A: 适用于需要的码数量较少的业务场景,API:
$app->app_code->get(string $path, array $optional = []);
其中 $optional
为以下可选参数:
- width Int - 默认 430 二维码的宽度
- auto_color 默认 false 自动配置线条颜色,如果颜色黑色,则说明不建议配置主色调
- line_color 数组,
auto_color
为false
时生效,使用 rgb 设置颜色 例如 ,示例:["r" => 0,"g" => 0,"b" => 0]
。
示例代码:
$response = $app->app_code->get('path/to/page');
// 或者
$response = $app->app_code->get('path/to/page', [
'width' => 600,
//...
]);
// 或者指定颜色
$response = $app->app_code->get('path/to/page', [
'width' => 600,
'line_color' => [
'r' => 105,
'g' => 166,
'b' => 134,
],
]);
// $response 成功时为 EasyWeChat\Kernel\Http\StreamResponse 实例,失败时为数组或者你指定的 API 返回格式
// 保存小程序码到文件
if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
$filename = $response->save('/path/to/directory');
}
// 或
if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
$filename = $response->saveAs('/path/to/directory', 'appcode.png');
}
接口B:适用于需要的码数量极多,或仅临时使用的业务场景API:
$app->app_code->getUnlimit(string $scene, array $optional = []);
其中 s c e n e 必 填 , scene 必填, scene必填,optinal 与 get 方法一致,多个 page 参数。
示例代码:
$response = $app->app_code->getUnlimit('scene-value', [
'page' => 'path/to/page',
'width' => 600,
]);
// $response 成功时为 EasyWeChat\Kernel\Http\StreamResponse 实例,失败为数组或你指定的 API 返回类型
// 保存小程序码到文件
if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
$filename = $response->save('/path/to/directory');
}
// 或
if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
$filename = $response->saveAs('/path/to/directory', 'appcode.png');
}
$app->app_code->getQrCode(string $path, int $width = null);
其中 $path 必填,其余参数可留空。
示例代码:
$response = $app->app_code->getQrCode('/path/to/page');
// $response 成功时为 EasyWeChat\Kernel\Http\StreamResponse 实例,失败为数组或你指定的 API 返回类型
// 保存小程序码到文件
if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
$filename = $response->save('/path/to/directory');
}
// 或
if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
$filename = $response->saveAs('/path/to/directory', 'appcode.png');
}
$service = $app->customer_service;
使用方法详看公众号-客服消息章节。
获取小程序概况趋势:
$app->data_cube->summaryTrend('20170313', '20170313')
开始日期与结束日期的格式为 yyyymmdd。
//API
summaryTrend(string $from, string $to); //概况趋势
dailyVisitTrend(string $from, string $to); //访问日趋势
weeklyVisitTrend(string $from, string $to); //访问周趋势
monthlyVisitTrend(string $from, string $to); //访问月趋势
visitDistribution(string $from, string $to); //访问分布
dailyRetainInfo(string $from, string $to); //访问日留存
weeklyRetainInfo(string $from, string $to); //访问周留存
monthlyRetainInfo(string $from, string $to); //访问月留存
visitPage(string $from, string $to); //访问页面
userPortrait(string $from, string $to); //用户画像分布数据
根据 jsCode 获取用户 session 信息。API:
$app->auth->session(string $code);
获取小程序模板库标题列表
$app->template_message->list($offset, $count);
获取模板库某个模板标题下关键词库
$app->template_message->get($id);
组合模板并添加至帐号下的个人模板库
$app->template_message->add($id, $keywordIdList);
获取帐号下已存在的模板列表
$app->template_message->getTemplates($offset, $count);
删除帐号下的某个模板
$app->template_message->delete($templateId);
发送模板消息
$app->template_message->send([
'touser' => 'user-openid',
'template_id' => 'template-id',
'page' => 'index',
'form_id' => 'form-id',
'data' => [
'keyword1' => 'VALUE',
'keyword2' => 'VALUE2',
// ...
],
]);
比如获取电话等功能,信息是加密的,需要解密。API:
$decryptedData = $app->encryptor->decryptData($session, $iv, $encryptedData);
用于校验一段文本是否含有违法内容。
频率限制:单个appid调用上限为2000次/分钟,1,000,000次/天
调用示例
// 传入要检测的文本内容,长度不超过500K字节
$content = '你好';
$result = $app->content_security->checkText($content);
// 正常返回 0
{
"errcode": "0",
"errmsg": "ok"
}
//当 $content 内含有敏感信息,则返回 87014
{
"errcode": 87014,
"errmsg": "risky content"
}
用于校验一张图片是否含敏感信息。如涉黄、敏感人脸(通常是政治人物)。
频率限制:单个appid调用上限为1000次/分钟,100,000次/天
调用示例
// 所传参数为要检测的图片文件的绝对路径,图片支持PNG、JPEG、JPG、GIF格式, 像素不超750 x 1334,同时文件大小不超过 300K,否则可能报错
$result = $app->content_security->checkImage('/path/to/the/image');
// 正常返回 0
{"errcode": "0", "errmsg": "ok"}
// 当图片文件内含有敏感内容,则返回 87014
{"errcode": 87014, "errmsg": "risky content"}
目前上述两个接口仅支持在小程序,示例中的 $app
表示小程序实例,即:
use EasyWeChat\Factory;
$config = [
'app_id' => 'wx3cf0f39249eb0exx',
'secret' => 'f1c242f4f28f735d4687abb469072axx',
// 下面为可选项
// 指定 API 调用返回结果的类型:array(default)/collection/object/raw/自定义类名
'response_type' => 'array',
'log' => [
'level' => 'debug',
'file' => __DIR__.'/wechat.log',
],
];
$app = Factory::miniProgram($config);
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/express/by-business/logistics.getAllDelivery.html
$app->express->listProviders();
{
"count": 8,
"data": [
{
"delivery_id": "BEST",
"delivery_name": "百世快递"
},
...
]
}
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/express/by-business/logistics.addOrder.html
$app->express->createWaybill($data);
// 成功返回
{
"order_id": "01234567890123456789",
"waybill_id": "123456789",
"waybill_data": [
{
"key": "SF_bagAddr",
"value": "广州"
},
{
"key": "SF_mark",
"value": "101- 07-03 509"
}
]
}
// 失败返回
{
"errcode": 9300501,
"errmsg": "delivery logic fail",
"delivery_resultcode": 10002,
"delivery_resultmsg": "客户密码不正确"
}
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/express/by-business/logistics.cancelOrder.html
$app->express->deleteWaybill($data);
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/express/by-business/logistics.getOrder.html
$app->express->getWaybill($data);
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/express/by-business/logistics.getPath.html
$app->express->getWaybillTrack($data);
仅在使用加盟类快递公司时,才可以调用。
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/express/by-business/logistics.getQuota.html
$app->express->getBalance($deliveryId, $bizId);
// 例如:
$app->express->getBalance('YTO', 'xyz');
若要用微信打单 PC 软件,才需要调用。
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/express/by-business/logistics.updatePrinter.html
$app->express->bindPrinter($openid);
若需要使用微信打单 PC 软件,才需要调用。
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/express/by-business/logistics.updatePrinter.html
$app->express->unbindPrinter($openid);
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/soter/soter.verifySignature.html
$app->soter->verifySignature($openid, $json, $signature);
返回值示例:
{"is_ok": true}
参数说明:
- string $openid - 用户 openid
- string $json - 通过 wx.startSoterAuthentication 成功回调获得的 resultJSON 字段
- string $signature - 通过 wx.startSoterAuthentication 成功回调获得的 resultJSONSignature 字段
微信文档:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/plugin-management/pluginManager.applyPlugin.html
$pluginAppId = 'xxxxxxxxx';
$app->plugin->apply($pluginAppId);
$pluginAppId = 'xxxxxxxxx';
$app->plugin->unbind($pluginAppId);
$app->plugin->list();
$page = 1;
$size = 10;
$app->plugin_dev->getUsers($page, $size);
$appId = 'wxxxxxxxxxxxxxx';
$app->plugin_dev->agree($appId);
$app->plugin_dev->refuse('拒绝理由');
$app->plugin_dev->delete();
微信文档:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/nearby-poi/nearbyPoi.add.html
$params = [
'kf_info' => '{"open_kf":true,"kf_headimg":"http://mmbiz.qpic.cn/mmbiz_jpg/kKMgNtnEfQzDKpLXYhgo3W3Gndl34gITqmP914zSwhajIEJzUPpx40P7R8fRe1QmicneQMhFzpZNhSLjrvU1pIA/0?wx_fmt=jpeg","kf_name":"Harden"}',
'pic_list' => '{"list":["http://mmbiz.qpic.cn/mmbiz_jpg/kKMgNtnEfQzDKpLXYhgo3W3Gndl34gITqmP914zSwhajIEJzUPpx40P7R8fRe1QmicneQMhFzpZNhSLjrvU1pIA/0?wx_fmt=jpeg","http://mmbiz.qpic.cn/mmbiz_jpg/kKMgNtnEfQzDKpLXYhgo3W3Gndl34gITRneE5FS9uYruXGMmrtmhsBySwddEWUGOibG8Ze2NT5E3Dyt79I0htNg/0?wx_fmt=jpeg"]}',
'service_infos' => '{"service_infos":[{"id":2,"type":1,"name":"快递","appid":"wx1373169e494e0c39","path":"index"},{"id":0,"type":2,"name":"自定义","appid":"wx1373169e494e0c39","path":"index"}]}',
'store_name' => '羊村小马烧烤',
'contract_phone' => '111111111',
'hour' => '00:00-11:11',
'company_name' => '深圳市腾讯计算机系统有限公司',
'credential' => '156718193518281',
'address' => '新疆维吾尔自治区克拉玛依市克拉玛依区碧水路15-1-8号(碧水云天广场)',
'qualification_list' => '3LaLzqiTrQcD20DlX_o-OV1-nlYMu7sdVAL7SV2PrxVyjZFZZmB3O6LPGaYXlZWq',
];
$app->nearby_poi->add($params);
$poiId = 'xxxxxxxx';
$params = [
'kf_info' => '{"open_kf":true,"kf_headimg":"http://mmbiz.qpic.cn/mmbiz_jpg/kKMgNtnEfQzDKpLXYhgo3W3Gndl34gITqmP914zSwhajIEJzUPpx40P7R8fRe1QmicneQMhFzpZNhSLjrvU1pIA/0?wx_fmt=jpeg","kf_name":"Harden"}',
'pic_list' => '{"list":["http://mmbiz.qpic.cn/mmbiz_jpg/kKMgNtnEfQzDKpLXYhgo3W3Gndl34gITqmP914zSwhajIEJzUPpx40P7R8fRe1QmicneQMhFzpZNhSLjrvU1pIA/0?wx_fmt=jpeg","http://mmbiz.qpic.cn/mmbiz_jpg/kKMgNtnEfQzDKpLXYhgo3W3Gndl34gITRneE5FS9uYruXGMmrtmhsBySwddEWUGOibG8Ze2NT5E3Dyt79I0htNg/0?wx_fmt=jpeg"]}',
'service_infos' => '{"service_infos":[{"id":2,"type":1,"name":"快递","appid":"wx1373169e494e0c39","path":"index"},{"id":0,"type":2,"name":"自定义","appid":"wx1373169e494e0c39","path":"index"}]}',
'contract_phone' => '111111111',
'hour' => '00:00-11:11',
'company_name' => '深圳市腾讯计算机系统有限公司',
'credential' => '156718193518281',
'address' => '新疆维吾尔自治区克拉玛依市克拉玛依区碧水路15-1-8号(碧水云天广场)',
'qualification_list' => '3LaLzqiTrQcD20DlX_o-OV1-nlYMu7sdVAL7SV2PrxVyjZFZZmB3O6LPGaYXlZWq',
];
$app->nearby_poi->update($poiId, $params);
$poiId = 'xxxxxxxx';
$app->nearby_poi->delete($poiId);
$page = 1;
$pageRows = 10;
$app->nearby_poi->list($page, $pageRows);
$poiId = 'xxxxxxxx';
$status = 0; // 0: 不展示,1:展示
$app->nearby_poi->setVisibility($poiId, $status);
微信文档:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.addTemplate.html
$tid = 563; // 模板标题 id,可通过接口获取,也可登录小程序后台查看获取
$kidList = [1, 2]; // 开发者自行组合好的模板关键词列表,可以通过 `getTemplateKeywords` 方法获取
$sceneDesc = '提示用户图书到期'; // 服务场景描述,非必填
$app->subscribe_message->addTemplate($tid, $kidList, $sceneDesc);
$templateId = 'bDmywsp2oEHjwAadTGKkUHpC0RgBVPvfAM7Cu1s03z8';
$app->subscribe_message->deleteTemplate($templateId);
$app->subscribe_message->getCategory();
$tid = 563; //模板标题id,可通过接口获取,也可登小程序后台查看获取
$app->subscribe_message->getTemplateKeywords($tid);
$ids = [612, 613]; // 类目 id
$start = 0; // 用于分页,从 start 开始。从 0 开始计数。
$limit = 30; // 用于分页,表拉取 limit 条记录。最大 30。
$app->subscribe_message->getTemplateTitles($ids, $start, $limit);
$app->subscribe_message->getTemplates();
$data = [
'template_id' => 'bDmywsp2oEHjwAadTGKkUJ-eJEiMiOf7H-dZ7wjdw80', // 所需下发的订阅模板id
'touser' => 'oSyZp5OBNPBRhG-7BVgWxbiNZm', // 接收者(用户)的 openid
'page' => '', // 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。
'data' => [ // 模板内容,格式形如 { "key1": { "value": any }, "key2": { "value": any } }
'date01' => [
'value' => '2019-12-01',
],
'number01' => [
'value' => 10,
],
],
];
$app->subscribe_message->send($data);