├── miscellaneous.md ├── official-account ├── reply.md ├── events.md ├── base.md ├── index.md ├── message-transfer.md ├── accounts.md ├── comment.md ├── semantic.md ├── menu.md ├── template_message.md ├── user-tag.md ├── customer_service.md ├── data_cube.md ├── user.md ├── poi.md ├── goods.md ├── store.md ├── tutorial.md ├── configuration.md ├── material.md ├── oauth.md ├── server.md ├── broadcasting.md ├── messages.md ├── card.md └── shake-around.md ├── mini-program ├── auth.md ├── customer_service.md ├── decrypt.md ├── index.md ├── soter.md ├── data_cube.md ├── template_message.md ├── plugin.md ├── express.md ├── app_code.md └── nearby_poi.md ├── micro-merchant ├── media.md ├── withdraw.md ├── certficates.md ├── material.md ├── upgrade.md ├── submit-application.md ├── merchant-config.md └── index.md ├── open-work ├── work.md ├── index.md ├── service.md ├── provider.md └── server.md ├── customize ├── replace-service.md ├── access_token.md └── cache.md ├── payment ├── reverse.md ├── bill.md ├── security.md ├── refund.md ├── index.md ├── scan-pay.md ├── transfer.md ├── redpack.md ├── order.md ├── notify.md └── jssdk.md ├── basic-services ├── url.md ├── qrcode.md ├── jssdk.md ├── content_security.md └── media.md ├── installation.md ├── wework ├── agents.md ├── index.md ├── message.md ├── server.md ├── media.md ├── menu.md ├── oauth.md ├── oa.md ├── invoice.md ├── group-robot.md ├── contacts.md └── external-contact.md ├── integration.md ├── README.md ├── contributing.md ├── open-platform ├── index.md ├── server.md └── authorizer-delegate.md ├── overview.md ├── index.md └── troubleshooting.md /miscellaneous.md: -------------------------------------------------------------------------------- 1 | # 其它 2 | 3 | 4 | ### 其它 -------------------------------------------------------------------------------- /official-account/reply.md: -------------------------------------------------------------------------------- 1 | # 自动回复 2 | 3 | ## 获取当前设置的回复规则 4 | 5 | ```php 6 | $app->auto_reply->current(); 7 | ``` -------------------------------------------------------------------------------- /official-account/events.md: -------------------------------------------------------------------------------- 1 | # 事件 2 | 3 | 4 | 5 | 更多请参考:[服务端](server.html) 6 | 7 | 关于事件类型请参考微信官方文档:http://mp.weixin.qq.com/wiki/ 8 | -------------------------------------------------------------------------------- /mini-program/auth.md: -------------------------------------------------------------------------------- 1 | # 微信登录 2 | 3 | ## 根据 jsCode 获取用户 session 信息 4 | 5 | API: 6 | 7 | ```php 8 | $app->auth->session(string $code); 9 | ``` 10 | -------------------------------------------------------------------------------- /mini-program/customer_service.md: -------------------------------------------------------------------------------- 1 | # 客服消息 2 | 3 | ## 获取实例 4 | 5 | ```php 6 | $service = $app->customer_service; 7 | ``` 8 | 9 | > 使用方法详看公众号-客服消息章节。 10 | 11 | -------------------------------------------------------------------------------- /micro-merchant/media.md: -------------------------------------------------------------------------------- 1 | # 图片上传 2 | 上传证件照片。支持 jpeg、jpg、bmp、png 格式,图片大小不超过2M。 3 | 4 | ```php 5 | // $path string 图片路径 6 | $response = $app->media->upload($path); 7 | ``` 8 | -------------------------------------------------------------------------------- /open-work/work.md: -------------------------------------------------------------------------------- 1 | # 企业 2 | 3 | 4 | ### 获取授权企业的相关信息 5 | 6 | 7 | ```php 8 | 9 | $work = $app->work('授权企业的corp_id','授权企业的永久授权码'); 10 | 11 | ``` 12 | 13 | 然后就可以像企业微信一样 获取相关的数据信息 -------------------------------------------------------------------------------- /mini-program/decrypt.md: -------------------------------------------------------------------------------- 1 | # 微信小程序消息解密 2 | 3 | ## 比如获取电话等功能,信息是加密的,需要解密。 4 | 5 | API: 6 | 7 | ```php 8 | $decryptedData = $app->encryptor->decryptData($session, $iv, $encryptedData); 9 | ``` 10 | -------------------------------------------------------------------------------- /official-account/base.md: -------------------------------------------------------------------------------- 1 | # 基础接口 2 | 3 | ## 清理接口调用次数 4 | 5 | > 此接口官方有每月调用限制,不可随意调用 6 | 7 | ```php 8 | $app->base->clearQuota(); 9 | ``` 10 | 11 | ## 获取微信服务器 IP (或IP段) 12 | 13 | ```php 14 | $app->base->getValidIps(); 15 | ``` -------------------------------------------------------------------------------- /customize/replace-service.md: -------------------------------------------------------------------------------- 1 | # 自定义服务模块 2 | 3 | 由于使用了容器模式来组织各模块的实例,意味着你可以比较容易的替换掉已经有的服务,以公众号服务为例: 4 | 5 | ```php 6 | 7 | <...> 8 | 9 | $app = Factory::officialAccount($config); 10 | 11 | $app->rebind('request', new MyCustomRequest(...)); 12 | ``` 13 | 14 | 这里的 `request` 为 SDK 内部服务名称。 15 | -------------------------------------------------------------------------------- /micro-merchant/withdraw.md: -------------------------------------------------------------------------------- 1 | # 提现相关 2 | 3 | ## 查询提现状态 4 | 5 | ```php 6 | $response = $app->withdraw->queryWithdrawalStatus($date, $subMchId = ''); 7 | ``` 8 | ## 重新发起提现 9 | 10 | ```php 11 | $response = $app->withdraw->requestWithdraw($date, $subMchId = ''); 12 | ``` 13 | 14 | > 以上接口调用过 `setSubMchId` 方法则无需传入 `sub_mch_id` 参数 -------------------------------------------------------------------------------- /payment/reverse.md: -------------------------------------------------------------------------------- 1 | # 撤销订单 2 | 3 | 目前只有 **刷卡支付** 有此功能。 4 | 5 | > 调用支付接口后请勿立即调用撤销订单API,建议支付后至少15s后再调用撤销订单接口。 6 | 7 | ## 通过内部订单号撤销订单 8 | 9 | ```php 10 | $app->reverse->byOutTradeNumber("商户系统内部的订单号(out_trade_no)"); 11 | ``` 12 | 13 | ## 通过微信订单号撤销订单 14 | 15 | ```php 16 | $app->reverse->byTransactionId("微信的订单号(transaction_id)"); 17 | ``` 18 | -------------------------------------------------------------------------------- /basic-services/url.md: -------------------------------------------------------------------------------- 1 | # 短网址服务 2 | 3 | 主要使用场景: 开发者用于生成二维码的原链接(商品、支付二维码等)太长导致扫码速度和成功率下降,将原长链接通过此接口转成短链接再生成二维码将大大提升扫码速度和成功率。 4 | 5 | ## 长链接转短链接 6 | 7 | ```php 8 | $shortUrl = $app->url->shorten('https://easywechat.com'); 9 | // 10 | ( 11 | [errcode] => 0 12 | [errmsg] => ok 13 | [short_url] => https://w.url.cn/s/Aq7jWrd 14 | ) 15 | ``` -------------------------------------------------------------------------------- /payment/bill.md: -------------------------------------------------------------------------------- 1 | # 对账单 2 | 3 | ## 下载对账单 4 | 5 | > 调用参数正确会返回一个 `EasyWeChat\Kernel\Http\StreamResponse` 对象,否则会返回相应错误信息 6 | 7 | Example: 8 | 9 | ```php 10 | $bill = $app->bill->get('20140603'); // type: ALL 11 | // or 12 | $bill = $app->bill->get('20140603', 'SUCCESS'); // type: SUCCESS 13 | 14 | // 调用正确,`$bill` 为 csv 格式的内容,保存为文件: 15 | $bill->saveAs('your/path/to', 'file-20140603.csv'); 16 | ``` 17 | 18 | 第二个参数为账单类型,参考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6 中 `bill_type`,默认为 `ALL` 19 | -------------------------------------------------------------------------------- /official-account/index.md: -------------------------------------------------------------------------------- 1 | ## 公众号 2 | 3 | 公众号的各模块相对比较统一,用法如下: 4 | 5 | 6 | ```php 7 | use EasyWeChat\Factory; 8 | 9 | $config = [ 10 | 'app_id' => 'wx3cf0f39249eb0exx', 11 | 'secret' => 'f1c242f4f28f735d4687abb469072axx', 12 | 13 | // 指定 API 调用返回结果的类型:array(default)/collection/object/raw/自定义类名 14 | 'response_type' => 'array', 15 | 16 | //... 17 | ]; 18 | 19 | $app = Factory::officialAccount($config); 20 | ``` 21 | 22 | `$app` 在所有相关公众号的的文档都是指 `Factory::officialAccount` 得到的实例,就不在每个页面单独写了。 -------------------------------------------------------------------------------- /official-account/message-transfer.md: -------------------------------------------------------------------------------- 1 | # 多客服消息转发 2 | 3 | 多客服的消息转发绝对是超级的简单,转发的消息类型为 `transfer`: 4 | 5 | ```php 6 | 7 | use EasyWeChat\Kernel\Messages\Transfer; 8 | 9 | // 转发收到的消息给客服 10 | $app->server->push(function($message) { 11 | return new Transfer(); 12 | }); 13 | 14 | $response = $app->server->serve(); 15 | ``` 16 | 17 | 当然,你也可以指定转发给某一个客服: 18 | 19 | ```php 20 | use EasyWeChat\Kernel\Messages\Transfer; 21 | 22 | $app->server->push(function($message) { 23 | return new Transfer($account); 24 | }); 25 | ``` -------------------------------------------------------------------------------- /micro-merchant/certficates.md: -------------------------------------------------------------------------------- 1 | # 获取平台证书 2 | 调用获取平台证书接口之前,请前往微信支付商户平台升级API证书,升级后才可成功调用本接口。 3 | 4 | ```php 5 | // 获取到证书后可以做缓存处理,无需每次重新获取 6 | $response = $app->certficates->get(bool $returnRaw = false); 7 | 8 | // 获取到平台证书后,可以直接使用 setCertificate 方法把证书配置追加到配置项里面去 9 | $app->setCertificate(string $certificate, string $serialNo); 10 | ``` 11 | > $returnRaw 不填默认为false时,请确保你的PHP已安装了sodium扩展 12 | > 返回值:固定array格式的解密后的证书信息 13 | 14 | > $returnRaw 传入true时 15 | > 返回值:Response对象`$response->getBody()->getContents();`获取到微信返回xml原始数据 16 | -------------------------------------------------------------------------------- /installation.md: -------------------------------------------------------------------------------- 1 | # 安装 2 | 3 | 4 | ## 环境要求 5 | 6 | > - PHP >= 7.0 7 | > - [PHP cURL 扩展](http://php.net/manual/en/book.curl.php) 8 | > - [PHP OpenSSL 扩展](http://php.net/manual/en/book.openssl.php) 9 | > - [PHP SimpleXML 扩展](http://php.net/manual/en/book.simplexml.php) 10 | > - [PHP fileinfo 拓展](http://php.net/manual/en/book.fileinfo.php) 11 | 12 | Laravel 5 拓展包: [overtrue/laravel-wechat](https://github.com/overtrue/laravel-wechat) 13 | 14 | ## 安装 15 | 16 | 使用 [composer](http://getcomposer.org/): 17 | 18 | ```shell 19 | $ composer require overtrue/wechat:~4.0 -vvv 20 | ``` -------------------------------------------------------------------------------- /mini-program/index.md: -------------------------------------------------------------------------------- 1 | # 小程序 2 | 3 | 4 | ```php 5 | use EasyWeChat\Factory; 6 | 7 | $config = [ 8 | 'app_id' => 'wx3cf0f39249eb0exx', 9 | 'secret' => 'f1c242f4f28f735d4687abb469072axx', 10 | 11 | // 下面为可选项 12 | // 指定 API 调用返回结果的类型:array(default)/collection/object/raw/自定义类名 13 | 'response_type' => 'array', 14 | 15 | 'log' => [ 16 | 'level' => 'debug', 17 | 'file' => __DIR__.'/wechat.log', 18 | ], 19 | ]; 20 | 21 | $app = Factory::miniProgram($config); 22 | ``` 23 | 24 | `$app` 在所有相关小程序的文档都是指 `Factory::miniProgram` 得到的实例,就不在每个页面单独写了。 25 | -------------------------------------------------------------------------------- /wework/agents.md: -------------------------------------------------------------------------------- 1 | # 应用管理 2 | 3 | > {warning} 企业微信在17年11月对 API 进行了大量的改动,应用管理部分已经没啥用了 4 | 5 | 应用管理是企业微信中比较特别的地方,因为它的使用是不基于应用的,或者说基于任何一个应用都能访问这些 API,所以在用法上是直接调用 work 实例的 `agent` 属性。 6 | 7 | ```php 8 | $config = [ 9 | ... 10 | ]; 11 | 12 | $app = Factory::work($config); 13 | ``` 14 | 15 | ## 应用列表 16 | 17 | ```php 18 | $agents = $app->agent->list(); // 测试拿不到内容 19 | ``` 20 | 21 | ## 应用详情 22 | 23 | ```php 24 | $agents = $app->agent->get($agentId); // 只能传配置文件中的 id,API 改动所致 25 | ``` 26 | 27 | ## 设置应用 28 | 29 | ```php 30 | $agents = $app->agent->set($agentId, ['foo' => 'bar']); 31 | ``` 32 | -------------------------------------------------------------------------------- /wework/index.md: -------------------------------------------------------------------------------- 1 | ## 企业微信 2 | 3 | 企业微信的使用与公众号以及其它几个应用的使用方式都是一致的,使用 `\EasyWeChat\Factory::work($config)` 来初始化: 4 | 5 | ```php 6 | $config = [ 7 | 'corp_id' => 'xxxxxxxxxxxxxxxxx', 8 | 9 | 'agent_id' => 100020, // 如果有 agend_id 则填写 10 | 'secret' => 'xxxxxxxxxx', 11 | 12 | // 指定 API 调用返回结果的类型:array(default)/collection/object/raw/自定义类名 13 | 'response_type' => 'array', 14 | 15 | 'log' => [ 16 | 'level' => 'debug', 17 | 'file' => __DIR__.'/wechat.log', 18 | ], 19 | ]; 20 | 21 | $app = Factory::work($config); 22 | ``` 23 | 24 | 然后你就可以用 `$app` 来调用企业微信的服务了。 -------------------------------------------------------------------------------- /micro-merchant/material.md: -------------------------------------------------------------------------------- 1 | # 商户信息修改 2 | ## 修改结算银行卡 3 | 4 | ```php 5 | $response = $app->material->setSettlementCard([ 6 | // 'sub_mch_id' => '1230000109', 7 | 'account_number' => '银行卡号', 8 | 'bank_name' => '开户银行全称(含支行)', 9 | 'account_bank' => '开户银行', 10 | 'bank_address_code' => '开户银行省市编码', 11 | ]); 12 | ``` 13 | ## 修改联系信息 14 | 15 | ```php 16 | $response = $app->material->updateContact([ 17 | // 'sub_mch_id' => '1230000109', 18 | 'mobile_phone' => '手机号', 19 | 'email' => '邮箱', 20 | 'merchant_name' => '商户简称', 21 | ]); 22 | ``` 23 | 24 | > 以上接口调用过 `setSubMchId` 方法则无需传入 `sub_mch_id` 参数 -------------------------------------------------------------------------------- /micro-merchant/upgrade.md: -------------------------------------------------------------------------------- 1 | # 商户升级 2 | ## 提交升级申请单 3 | 4 | 使用“提交升级申请单”接口为小微商户发起升级流程,根据商户实际情况可升级为个体户、企业、党政、机关及事业单位、其他组织。。 5 | 6 | ```php 7 | $result = $app->upgrade([ 8 | 'organization_type' => '2', // 主体类型 9 | 'business_license_copy' => 'media_id', // 营业执照扫描件 10 | // ... 11 | // 参数太多就不一一列出,自行根据 (小微商户专属文档 -> 提交升级申请单API) 填写 12 | ]); 13 | ``` 14 | 15 | ## 查询升级申请单状态 16 | 使用“提交升级申请单”接口后,可不定期调用此接口查询申请单状态(建议提交申请后1分钟查询),直至申请单为“完成”状态。 17 | 18 | 1)若申请状态为待账户验证,请按接口中的指引完成账户验证 19 | 20 | 2)若申请状态为审核中,微信支付会在2个工作日内完成资料审核 21 | 22 | 3)若申请状态为待签约,接口会返回签约二维码 23 | 24 | ```php 25 | $app->order->getUpgradeStatus(string $subMchId = ''); 26 | ``` 27 | > 调用该接口前调用过 `setSubMchId` 方法则无需传入 `$subMchId` 参数 28 | -------------------------------------------------------------------------------- /official-account/accounts.md: -------------------------------------------------------------------------------- 1 | # 多账号接入 2 | 3 | 如果你想使用本项目接入多个公众号,在本程序中,您可以为每个帐号都设置一个 id,此 id 对应了该帐号的 appid、token 等信息。 4 | 如下表 5 | 6 | | id | appId | secret | 其它... | 7 | | ---- | -------------------- | ---------------------------------- | ----- | 8 | | 1 | `wx3cf0f39249eb0e60` | `f28f735d4f1c242f4687abb469072a29` | ... | 9 | | 2 | `wx49eb0e63cf0f39s2` | `8f735d4687abb469f1c2422a29f4f207` | ... | 10 | | N | `wx5cfeb0e60f392490` | `35f8f27d46f1c242f487a9072a29bb46` | ... | 11 | 12 | 在微信公众平台的设置中,您可以将您帐号中平台的 `url` 设置为 `您的网址/?id=xxx`,如: 13 | 14 | ``` 15 | http://www.easywechat.com/wechat?id=1 16 | ``` 17 | 18 | 而在程序入口处,根据 `id` 查找对应帐号的 `appid` 和 其它信息来创建配置数组创建实例即可。 19 | -------------------------------------------------------------------------------- /micro-merchant/submit-application.md: -------------------------------------------------------------------------------- 1 | # 商户入驻 2 | ## 申请入驻 3 | 4 | 使用申请入驻接口提交你的小微商户资料。 5 | 6 | ```php 7 | $result = $app->submitApplication([ 8 | 'business_code' => '123456', // 业务申请编号 9 | 'id_card_copy' => 'media_id', // 身份证人像面照片 10 | // ... 11 | // 参数太多就不一一列出,自行根据 (小微商户专属文档 -> 申请入驻api) 填写 12 | ]); 13 | ``` 14 | 15 | ## 查询申请状态 16 | 17 | 使用申请入驻接口提交小微商户资料后,一般5分钟左右可以通过该查询接口查询具体的申请结果。 18 | 19 | ```php 20 | $applymentId = '商户申请单号(applyment_id 申请入驻接口返回)'; 21 | $businessCode = '业务申请编号(business_code)'; 22 | $app->order->getStatus(string $applymentId, string $businessCode = ''); 23 | ``` 24 | > 商户申请单号和业务申请编号填写一个就行了,当 `applyment_id` 已填写时,`business_code` 字段无效。 25 | 26 | 当查询申请状态为待签约,接口会一并返回签约二维码,服务商需引导商户使用本人微信扫码完成协议签署。 27 | -------------------------------------------------------------------------------- /open-work/index.md: -------------------------------------------------------------------------------- 1 | # 企业微信第三方服务商 2 | 3 | ## 实例化 4 | 5 | ```php 6 | '服务商的corpid', 11 | 'secret' => '服务商的secret,在服务商管理后台可见', 12 | 'suite_id' => '以ww或wx开头应用id', 13 | 'suite_secret' => '应用secret', 14 | 'token' => '应用的Token', 15 | 'aes_key' => '应用的EncodingAESKey', 16 | 'reg_template_id' => '注册定制化模板ID', 17 | 'redirect_uri_install' => '安装应用的回调url(可选)', 18 | 'redirect_uri_single' => '单点登录回调url (可选)', 19 | 'redirect_uri_oauth' => '网页授权第三方回调url (可选)', 20 | 21 | ]; 22 | 23 | $app = Factory::openWork($config); 24 | ``` 25 | 26 | -------------------------------------------------------------------------------- /wework/message.md: -------------------------------------------------------------------------------- 1 | # 消息 2 | 3 | ## 主动发送消息 4 | 5 | ```php 6 | use EasyWeChat\Kernel\Messages\TextCard; 7 | 8 | 9 | // 获取 Messenger 实例 10 | $messenger = $app->messenger; 11 | 12 | // 准备消息 13 | $message = new TextCard([ 14 | 'title' => '你的请假单审批通过', 15 | 'description' => '单号:1928373, ....', 16 | 'url' => 'http://easywechat.com/oa/....' 17 | ]); 18 | 19 | // 发送 20 | $messenger->message($message)->toUser('overtrue')->send(); 21 | 22 | ``` 23 | 24 | 你也可以很方便的发送普通文本消息: 25 | 26 | ```php 27 | $messenger->message('你的请假单(单号:1928373)已经审批通过!')->toUser('overtrue')->send(); 28 | // 或者写成 29 | $messenger->toUser('overtrue')->send('你的请假单(单号:1928373)已经审批通过!'); 30 | ``` 31 | 32 | ## 接收消息 33 | 34 | 被动接收消息,与回复消息,请参考:[服务端](server) 35 | -------------------------------------------------------------------------------- /wework/server.md: -------------------------------------------------------------------------------- 1 | ## 服务端 2 | 3 | 我们在企业微信应用开启接收消息的功能,将设置页面的 token 与 aes key 配置到 agents 下对应的应用内: 4 | 5 | ```php 6 | $config = [ 7 | 'corp_id' => 'xxxxxxxxxxxxxxxxx', 8 | 9 | 'agent_id' => 100022, 10 | 'secret' => 'xxxxxxxxxx', 11 | 12 | // server config 13 | 'token' => 'xxxxxxxxx', 14 | 'aes_key' => 'xxxxxxxxxxxxxxxxxx', 15 | 16 | //... 17 | ]; 18 | 19 | $app = Factory::work($config); 20 | ``` 21 | 22 | 接着配置服务端与公众号的服务端用法一样: 23 | 24 | ```php 25 | $app->server->push(function(){ 26 | return 'Hello easywechat.'; 27 | }); 28 | 29 | $response = $app->server->serve(); 30 | 31 | $response->send(); 32 | ``` 33 | 34 | `$response` 为 `Symfony\Component\HttpFoundation\Response` 实例,根据你的框架情况来决定如何处理响应。 35 | -------------------------------------------------------------------------------- /mini-program/soter.md: -------------------------------------------------------------------------------- 1 | # 生物认证 2 | 3 | ## 生物认证秘钥签名验证 4 | 5 | > https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/soter/soter.verifySignature.html 6 | 7 | ```php 8 | $app->soter->verifySignature($openid, $json, $signature); 9 | ``` 10 | 11 | 返回值示例: 12 | ```json 13 | { 14 | "is_ok": true 15 | } 16 | ``` 17 | 18 | 参数说明: 19 | 20 | > - string $openid - 用户 openid 21 | > - string $json - 通过 [wx.startSoterAuthentication](https://developers.weixin.qq.com/miniprogram/dev/api/open-api/soter/wx.startSoterAuthentication.html) 成功回调获得的 resultJSON 字段 22 | > - string $signature - 通过 [wx.startSoterAuthentication](https://developers.weixin.qq.com/miniprogram/dev/api/open-api/soter/wx.startSoterAuthentication.html) 成功回调获得的 resultJSONSignature 字段 -------------------------------------------------------------------------------- /integration.md: -------------------------------------------------------------------------------- 1 | # 在框架中使用 2 | 3 | EasyWeChat 是一个通用的 Composer 包,所以不需要对框架单独做修改,只要支持 Composer 就能直接使用,当然了,为了更方便的使用,我们收集了以下框架单独提供的拓展包: 4 | 5 | ## Laravel 6 | 7 | > - [overtrue/laravel-wechat](https://github.com/overtrue/laravel-wechat) 8 | 9 | 10 | ## Symfony 11 | 12 | > - [lilocon/WechatBundle](https://github.com/lilocon/WechatBundle) 13 | 14 | ## Yii 15 | 16 | > - [jianyan74/yii2-easy-wechat](https://github.com/jianyan74/yii2-easy-wechat) 适用于 EasyWeChat 4.x 17 | > - [max-wen/yii2-easy-wechat](https://github.com/max-wen/yii2-easy-wechat) 适用于 EasyWeChat 3.x 18 | 19 | ## ThinkPHP 20 | 21 | > - [naixiaoxin/think-wechat](https://github.com/qiqizjl/think-wechat) 22 | 23 | ## CI 24 | 25 | TODO 26 | 27 | ## Phalcon 28 | 29 | TODO 30 | 31 | ... more 32 | 33 | -------------------------------------------------------------------------------- /mini-program/data_cube.md: -------------------------------------------------------------------------------- 1 | # 数据统计与分析 2 | 3 | 获取小程序概况趋势: 4 | 5 | ```php 6 | $app->data_cube->summaryTrend('20170313', '20170313') 7 | ``` 8 | 开始日期与结束日期的格式为 yyyymmdd。 9 | 10 | ## API 11 | 12 | > - `summaryTrend(string $from, string $to);` 概况趋势 13 | > - `dailyVisitTrend(string $from, string $to);` 访问日趋势 14 | > - `weeklyVisitTrend(string $from, string $to);` 访问周趋势 15 | > - `monthlyVisitTrend(string $from, string $to);` 访问月趋势 16 | > - `visitDistribution(string $from, string $to);` 访问分布 17 | > - `dailyRetainInfo(string $from, string $to);` 访问日留存 18 | > - `weeklyRetainInfo(string $from, string $to);` 访问周留存 19 | > - `monthlyRetainInfo(string $from, string $to);` 访问月留存 20 | > - `visitPage(string $from, string $to);` 访问页面 21 | > - `userPortrait(string $from, string $to);` 用户画像分布数据 22 | 23 | -------------------------------------------------------------------------------- /wework/media.md: -------------------------------------------------------------------------------- 1 | # 临时素材 2 | 3 | 它的使用是不基于应用的,或者说基于任何一个应用都能访问这些 API,所以在用法上是直接调用 work 实例的 `media` 属性: 4 | 5 | **上传的媒体文件限制:** 6 | 7 | 所有文件size必须大于5个字节 8 | 9 | > - 图片(image):2MB,支持JPG,PNG格式 10 | > - 语音(voice):2MB,播放长度不超过60s,支持AMR格式 11 | > - 视频(video):10MB,支持MP4格式 12 | > - 普通文件(file):20MB 13 | 14 | ## 上传图片 15 | 16 | > 注意:微信图片上传服务有敏感检测系统,图片内容如果含有敏感内容,如色情,商品推广,虚假信息等,上传可能失败。 17 | 18 | ```php 19 | $app->media->uploadImage($path); // $path 为本地文件路径 20 | ``` 21 | 22 | ## 上传声音 23 | 24 | ```php 25 | $app->media->uploadVoice($path); 26 | ``` 27 | 28 | ## 上传视频 29 | 30 | ```php 31 | $app->media->uploadVideo($path, $title, $description); 32 | ``` 33 | 34 | ## 上传普通文件 35 | 36 | ```php 37 | $app->media->uploadFile($path); 38 | ``` 39 | 40 | ## 获取素材 41 | 42 | ```php 43 | $app->media->get($mediaId); 44 | ``` -------------------------------------------------------------------------------- /customize/access_token.md: -------------------------------------------------------------------------------- 1 | # Access Token 2 | 3 | 4 | 我们一个 SDK 应用在初始化以后,你可以在任何时机从应用中拿到该配置下的 Access Token 实例: 5 | 6 | ```php 7 | use EasyWeChat\Factory; 8 | 9 | $config = [ 10 | //... 11 | ]; 12 | 13 | $app = Factory::officialAccount($config); 14 | 15 | // 获取 access token 实例 16 | $accessToken = $app->access_token; 17 | $token = $accessToken->getToken(); // token 数组 token['access_token'] 字符串 18 | $token = $accessToken->getToken(true); // 强制重新从微信服务器获取 token. 19 | ``` 20 | 21 | ## 修改 `$app` 的 Access Token 22 | 23 | ```php 24 | $app['access_token']->setToken($newAccessToken, 7200); 25 | ``` 26 | 27 | 例如: 28 | 29 | ```php 30 | $app['access_token']->setToken('ccfdec35bd7ba359f6101c2da321d675'); 31 | // 或者指定过期时间 32 | $app['access_token']->setToken('ccfdec35bd7ba359f6101c2da321d675', 3600); // 单位:秒 33 | ``` 34 | -------------------------------------------------------------------------------- /micro-merchant/merchant-config.md: -------------------------------------------------------------------------------- 1 | # 小微商户配置 2 | 3 | ## 关注功能配置 4 | 5 | ```php 6 | $response = $app->merchantConfig->setFollowConfig(string $subAppId, string $subscribeAppId, string $receiptAppId = '', string $subMchId = ''); 7 | ``` 8 | > 注意:`subscribe_appid`,`receipt_appid` 两个参数二选一,两个都填的话SDK默认选第一个,具体请参考小微商户专属文档 9 | 10 | ## 开发配置新增支付目录 11 | 12 | ```php 13 | $response = $app->merchantConfig->addPath(string $jsapiPath, string $appId = '', string $subMchId = ''); 14 | ``` 15 | 16 | ## 新增对应APPID关联 17 | 18 | ```php 19 | $response = $app->merchantConfig->bindAppId(string $subAppId, string $appId = '', string $subMchId = ''); 20 | ``` 21 | 22 | ## 开发配置查询 23 | 24 | ```php 25 | $response = $app->merchantConfig->getConfig(string $subMchId = '', string $appId = ''); 26 | ``` 27 | 28 | > 以上接口调用过 `setSubMchId` 方法并且两个参数都传入过 则无需传入 `sub_mch_id` 和 `appid` 参数 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EasyWeChat 文档 2 | 3 | www.easywechat.com 4 | 5 | # 参与贡献 6 | 7 | 1. fork 当前库到你的名下 8 | 2. 选择你想要修改的语言版本,`zh-CN` 或者 `en` 9 | 3. 在你的本地修改完成审阅过后提交到你的仓库 10 | 4. 提交 PR 并描述你的修改,等待合并 11 | 12 | # 说明 13 | 14 | 本项目有俩目录:`zh-cn` 与 `en`,分别为中文版与英文版。 15 | 16 | # License 17 | 18 | 知识共享许可协议
EasyWeChat 官方文档overtrue 创作,采用 知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议进行许可。 -------------------------------------------------------------------------------- /wework/menu.md: -------------------------------------------------------------------------------- 1 | # 自定义菜单 2 | 3 | 自定义菜单是指为单个应用设置自定义菜单功能,所以在使用时请注意调用正确的应用实例。 4 | 5 | ```php 6 | $config = [ 7 | 'corp_id' => 'xxxxxxxxxxxxxxxxx', 8 |    'secret'   => 'xxxxxxxxxx', // 应用的 secret 9 | //... 10 | ]; 11 | $app = Factory::work($config); 12 | ``` 13 | 14 | ## 创建菜单 15 | 16 | ```php 17 | $menus = [ 18 | 'button' => [ 19 | [ 20 | 'name' => '首页', 21 | 'type' => 'view', 22 | 'url' => 'https://easywechat.com' 23 | ], 24 | [ 25 | 'name' => '关于我们', 26 | 'type' => 'view', 27 | 'url' => 'https://easywechat.com/about' 28 | ], 29 | //... 30 | ], 31 | ]; 32 | 33 | $app->menu->create($menus); 34 | ``` 35 | 36 | ## 获取菜单 37 | 38 | ```php 39 | $app->menu->get(); 40 | ``` 41 | 42 | ## 删除菜单 43 | 44 | ```php 45 | $app->menu->delete(); 46 | ``` 47 | -------------------------------------------------------------------------------- /mini-program/template_message.md: -------------------------------------------------------------------------------- 1 | # 模板消息 2 | 3 | ## 获取小程序模板库标题列表 4 | 5 | ``` 6 | $app->template_message->list($offset, $count); 7 | ``` 8 | 9 | ## 获取模板库某个模板标题下关键词库 10 | 11 | ``` 12 | $app->template_message->get($id); 13 | ``` 14 | 15 | ## 组合模板并添加至帐号下的个人模板库 16 | 17 | ``` 18 | $app->template_message->add($id, $keywordIdList); 19 | ``` 20 | 21 | ## 获取帐号下已存在的模板列表 22 | 23 | ``` 24 | $app->template_message->getTemplates($offset, $count); 25 | ``` 26 | 27 | ## 删除帐号下的某个模板 28 | 29 | ``` 30 | $app->template_message->delete($templateId); 31 | ``` 32 | 33 | ## 发送模板消息 34 | 35 | ```php 36 | $app->template_message->send([ 37 | 'touser' => 'user-openid', 38 | 'template_id' => 'template-id', 39 | 'page' => 'index', 40 | 'form_id' => 'form-id', 41 | 'data' => [ 42 | 'keyword1' => 'VALUE', 43 | 'keyword2' => 'VALUE2', 44 | // ... 45 | ], 46 | ]); 47 | ``` 48 | -------------------------------------------------------------------------------- /mini-program/plugin.md: -------------------------------------------------------------------------------- 1 | # 插件管理 2 | 3 | > 微信文档:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/plugin-management/pluginManager.applyPlugin.html 4 | 5 | ## 申请使用插件 6 | 7 | ```php 8 | $pluginAppId = 'xxxxxxxxx'; 9 | 10 | $app->plugin->apply($pluginAppId); 11 | ``` 12 | 13 | ## 删除已添加的插件 14 | 15 | ```php 16 | $pluginAppId = 'xxxxxxxxx'; 17 | 18 | $app->plugin->unbind($pluginAppId); 19 | ``` 20 | 21 | ## 查询已添加的插件 22 | 23 | ```php 24 | $app->plugin->list(); 25 | ``` 26 | 27 | ## 获取当前所有插件使用方 28 | 29 | ```php 30 | $page = 1; 31 | $size = 10; 32 | 33 | $app->plugin_dev->getUsers($page, $size); 34 | ``` 35 | 36 | ## 同意插件使用申请 37 | 38 | ```php 39 | $appId = 'wxxxxxxxxxxxxxx'; 40 | 41 | $app->plugin_dev->agree($appId); 42 | ``` 43 | 44 | ## 拒绝插件使用申请 45 | 46 | ```php 47 | $app->plugin_dev->refuse('拒绝理由'); 48 | ``` 49 | 50 | ## 删除已拒绝的申请者 51 | 52 | ```php 53 | $app->plugin_dev->delete(); 54 | ``` 55 | -------------------------------------------------------------------------------- /official-account/comment.md: -------------------------------------------------------------------------------- 1 | # 评论数据管理 2 | 3 | 4 | 5 | ## 打开已群发文章评论 6 | 7 | ```php 8 | $app->comment->open($msgId, $index = null); 9 | ``` 10 | 11 | ## 关闭已群发文章评论 12 | 13 | ```php 14 | $app->comment->close($msgId, $index = null); 15 | ``` 16 | 17 | ## 查看指定文章的评论数据 18 | 19 | ```php 20 | $app->comment->list(string $msgId, int $index, int $begin, int $count, int $type = 0); 21 | ``` 22 | 23 | ## 将评论标记精选 24 | 25 | ```php 26 | $app->comment->markElect(string $msgId, int $index, int $commentId); 27 | ``` 28 | 29 | ## 将评论取消精选 30 | 31 | ```php 32 | $app->comment->unmarkElect(string $msgId, int $index, int $commentId); 33 | ``` 34 | 35 | ## 删除评论 36 | 37 | ```php 38 | $app->comment->delete(string $msgId, int $index, int $commentId); 39 | ``` 40 | 41 | ## 回复评论 42 | 43 | ```php 44 | $app->comment->reply(string $msgId, int $index, int $commentId, string $content); 45 | ``` 46 | 47 | ## 删除回复 48 | 49 | ```php 50 | $app->comment->deleteReply(string $msgId, int $index, int $commentId); 51 | ``` 52 | -------------------------------------------------------------------------------- /wework/oauth.md: -------------------------------------------------------------------------------- 1 | # OAuth 2 | 3 | > {warning} 此文档为企业微信内部应用开发的网页授权 4 | 5 | [企业微信官方文档](https://work.weixin.qq.com/api/doc#90000/90135/91020) 6 | 7 | 创建实例: 8 | 9 | ```php 10 | $config = [ 11 | 'corp_id' => 'xxxxxxxxxxxxxxxxx', 12 | 'secret' => 'xxxxxxxxxx', // 应用的 secret 13 | 'agent_id' => 100001, 14 | ]; 15 | 16 | $app = Factory::work($config); 17 | ``` 18 | 19 | ## 跳转授权 20 | 21 | ```php 22 | // $callbackUrl 为授权回调地址 23 | $callbackUrl = 'https://xxx.xxx'; // 需设置可信域名 24 | 25 | // 返回一个 redirect 实例 26 | $redirect = $app->oauth->redirect($callbackUrl); 27 | 28 | // 获取企业微信跳转目标地址 29 | $targetUrl = $redirect->getTargetUrl(); 30 | 31 | // 直接跳转到企业微信授权 32 | $redirect->send(); 33 | ``` 34 | 35 | ## 获取授权用户信息 36 | 37 | 在回调页面中,你可以使用以下方式获取授权者信息: 38 | 39 | ```php 40 | $user = $app->oauth->detailed()->user(); 41 | 42 | // 获取用户信息 43 | $user->getId(); // 对应企业微信英文名(userid) 44 | $user->getOriginal(); // 获取企业微信接口返回的原始信息 45 | ``` 46 | 47 | 获取用户其他信息需调用通讯录接口,参考:[企业微信通讯录API](https://github.com/EasyWeChat/docs/blob/master/wework/contacts.md) 48 | ```php 49 | -------------------------------------------------------------------------------- /wework/oa.md: -------------------------------------------------------------------------------- 1 | # OA 2 | 3 | ```php 4 | $config = [ 5 | 'corp_id' => 'xxxxxxxxxxxxxxxxx', 6 | 'secret' => 'xxxxxxxxxx', 7 | //... 8 | ]; 9 | 10 | $app = Factory::work($config); 11 | ``` 12 | 13 | ## 获取打卡数据 14 | 15 | API: 16 | 17 | ```php 18 | mixed checkinRecords(int $startTime, int $endTime, array $userList, int $type = 3) 19 | ``` 20 | > {info} $type: 打卡类型 1:上下班打卡;2:外出打卡;3:全部打卡 21 | 22 | ```php 23 | // 全部打卡数据 24 | $app->oa->checkinRecords(1492617600, 1492790400, ["james","paul"]); 25 | 26 | // 获取上下班打卡 27 | $app->oa->checkinRecords(1492617600, 1492790400, ["james","paul"], 1); 28 | 29 | // 获取外出打卡 30 | $app->oa->checkinRecords(1492617600, 1492790400, ["james","paul"], 2); 31 | ``` 32 | 33 | ## 获取审批数据 34 | 35 | API: 36 | 37 | ```php 38 | mixed approvalRecords(int $startTime, int $endTime, int $nextNumber = null) 39 | ``` 40 | 41 | > {info} $nextNumber: 第一个拉取的审批单号,不填从该时间段的第一个审批单拉取 42 | 43 | ```php 44 | $app->oa->approvalRecords(1492617600, 1492790400); 45 | 46 | // 指定第一个拉取的审批单号,不填从该时间段的第一个审批单拉取 47 | $app->oa->approvalRecords(1492617600, 1492790400, '201704240001'); 48 | ``` 49 | -------------------------------------------------------------------------------- /open-work/service.md: -------------------------------------------------------------------------------- 1 | # 第三方应用接口 2 | 3 | 4 | ## 获取预授权码 5 | 6 | ```php 7 | $app->corp->getPreAuthCode(); 8 | ``` 9 | 10 | ## 设置授权配置 11 | 12 | ```php 13 | $app->corp->setSession(string $preAuthCode, array $sessionInfo); 14 | ``` 15 | 16 | ## 获取企业永久授权码 17 | 18 | ```php 19 | $app->corp->getPermanentByCode(string $preAuthCode); //传入临时授权码 20 | ``` 21 | 22 | ## 获取企业授权信息 23 | 24 | ```php 25 | $app->corp->getAuthorization(string $authCorpId, string $permanentCode); //$authCorpId 授权的企业corp_id $permanentCode 授权的永久授权码 26 | ``` 27 | 28 | ## 获取应用的管理员列表 29 | 30 | ```php 31 | $app->corp->getManagers(string $authCorpId, string $agentId); //$authCorpId 授权的企业corp_id $agentId 授权方安装的应用agentid 32 | ``` 33 | 34 | ## 网页授权登录第三方 35 | 36 | ### 构造第三方oauth2链接 37 | 38 | ```php 39 | //$redirectUri 回调uri 这里可以覆盖 默认读取配置文件 40 | //$scope 应用授权作用域。 41 | //$state 自定义安全值 42 | $app->corp->getOAuthRedirectUrl(string $redirectUri = '', string $scope = 'snsapi_userinfo', string $state = null); 43 | ``` 44 | 45 | ### 第三方根据code获取企业成员信息 46 | 47 | ```php 48 | $app->corp->getUserByCode(string $code); 49 | ``` 50 | 51 | ### 第三方使用user_ticket获取成员详情 52 | 53 | ```php 54 | $app->corp->getUserByTicket(string $userTicket); 55 | ``` 56 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | # 贡献代码 2 | 3 | ## 开发 4 | 5 | 我们欢迎广大开发者贡献大家的智慧,让我们共同让它变得更完美. 6 | 7 | ### 开始之前 8 | 9 | 请严格遵循以下代码标准: 10 | 11 | > - [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md). 12 | > - 使用 4 个空格作为缩进。 13 | 14 | ### 流程 15 | 16 | 1. Fork [overtrue/wechat](https://github.com/overtrue/wechat) 到本地. 17 | 2. 创建新的分支: 18 | 19 | ```shell 20 | $ git checkout -b new_feature 21 | ``` 22 | 23 | 3. 编写代码。 24 | 4. Push 到你的分支: 25 | 26 | ```shell 27 | $ git push origin new_feature 28 | ``` 29 | 30 | 5. 创建 Pull Request 并描述你完成的功能或者做出的修改。 31 | 32 | > {warning} 注意:注释请使用英文 33 | 34 | ## 更新文档 35 | 36 | 我们的文档也是开源的,源代码在 [EasyWeChat/docs](https://github.com/EasyWeChat/docs)。 37 | 38 | ### 流程 39 | 40 | 1. Fork [EasyWeChat/docs](https://github.com/EasyWeChat/docs) 41 | 2. Clone 到你的电脑: 42 | 43 | ```shell 44 | $ git clone https://github.com//site.git 45 | $ cd docs 46 | ``` 47 | 48 | 3. 创建新的分支,编辑文档 49 | 4. Push 到你的分支。 50 | 5. 创建 Pull Request 并描述你完成的功能或者做出的修改。 51 | 52 | ## 报告 Bug 53 | 54 | 当你在使用过程中遇到问题,请查阅 [疑难解答](troubleshooting.html) 或者在这里提问 [GitHub](https://github.com/overtrue/wechat/issues). 如果还是不能解决你的问题,请到 GitHub 联系我们。 55 | 56 | [overtrue/wechat]: https://github.com/overtrue/wechat 57 | -------------------------------------------------------------------------------- /basic-services/qrcode.md: -------------------------------------------------------------------------------- 1 | # 二维码 2 | 3 | 目前有 2 种类型的二维码: 4 | 5 | 1. 临时二维码,是有过期时间的,最长可以设置为在二维码生成后的 **30天**后过期,但能够生成较多数量。临时二维码主要用于帐号绑定等不要求二维码永久保存的业务场景 6 | 2. 永久二维码,是无过期时间的,但数量较少(目前为最多10万个)。永久二维码主要用于适用于帐号绑定、用户来源统计等场景。 7 | 8 | ## 创建临时二维码 9 | 10 | ```php 11 | $result = $app->qrcode->temporary('foo', 6 * 24 * 3600); 12 | 13 | // Array 14 | // ( 15 | // [ticket] => gQFD8TwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyTmFjVTRWU3ViUE8xR1N4ajFwMWsAAgS2uItZAwQA6QcA 16 | // [expire_seconds] => 518400 17 | // [url] => http://weixin.qq.com/q/02NacU4VSubPO1GSxj1p1k 18 | // ) 19 | ``` 20 | 21 | ## 创建永久二维码 22 | 23 | ```php 24 | $result = $app->qrcode->forever(56);// 或者 $app->qrcode->forever("foo"); 25 | // Array 26 | // ( 27 | // [ticket] => gQFD8TwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyTmFjVTRWU3ViUE8xR1N4ajFwMWsAAgS2uItZAwQA6QcA 28 | // [url] => http://weixin.qq.com/q/02NacU4VSubPO1GSxj1p1k 29 | // ) 30 | ``` 31 | 32 | ## 获取二维码网址 33 | 34 | ```php 35 | $url = $app->qrcode->url($ticket); 36 | // https://api.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET 37 | ``` 38 | 39 | ## 获取二维码内容 40 | 41 | ```php 42 | $url = $app->qrcode->url($ticket); 43 | 44 | $content = file_get_contents($url); // 得到二进制图片内容 45 | 46 | file_put_contents(__DIR__ . '/code.jpg', $content); // 写入文件 47 | ``` 48 | -------------------------------------------------------------------------------- /basic-services/jssdk.md: -------------------------------------------------------------------------------- 1 | # JSSDK 2 | 3 | 微信 JSSDK 官方文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115 4 | 5 | ## API 6 | 7 | #### 获取JSSDK的配置数组 8 | 9 | ```php 10 | $app->jssdk->buildConfig(array $APIs, $debug = false, $beta = false, $json = true); 11 | ``` 12 | 13 | 默认返回 JSON 字符串,当 `$json` 为 `false` 时返回数组,你可以直接使用到网页中。 14 | 15 | #### 设置当前URL 16 | 17 | ```php 18 | $app->jssdk->setUrl($url) 19 | ``` 20 | 如果不想用默认读取的URL,可以使用此方法手动设置,通常不需要。 21 | 22 | 23 | #### 示例 24 | 25 | 我们可以生成js配置文件: 26 | 27 | ```js 28 | 29 | 32 | ``` 33 | 结果如下: 34 | 35 | 36 | ```js 37 | 38 | 48 | ``` 49 | 50 | -------------------------------------------------------------------------------- /payment/security.md: -------------------------------------------------------------------------------- 1 | # 安全与风控 2 | 3 | > {info} EasyWeChat 4.0.7+ 4 | 5 | ## 获取 RSA 公钥 6 | 7 | ```php 8 | $result = $app->security->getPublicKey(); 9 | 10 | // 存成文件 11 | 12 | file_put_contents('./public.pem', $result); 13 | ``` 14 | 15 | 将会得到 PKCS#1 格式密钥: 16 | 17 | ``` 18 | -----BEGIN RSA PUBLIC KEY----- 19 | MIIBCgKCAQEArT82k67xybiJS9AD8nNAeuDYdrtCRaxkS6cgs8L9h83eqlDTlrdw 20 | zBVSv5V4imTq/URbXn4K0V/KJ1TwDrqOI8hamGB0fvU13WW1NcJuv41RnJVua0QA 21 | lS3tS1JzOZpMS9BEGeFvyFF/epbi/m9+2kUWG94FccArNnBtBqqvFncXgQsm98JB 22 | 3a62NbS1ePP/hMI7Kkz+JNMyYsWkrOUFDCXAbSZkWBJekY4nGZtK1erqGRve8Jbx 23 | TWirAm/s08rUrjOuZFA21/EI2nea3DidJMTVnXVPY2qcAjF+595shwUKyTjKB8v1 24 | REPB3hPF1Z75O6LwuLfyPiCrCTmVoyfqjwIDAQAB 25 | -----END RSA PUBLIC KEY----- 26 | ``` 27 | 28 | 使用 OpenSSL 转换 PKCS#1 为 PKCS#8 格式密钥: 29 | 30 | ```shell 31 | openssl rsa -RSAPublicKey_in -in public.pem -out public.pem 32 | ``` 33 | 34 | PKCS#8 格式密钥: 35 | 36 | ``` 37 | -----BEGIN PUBLIC KEY----- 38 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArT82k67xybiJS9AD8nNA 39 | euDYdrtCRaxkS6cgs8L9h83eqlDTlrdwzBVSv5V4imTq/URbXn4K0V/KJ1TwDrqO 40 | I8hamGB0fvU13WW1NcJuv41RnJVua0QAlS3tS1JzOZpMS9BEGeFvyFF/epbi/m9+ 41 | lkUWG94FccArNnBtBqqvFncXgQsm98JB3a42NbS1ePP/hMI7Kkz+JNMyYsWkrOUF 42 | DCXAbSZkWBJekY4nGZtK1erqGRve8JbxTWirAm/s08rUrjOuZFA21/EI2nea3Did 43 | JMTVnXVPY2qcAjF+595shwUKyTjKB8v1REPB3hPF1Z75O6LwuLfyPiCrCTmVoyfq 44 | jwIDAQAB 45 | -----END PUBLIC KEY----- 46 | ``` 47 | -------------------------------------------------------------------------------- /open-platform/index.md: -------------------------------------------------------------------------------- 1 | # 微信开放平台第三方平台 2 | 3 | 此页涉及接口信息与说明请参见:[授权流程技术说明 - 官方文档](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1453779503&token=&lang=) 4 | 5 | # 微信开放平台第三方平台 6 | 7 | ## 实例化 8 | 9 | ```php 10 | '开放平台第三方平台 APPID', 15 | 'secret' => '开放平台第三方平台 Secret', 16 | 'token' => '开放平台第三方平台 Token', 17 | 'aes_key' => '开放平台第三方平台 AES Key' 18 | ]; 19 | 20 | $openPlatform = Factory::openPlatform($config); 21 | ``` 22 | 23 | ## 获取用户授权页 URL 24 | 25 | ```php 26 | $openPlatform->getPreAuthorizationUrl('https://easywechat.com/callback'); // 传入回调URI即可 27 | ``` 28 | 29 | ## 使用授权码换取接口调用凭据和授权信息 30 | 31 | 在用户在授权页授权流程完成后,授权页会自动跳转进入回调URI,并在URL参数中返回授权码和过期时间,如:(https://easywechat.com/callback?auth_code=xxx&expires_in=600) 32 | 33 | ```php 34 | $openPlatform->handleAuthorize(string $authCode = null); 35 | ``` 36 | 37 | > $authCode 不传的时候会获取 url 中的 auth_code 参数值 38 | 39 | ## 获取授权方的帐号基本信息 40 | 41 | ```php 42 | $openPlatform->getAuthorizer(string $appId); 43 | ``` 44 | 45 | ## 获取授权方的选项设置信息 46 | 47 | ```php 48 | $openPlatform->getAuthorizerOption(string $appId, string $name); 49 | ``` 50 | 51 | ## 设置授权方的选项信息 52 | 53 | ```php 54 | $openPlatform->setAuthorizerOption(string $appId, string $name, string $value); 55 | ``` 56 | 57 | > 该API用于获取授权方的公众号或小程序的选项设置信息,如:地理位置上报,语音识别开关,多客服开关。注意,获取各项选项设置信息,需要有授权方的授权,详见权限集说明。 58 | 59 | 60 | ## 获取已授权的授权方列表 61 | 62 | ```php 63 | $openPlatform->getAuthorizers(int $offset = 0, int $count = 500) 64 | ``` 65 | -------------------------------------------------------------------------------- /micro-merchant/index.md: -------------------------------------------------------------------------------- 1 | # 小微商户 2 | 3 | 你在阅读本文之前确认你已经仔细阅读了:[微信小微商户专属接口文档](https://pay.weixin.qq.com/wiki/doc/api/xiaowei.php?chapter=19_2)。 4 | 5 | ## 配置 6 | 7 | 小微商户整体接口调用方式相对于其他微信接口略有不同,配置时请勿填错,相关配置如下: 8 | 9 | ```php 10 | use EasyWeChat\Factory; 11 | 12 | $config = [ 13 | // 必要配置 14 | 'mch_id' => 'your-mch-id', // 服务商的商户号 15 | 'key' => 'key-for-signature', // API 密钥 16 | 'apiv3_key' => 'APIv3-key-for-signature', // APIv3 密钥 17 | // API 证书路径(登录商户平台下载 API 证书) 18 | 'cert_path' => 'path/to/your/cert.pem', // XXX: 绝对路径!!!! 19 | 'key_path' => 'path/to/your/key', // XXX: 绝对路径!!!! 20 | // 以下两项配置在获取证书接口时可为空,在调用入驻接口前请先调用获取证书接口获取以下两项配置,如果获取过证书可以直接在这里配置,也可参照本文档获取平台证书章节中示例 21 | // 'serial_no' => '获取证书接口获取到的平台证书序列号', 22 | // 'certificate' => '获取证书接口获取到的证书内容' 23 | 24 | // 以下为可选项 25 | // 指定 API 调用返回结果的类型:array(default)/collection/object/raw/自定义类名 26 | 'response_type' => 'array' 27 | 'appid' => 'wx931386123456789e' // 服务商的公众账号 ID 28 | ]; 29 | 30 | $app = Factory::microMerchant($config); 31 | 32 | ``` 33 | 34 | `$app` 在所有相关小程序的文档都是指 `Factory::miniProgram` 得到的实例,就不在每个页面单独写了。 35 | 36 | ## 使用时值得注意的地方: 37 | 1、小微商户所有接口中以下列出参数 `version`, `mch_id`, `nonce_str`, `sign`, `sign_type`, `cert_sn` 可不用传入。 38 | 39 | 2、所有敏感信息无需手动加密,sdk会在调用接口前自动完成加密 40 | 41 | 3、在调用入驻等需要敏感信息加密的接口前请先调用获取证书接口然后把配置填入配置项 42 | 43 | 4、入驻成功获取到子商户号后需帮助子商户调用配置修改等接口可以先调用以下方法,方便调用修改等接口时无需再次传入子商户号 44 | ```php 45 | // $subMchId 为子商户号 46 | // $appid 服务商的公众账号 ID 47 | $app->setSubMchId(string $subMchId, string $appId = ''); 48 | ``` -------------------------------------------------------------------------------- /payment/refund.md: -------------------------------------------------------------------------------- 1 | # 退款 2 | 3 | ## 申请退款 4 | 5 | 当交易发生之后一段时间内,由于买家或者卖家的原因需要退款时,卖家可以通过退款接口将支付款退还给买家,微信支付将在收到退款请求并且验证成功之后,按照退款规则将支付款按原路退到买家帐号上。 6 | 7 | 注意: 8 | 9 | > 1、交易时间超过一年的订单无法提交退款; 10 | > 2、微信支付退款支持单笔交易分多次退款,多次退款需要提交原支付订单的商户订单号和设置不同的退款单号。一笔退款失败后重新提交,要采用原来的退款单号。总退款金额不能超过用户实际支付金额。 11 | 12 | 参考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4 13 | 14 | ### 根据微信订单号退款 15 | 16 | ```php 17 | // 参数分别为:微信订单号、商户退款单号、订单金额、退款金额、其他参数 18 | $app->refund->byTransactionId(string $transactionId, string $refundNumber, int $totalFee, int $refundFee, array $config = []); 19 | 20 | // Example: 21 | $result = $app->refund->byTransactionId('transaction-id-xxx', 'refund-no-xxx', 10000, 10000, [ 22 | // 可在此处传入其他参数,详细参数见微信支付文档 23 | 'refund_desc' => '商品已售完', 24 | ]); 25 | 26 | ``` 27 | ### 根据商户订单号退款 28 | 29 | ```php 30 | // 参数分别为:商户订单号、商户退款单号、订单金额、退款金额、其他参数 31 | $app->refund->byOutTradeNumber(string $number, string $refundNumber, int $totalFee, int $refundFee, array $config = []); 32 | 33 | // Example: 34 | $result = $app->refund->byOutTradeNumber('out-trade-no-xxx', 'refund-no-xxx', 20000, 1000, [ 35 | // 可在此处传入其他参数,详细参数见微信支付文档 36 | 'refund_desc' => '退运费', 37 | ]); 38 | ``` 39 | 40 | > $refundNumber 为商户退款单号,自己生成用于自己识别即可。 41 | 42 | ## 查询退款 43 | 44 | 提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。 45 | 46 | 可通过 4 种不同类型的单号查询: 47 | 48 | > - 微信订单号 => `queryByTransactionId($transactionId)` 49 | > - 商户订单号 => `queryByOutTradeNumber($outTradeNumber)` 50 | > - 商户退款单号 => `queryByOutRefundNumber($outRefundNumber)` 51 | > - 微信退款单号 => `queryByRefundId($refundId)` 52 | -------------------------------------------------------------------------------- /basic-services/content_security.md: -------------------------------------------------------------------------------- 1 | # 内容安全接口 2 | 3 | ## 文本安全内容检测 4 | 5 | 用于校验一段文本是否含有违法内容。 6 | 7 | ### 频率限制 8 | 9 | 单个appid调用上限为2000次/分钟,1,000,000次/天 10 | 11 | ### 调用示例 12 | 13 | ```php 14 | // 传入要检测的文本内容,长度不超过500K字节 15 | $content = '你好'; 16 | 17 | $result = $app->content_security->checkText($content); 18 | 19 | // 正常返回 0 20 | { 21 | "errcode": "0", 22 | "errmsg": "ok" 23 | } 24 | 25 | //当 $content 内含有敏感信息,则返回 87014 26 | { 27 | "errcode": 87014, 28 | "errmsg": "risky content" 29 | } 30 | ``` 31 | 32 | ## 图片安全内容检测 33 | 34 | 用于校验一张图片是否含有敏感信息。如涉黄、涉及敏感人脸(通常是政治人物)。 35 | 36 | ### 频率限制 37 | 38 | 单个appid调用上限为1000次/分钟,100,000次/天 39 | 40 | ### 调用示例 41 | 42 | ```php 43 | // 所传参数为要检测的图片文件的绝对路径,图片格式支持PNG、JPEG、JPG、GIF, 像素不超过 750 x 1334,同时文件大小以不超过 300K 为宜,否则可能报错 44 | $result = $app->content_security->checkImage('/path/to/the/image'); 45 | 46 | // 正常返回 0 47 | { 48 | "errcode": "0", 49 | "errmsg": "ok" 50 | } 51 | 52 | // 当图片文件内含有敏感内容,则返回 87014 53 | { 54 | "errcode": 87014, 55 | "errmsg": "risky content" 56 | } 57 | ``` 58 | 59 | ## 重要说明 60 | 61 | 目前上述两个接口仅支持在小程序中使用,示例中的 `$app` 表示小程序实例,即: 62 | 63 | ```php 64 | use EasyWeChat\Factory; 65 | 66 | $config = [ 67 | 'app_id' => 'wx3cf0f39249eb0exx', 68 | 'secret' => 'f1c242f4f28f735d4687abb469072axx', 69 | 70 | // 下面为可选项 71 | // 指定 API 调用返回结果的类型:array(default)/collection/object/raw/自定义类名 72 | 'response_type' => 'array', 73 | 74 | 'log' => [ 75 | 'level' => 'debug', 76 | 'file' => __DIR__.'/wechat.log', 77 | ], 78 | ]; 79 | 80 | $app = Factory::miniProgram($config); 81 | ``` 82 | -------------------------------------------------------------------------------- /open-work/provider.md: -------------------------------------------------------------------------------- 1 | # 服务商相关接口 2 | 3 | ## 单点登录 4 | 5 | 6 | ### 获取从第三方单点登录连接 7 | 8 | ```php 9 | $app->provider->getLoginUrl(string $redirectUri = '', string $userType = 'admin', string $state = ''); //$redirectUri 回调地址 $userType支持登录的类型 10 | ``` 11 | 12 | ### 获取登录用户信息 13 | 14 | ```php 15 | $app->provider->getLoginInfo(string $authCode); //$authCode oauth2.0授权企业微信管理员登录产生的code,最长为512字节。只能使用一次,5分钟未被使用自动过期 16 | ``` 17 | 18 | ## 注册定制化 19 | 20 | ### 获取注册码 21 | 22 | ```php 23 | $app->provider->getRegisterCode( 24 | string $corpName = '', //企业名称 25 | string $adminName = '',//管理员姓名 26 | string $adminMobile = '',//管理员手机号 27 | string $state = ''//自定义的状态值 28 | ); 29 | ``` 30 | 31 | ### 获取注册Uri 32 | 33 | ```php 34 | $app->provider->getRegisterUri(string $registerCode = ''); //$registerCode 注册码 35 | ``` 36 | 37 | ### 查询注册状态 38 | 39 | ```php 40 | $app->provider->getRegisterInfo(string $registerCode); //$registerCode 注册码 41 | ``` 42 | 43 | ### 设置授权应用可见范围 44 | 45 | ```php 46 | $app->provider->setAgentScope( 47 | string $accessToken, //查询注册状态接口返回的access_token 48 | string $agentId, // 授权方应用id 49 | array $allowUser = [], //应用可见范围(成员)若未填该字段,则清空可见范围中成员列表 50 | array $allowParty = [], // 应用可见范围(部门)若未填该字段,则清空可见范围中部门列表 51 | array $allowTag = [] //应用可见范围(标签)若未填该字段,则清空可见范围中标签列表 52 | ) 53 | ``` 54 | 55 | ### 设置通讯录同步完成 56 | 57 | ```php 58 | $app->provider->contactSyncSuccess(string $accessToken); //$accessToken //查询注册状态接口返回的access_token 59 | ``` 60 | -------------------------------------------------------------------------------- /open-work/server.md: -------------------------------------------------------------------------------- 1 | # 服务端 2 | 3 | ## 企业微信第三方回调协议 4 | 5 | 6 | SDK 默认会处理事件 `suite_ticket` ,并会缓存 `suite_ticket` 7 | 8 | 9 | > {info} 需要注意的是:授权成功、变更授权、取消授权通知时间的响应必须在1000ms内完成,以保证用户安装应用的体验。建议在接收到此事件时 立即回应企业微信,之后再做相关业务的处理。 10 | 11 | 12 | ```php 13 | $server = $app->server; 14 | 15 | $server->push(function ($message) { 16 | switch ($message['InfoType']) { 17 | //推送suite_ticket 18 | case 'suite_ticket': 19 | break; 20 | //授权成功通知 21 | case 'create_auth': 22 | break; 23 | //变更授权通知 24 | case 'cancel_auth': 25 | break; 26 | //通讯录事件通知 27 | case 'change_contact': 28 | switch ($message['ChangeType']){ 29 | case 'create_user': 30 | return '新增成员事件'; 31 | break; 32 | case 'update_user': 33 | return '更新成员事件'; 34 | break; 35 | case 'delete_user': 36 | return '删除成员事件'; 37 | break; 38 | case 'create_party': 39 | return '新增部门事件'; 40 | break; 41 | case 'update_party': 42 | return '更新部门事件'; 43 | break; 44 | case 'delete_party': 45 | return '删除部门事件'; 46 | break; 47 | case 'update_tag': 48 | return '标签成员变更事件'; 49 | break; 50 | } 51 | break; 52 | default: 53 | return 'fail'; 54 | break; 55 | } 56 | }); 57 | $response = $server->serve(); 58 | $response->send(); 59 | 60 | ``` 61 | 62 | -------------------------------------------------------------------------------- /payment/index.md: -------------------------------------------------------------------------------- 1 | # 支付 2 | 3 | 你在阅读本文之前确认你已经仔细阅读了:[微信支付 | 商户平台开发文档](https://pay.weixin.qq.com/wiki/doc/api/index.html)。 4 | 5 | ## 配置 6 | 7 | 配置在前面的例子中已经提到过了,支付的相关配置如下: 8 | 9 | ```php 10 | use EasyWeChat\Factory; 11 | 12 | $config = [ 13 | // 必要配置 14 | 'app_id' => 'xxxx', 15 | 'mch_id' => 'your-mch-id', 16 | 'key' => 'key-for-signature', // API 密钥 17 | 18 | // 如需使用敏感接口(如退款、发送红包等)需要配置 API 证书路径(登录商户平台下载 API 证书) 19 | 'cert_path' => 'path/to/your/cert.pem', // XXX: 绝对路径!!!! 20 | 'key_path' => 'path/to/your/key', // XXX: 绝对路径!!!! 21 | 22 | 'notify_url' => '默认的订单回调地址', // 你也可以在下单时单独设置来想覆盖它 23 | ]; 24 | 25 | $app = Factory::payment($config); 26 | ``` 27 | 28 | ### 服务商 29 | 30 | #### 设置子商户信息 31 | 32 | ```php 33 | $app->setSubMerchant('sub-merchant-id', 'sub-app-id'); // 子商户 AppID 为可选项 34 | ``` 35 | 36 | ### 刷卡支付 37 | 38 | [官方文档](https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10) 39 | 40 | ```php 41 | $result = $app->pay([ 42 | 'body' => 'image形象店-深圳腾大- QQ公仔', 43 | 'out_trade_no' => '1217752501201407033233368018', 44 | 'total_fee' => 888, 45 | 'auth_code' => '120061098828009406', 46 | ]); 47 | ``` 48 | 49 | ## 授权码查询OPENID接口 50 | 51 | ```php 52 | $app->authCodeToOpenid($authCode); 53 | ``` 54 | 55 | ## 沙箱模式 56 | 57 | 微信支付沙箱环境,是提供给微信支付商户的开发者,用于模拟支付及回调通知。以验证商户是否理解回调通知、账单格式,以及是否对异常做了正确的处理。EasyWeChat SDK 对于这一功能进行了封装,开发者只需一步即可在沙箱模式和常规模式间切换,方便开发与最终的部署。 58 | 59 | ```php 60 | // 在实例化的时候传入配置即可 61 | $app = Factory::payment([ 62 | // ... 63 | 'sandbox' => true, // 设置为 false 或注释则关闭沙箱模式 64 | ]); 65 | 66 | // 判断当前是否为沙箱模式: 67 | bool $app->inSandbox(); 68 | ``` 69 | 70 | > {warning} 特别注意,沙箱模式对于测试用例有严格要求,若使用的用例与规定不符,将导致测试失败。具体用例要求可关注公众号“微信支付商户接入验收助手”(WXPayAssist)查看。 71 | -------------------------------------------------------------------------------- /official-account/semantic.md: -------------------------------------------------------------------------------- 1 | # 语义理解 2 | 3 | > 貌似此接口已经下线,调用无正确返回值 4 | 5 | + `query($keyword, $categories, $optional = [])` 语义理解: 6 | 7 | + `$keyword` 为关键字 8 | + `$categories` 需要使用的服务类型,多个用 “,” 隔开字符串,不能为空; 9 | + `$optional` 为其它属性: 10 | + `latitude` `float` 纬度坐标,与经度同时传入;与城市二选一传入 11 | + `longitude` `float` 经度坐标,与纬度同时传入;与城市二选一传入 12 | + `city` `string` 城市名称,与经纬度二选一传入 13 | + `region` `string` 区域名称,在城市存在的情况下可省;与经纬度二选一传入 14 | + `uid` `string` 用户唯一id(非开发者id),用户区分公众号下的不同用户(建议填入用户openid),如果为空,则无法使用上下文理解功能。appid和uid同时存在的情况下,才可以使用上下文理解功能。 15 | 16 | > 注:单类别意图比较明确,识别的覆盖率比较大,所以如果只要使用特定某个类别,建议将 category 只设置为该类别。 17 | 18 | 示例: 19 | 20 | ```php 21 | $result = $app->semantic->query('查一下明天从北京到上海的南航机票', "flight,hotel", array('city' => '北京', 'uid' => '123456')); 22 | // 查询参数: 23 | // { 24 | // "query":"查一下明天从北京到上海的南航机票", 25 | // "city":"北京", 26 | // "category": "flight,hotel", 27 | // "appid":"wxaaaaaaaaaaaaaaaa", 28 | // "uid":"123456" 29 | // } 30 | ``` 31 | 返回值示例: 32 | 33 | ```json 34 | { 35 | "errcode":0, 36 | "query":"查一下明天从北京到上海的南航机票", 37 | "type":"flight", 38 | "semantic":{ 39 | "details":{ 40 | "start_loc":{ 41 | "type":"LOC_CITY", 42 | "city":"北京市", 43 | "city_simple":"北京", 44 | "loc_ori":"北京" 45 | }, 46 | "end_loc": { 47 | "type":"LOC_CITY", 48 | "city":"上海市", 49 | "city_simple":"上海", 50 | "loc_ori":"上海" 51 | }, 52 | "start_date": { 53 | "type":"DT_ORI", 54 | "date":"2014-03-05", 55 | "date_ori":"明天" 56 | }, 57 | "airline":"中国南方航空公司" 58 | }, 59 | "intent":"SEARCH" 60 | } 61 | ``` -------------------------------------------------------------------------------- /wework/invoice.md: -------------------------------------------------------------------------------- 1 | # 电子发票 2 | 3 | ```php 4 | $config = [ 5 | 'corp_id' => 'xxxxxxxxxxxxxxxxx', 6 | 'secret' => 'xxxxxxxxxx', 7 | //... 8 | ]; 9 | 10 | $app = Factory::work($config); 11 | ``` 12 | 13 | ## 查询电子发票 14 | 15 | https://work.weixin.qq.com/api/doc#11631 16 | 17 | API: 18 | 19 | ```php 20 | mixed get(string $cardId, string $encryptCode) 21 | ``` 22 | 23 | example: 24 | 25 | ```php 26 | $app->invoice->get('CARDID', 'ENCRYPTCODE'); 27 | ``` 28 | 29 | ## 批量查询电子发票 30 | 31 | https://work.weixin.qq.com/api/doc#11974 32 | 33 | API: 34 | 35 | ```php 36 | mixed select(array $invoices) 37 | ``` 38 | 39 | > {info} $invoices: 发票参数列表 40 | 41 | example: 42 | 43 | ```php 44 | $invoices = [ 45 | ["card_id" => "CARDID1", "encrypt_code" => "ENCRYPTCODE1"], 46 | ["card_id" => "CARDID2", "encrypt_code" => "ENCRYPTCODE2"] 47 | ]; 48 | 49 | $app->invoice->select($invoices); 50 | ``` 51 | 52 | ## 更新发票状态 53 | 54 | https://work.weixin.qq.com/api/doc#11633 55 | 56 | API: 57 | 58 | ```php 59 | mixed update(string $cardId, string $encryptCode, string $status) 60 | ``` 61 | 62 | > {warning} $status: 发报销状态 63 | >> - INVOICE_REIMBURSE_INIT:发票初始状态,未锁定; 64 | >> - INVOICE_REIMBURSE_LOCK:发票已锁定,无法重复提交报销; 65 | >> - INVOICE_REIMBURSE_CLOSURE:发票已核销,从用户卡包中移除 66 | 67 | ## 批量更新发票状态 68 | 69 | https://work.weixin.qq.com/api/doc#11633 70 | 71 | API: 72 | 73 | ```php 74 | mixed batchUpdate(array $invoices, string $openid, string $status) 75 | ``` 76 | 77 | example: 78 | 79 | ```php 80 | $invoices = [ 81 | ["card_id" => "CARDID1", "encrypt_code" => "ENCRYPTCODE1"], 82 | ["card_id" => "CARDID2", "encrypt_code" => "ENCRYPTCODE2"] 83 | ]; 84 | $openid = 'oV-gpwSU3xlMXbq0PqqRp1xHu9O4'; 85 | 86 | $status = 'INVOICE_REIMBURSE_CLOSURE'; 87 | 88 | $app->invoice->batchUpdate($invoices, $openid, $status) 89 | ``` 90 | 91 | -------------------------------------------------------------------------------- /open-platform/server.md: -------------------------------------------------------------------------------- 1 | # 服务端 2 | 3 | ## 第三方平台推送事件 4 | 5 | 公众号第三方平台推送的有四个事件: 6 | 7 | > 如已经授权的公众号、小程序再次进行授权,而未修改已授权的权限的话,是没有相关事件推送的。 8 | 9 | ​ 授权成功 `authorized` 10 | 11 | ​ 授权更新 `updateauthorized` 12 | 13 | ​ 授权取消 `unauthorized` 14 | 15 | ​ VerifyTicket `component_verify_ticket` 16 | 17 | SDK 默认会处理事件 `component_verify_ticket` ,并会缓存 `verify_ticket` 所以如果你暂时不需要处理其他事件,直接这样使用即可: 18 | 19 | ```php 20 | $server = $openPlatform->server; 21 | 22 | return $server->serve(); 23 | ``` 24 | 25 | ## 自定义消息处理器 26 | 27 | > *消息处理器详细说明见公众号开发 - 服务器一节* 28 | 29 | ```php 30 | use EasyWeChat\OpenPlatform\Server\Guard; 31 | 32 | $server = $openPlatform->server; 33 | 34 | // 处理授权成功事件 35 | $server->push(function ($message) { 36 | // ... 37 | }, Guard::EVENT_AUTHORIZED); 38 | 39 | // 处理授权更新事件 40 | $server->push(function ($message) { 41 | // ... 42 | }, Guard::EVENT_UPDATE_AUTHORIZED); 43 | 44 | // 处理授权取消事件 45 | $server->push(function ($message) { 46 | // ... 47 | }, Guard::EVENT_UNAUTHORIZED); 48 | ``` 49 | 50 | ### 示例(Laravel 框架) 51 | 52 | ```php 53 | // 假设你的开放平台第三方平台设置的授权事件接收 URL 为: https://easywechat.com/open-platform (其他事件推送同样会推送到这个 URL) 54 | Route::post('open-platform', function () { // 关闭 CSRF 55 | // $openPlatform 为你实例化的开放平台对象,此处省略实例化步骤 56 | return $openPlatform->server->serve(); // Done! 57 | }); 58 | 59 | // 处理事件 60 | use EasyWeChat\OpenPlatform\Server\Guard; 61 | Route::post('open-platform', function () { 62 | $server = $openPlatform->server; 63 | // 处理授权成功事件,其他事件同理 64 | $server->push(function ($message) { 65 | // $message 为微信推送的通知内容,不同事件不同内容,详看微信官方文档 66 | // 获取授权公众号 AppId: $message['AuthorizerAppid'] 67 | // 获取 AuthCode:$message['AuthorizationCode'] 68 | // 然后进行业务处理,如存数据库等... 69 | }, Guard::EVENT_AUTHORIZED); 70 | 71 | return $server->serve(); 72 | }); 73 | ``` 74 | -------------------------------------------------------------------------------- /official-account/menu.md: -------------------------------------------------------------------------------- 1 | # 自定义菜单 2 | 3 | ## 读取(查询)已设置菜单 4 | 5 | 6 | ```php 7 | $list = $app->menu->list(); 8 | ``` 9 | 10 | ## 获取当前菜单 11 | 12 | ```php 13 | $current = $app->menu->current(); 14 | ``` 15 | 16 | ## 添加菜单 17 | 18 | ### 添加普通菜单 19 | 20 | ```php 21 | $buttons = [ 22 | [ 23 | "type" => "click", 24 | "name" => "今日歌曲", 25 | "key" => "V1001_TODAY_MUSIC" 26 | ], 27 | [ 28 | "name" => "菜单", 29 | "sub_button" => [ 30 | [ 31 | "type" => "view", 32 | "name" => "搜索", 33 | "url" => "http://www.soso.com/" 34 | ], 35 | [ 36 | "type" => "view", 37 | "name" => "视频", 38 | "url" => "http://v.qq.com/" 39 | ], 40 | [ 41 | "type" => "click", 42 | "name" => "赞一下我们", 43 | "key" => "V1001_GOOD" 44 | ], 45 | ], 46 | ], 47 | ]; 48 | $app->menu->create($buttons); 49 | ``` 50 | 51 | 以上将会创建一个普通菜单。 52 | 53 | ### 添加个性化菜单 54 | 55 | 与创建普通菜单不同的是,需要在 `create()` 方法中将个性化匹配规则作为第二个参数传进去: 56 | 57 | ```php 58 | $buttons = [ 59 | // ... 60 | ]; 61 | $matchRule = [ 62 | "tag_id" => "2", 63 | "sex" => "1", 64 | "country" => "中国", 65 | "province" => "广东", 66 | "city" => "广州", 67 | "client_platform_type" => "2", 68 | "language" => "zh_CN" 69 | ]; 70 | $app->menu->create($buttons, $matchRule); 71 | ``` 72 | 73 | ## 删除菜单 74 | 75 | 有两种删除方式,一种是**全部删除**,另外一种是**根据菜单 ID 来删除**(删除个性化菜单时用,ID 从查询接口获取): 76 | 77 | ```php 78 | $app->menu->delete(); // 全部 79 | $app->menu->delete($menuId); 80 | ``` 81 | 82 | ## 测试个性化菜单 83 | 84 | ```php 85 | $app->menu->match($userId); 86 | ``` 87 | 88 | > `$userId` 可以是粉丝的 OpenID,也可以是粉丝的微信号。 89 | 90 | 返回 `$menu` 与指定的 `$userId` 匹配的菜单项。 91 | -------------------------------------------------------------------------------- /official-account/template_message.md: -------------------------------------------------------------------------------- 1 | # 模板消息 2 | 3 | 模板消息仅用于公众号向用户发送重要的服务通知,只能用于符合其要求的服务场景中,如信用卡刷卡通知,商品购买成功通知等。不支持广告等营销类消息以及其它所有可能对用户造成骚扰的消息。 4 | 5 | ## 修改账号所属行业 6 | 7 | ```php 8 | $app->template_message->setIndustry($industryId1, $industryId2); 9 | ``` 10 | 11 | ## 获取支持的行业列表 12 | 13 | ```php 14 | $app->template_message->getIndustry(); 15 | ``` 16 | 17 | ## 添加模板 18 | 19 | 在公众号后台获取 `$shortId` 并添加到账户。 20 | 21 | ```php 22 | $app->template_message->addTemplate($shortId); 23 | ``` 24 | 25 | ## 获取所有模板列表 26 | 27 | ```php 28 | $app->template_message->getPrivateTemplates(); 29 | ``` 30 | 31 | ## 删除模板 32 | 33 | ```php 34 | $app->template_message->deletePrivateTemplate($templateId); 35 | ``` 36 | 37 | ## 发送模板消息 38 | 39 | ```php 40 | $app->template_message->send([ 41 | 'touser' => 'user-openid', 42 | 'template_id' => 'template-id', 43 | 'url' => 'https://easywechat.org', 44 | 'miniprogram' => [ 45 | 'appid' => 'xxxxxxx', 46 | 'pagepath' => 'pages/xxx', 47 | ], 48 | 'data' => [ 49 | 'key1' => 'VALUE', 50 | 'key2' => 'VALUE2', 51 | ... 52 | ], 53 | ]); 54 | ``` 55 | > 如果 url 和 miniprogram 字段都传,会优先跳转小程序。 56 | 57 | ## 发送一次性订阅消息 58 | 59 | ```php 60 | $app->template_message->sendSubscription([ 61 | 'touser' => 'user-openid', 62 | 'template_id' => 'template-id', 63 | 'url' => 'https://easywechat.org', 64 | 'scene' => 1000, 65 | 'data' => [ 66 | 'key1' => 'VALUE', 67 | 'key2' => 'VALUE2', 68 | ... 69 | ], 70 | ]); 71 | ``` 72 | 73 | > 如果你想为发送的内容字段指定颜色,你可以将 "data" 部分写成下面 4 种不同的样式,不写 `color` 将会是默认黑色: 74 | 75 | ```php 76 | 'data' => [ 77 | 'foo' => '你好', // 不需要指定颜色 78 | 'bar' => ['你好', '#F00'], // 指定为红色 79 | 'baz' => ['value' => '你好', 'color' => '#550038'], // 与第二种一样 80 | 'zoo' => ['value' => '你好'], // 与第一种一样 81 | ] 82 | ``` 83 | -------------------------------------------------------------------------------- /basic-services/media.md: -------------------------------------------------------------------------------- 1 | # 临时素材 2 | 3 | 上传的临时多媒体文件有格式和大小限制,如下: 4 | 5 | > - 图片(image): 2M,支持 `JPG` 格式 6 | > - 语音(voice):2M,播放长度不超过 `60s`,支持 `AMR\MP3` 格式 7 | > - 视频(video):10MB,支持 `MP4` 格式 8 | > - 缩略图(thumb):64KB,支持 `JPG` 格式 9 | 10 | ## 上传图片 11 | 12 | > {warning} 注意:微信图片上传服务有敏感检测系统,图片内容如果含有敏感内容,如色情,商品推广,虚假信息等,上传可能失败。 13 | 14 | ```php 15 | $app->media->uploadImage($path); 16 | ``` 17 | 18 | ## 上传声音 19 | 20 | ```php 21 | $app->media->uploadVoice($path); 22 | ``` 23 | 24 | ## 上传视频 25 | 26 | ```php 27 | $app->media->uploadVideo($path, $title, $description); 28 | ``` 29 | 30 | ## 上传缩略图 31 | 32 | 用于视频封面或者音乐封面。 33 | 34 | ```php 35 | $app->media->uploadThumb($path); 36 | ``` 37 | 38 | ## 上传群发视频 39 | 40 | 上传视频获取 `media_id` 用以创建群发消息用。 41 | 42 | ```php 43 | $app->media->uploadVideoForBroadcasting($path, $title, $description); 44 | 45 | //{ 46 | // "media_id": "rF4UdIMfYK3efUfyoddYRMU50zMiRmmt_l0kszupYh_SzrcW5Gaheq05p_lHuOTQ", 47 | // "title": "TITLE", 48 | // "description": "Description" 49 | //} 50 | ``` 51 | 52 | ## 创建群发消息 53 | 54 | 不要与上面 **上传群发视频** 搞混了,上面一个是上传视频得到 `media_id`,这个是使用该 `media_id` 加标题描述 **创建一条消息素材** 用来发送给用户。详情参见:[消息群发](broadcasting) 55 | 56 | ```php 57 | $app->media->createVideoForBroadcasting($mediaId, $title, $description); 58 | 59 | //{ 60 | // "type":"video", 61 | // "media_id":"IhdaAQXuvJtGzwwc0abfXnzeezfO0NgPK6AQYShD8RQYMTtfzbLdBIQkQziv2XJc", 62 | // "created_at":1398848981 63 | //} 64 | ``` 65 | 66 | ## 获取临时素材内容 67 | 68 | 比如图片、语音等二进制流内容,响应为 `EasyWeChat\Kernel\Http\StreamResponse` 实例。 69 | 70 | ```php 71 | $stream = $app->media->get($mediaId); 72 | 73 | if ($stream instanceof \EasyWeChat\Kernel\Http\StreamResponse) { 74 | // 以内容 md5 为文件名存到本地 75 | $stream->save('保存目录'); 76 | 77 | // 自定义文件名,不需要带后缀 78 | $stream->saveAs('保存目录', '文件名'); 79 | } 80 | ``` 81 | 82 | ## 获取 JSSDK 上传的高清语音 83 | 84 | ```php 85 | $stream = $app->media->getJssdkMedia($mediaId); 86 | $stream->saveAs('保存目录', 'custom-name.speex'); 87 | ``` 88 | -------------------------------------------------------------------------------- /official-account/user-tag.md: -------------------------------------------------------------------------------- 1 | # 用户标签 2 | 3 | ## 获取所有标签 4 | 5 | ```php 6 | $app->user_tag->list(); 7 | ``` 8 | 9 | 示例: 10 | 11 | ```php 12 | $tags = $app->user_tag->list(); 13 | 14 | // { 15 | // "tags": [ 16 | // { 17 | // "id": 0, 18 | // "name": "标签1", 19 | // "count": 72596 20 | // }, 21 | // { 22 | // "id": 1, 23 | // "name": "标签2", 24 | // "count": 36 25 | // }, 26 | // ... 27 | // ] 28 | // } 29 | ``` 30 | 31 | ## 创建标签 32 | 33 | ```php 34 | $app->user_tag->create($name); 35 | ``` 36 | 37 | 示例: 38 | 39 | ```php 40 | $app->user_tag->create('测试标签'); 41 | ``` 42 | 43 | ## 修改标签信息 44 | 45 | ```php 46 | $app->user_tag->update($tagId, $name); 47 | ``` 48 | 49 | 示例: 50 | 51 | ```php 52 | $app->user_tag->update(12, "新的名称"); 53 | ``` 54 | 55 | ## 删除标签 56 | 57 | ```php 58 | $app->user_tag->delete($tagId); 59 | ``` 60 | 61 | ## 获取指定 openid 用户所属的标签 62 | 63 | ```php 64 | $userTags = $app->user_tag->userTags($openId); 65 | // 66 | // { 67 | // "tagid_list":["标签1","标签2"] 68 | // } 69 | ``` 70 | 71 | ## 获取标签下用户列表 72 | 73 | ```php 74 | $app->user_tag->usersOfTag($tagId, $nextOpenId = ''); 75 | // $nextOpenId:第一个拉取的OPENID,不填默认从头开始拉取 76 | 77 | // { 78 | // "count":2, // 这次获取的粉丝数量 79 | // "data":{ // 粉丝列表 80 | // "openid":[ 81 | // "ocYxcuAEy30bX0NXmGn4ypqx3tI0", 82 | // "ocYxcuBt0mRugKZ7tGAHPnUaOW7Y" 83 | // ] 84 | // }, 85 | // "next_openid":"ocYxcuBt0mRugKZ7tGAHPnUaOW7Y"//拉取列表最后一个用户的openid 86 | // } 87 | ``` 88 | 89 | ## 批量为用户添加标签 90 | 91 | ```php 92 | $openIds = [$openId1, $openId2, ...]; 93 | $app->user_tag->tagUsers($openIds, $tagId); 94 | ``` 95 | 96 | 97 | ## 批量为用户移除标签 98 | 99 | ```php 100 | $openIds = [$openId1, $openId2, ...]; 101 | $app->user_tag->untagUsers($openIds, $tagId); 102 | ``` 103 | -------------------------------------------------------------------------------- /payment/scan-pay.md: -------------------------------------------------------------------------------- 1 | ## 扫码支付 2 | 3 | ### 模式一:先生成产品二维码,扫码下单后支付 4 | 5 | > {warning} 请务必先熟悉流程:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4 6 | 7 | #### 生成产品二维码内容 8 | 9 | ```php 10 | $content = $app->scheme($productId); // $productId 为你的产品/商品ID,用于回调时带回,自己识别即可 11 | 12 | //结果示例:weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX 13 | ``` 14 | 15 | 将 `$content` 生成二维码,SDK 并不内置二维码生成库,使用你熟悉的工具创建二维码即可,比如 PHP 部分有以下工具可以选择: 16 | 17 | > - https://github.com/endroid/qr-code 18 | > - https://github.com/SimpleSoftwareIO/simple-qrcode 19 | > - https://github.com/aferrandini/PHPQRCode 20 | 21 | #### 处理回调 22 | 23 | 当用户扫码时,你的回调接口会收到一个通知,调用[统一下单接口](https://www.easywechat.com/docs/master/zh-CN/payment/order)创建订单后返回 `prepay_id`,你可以使用下面的代码处理扫码通知: 24 | 25 | ```php 26 | // 扫码支付通知接收第三个参数 `$alert`,如果触发该函数,会返回“业务错误”到微信服务器,触发 `$fail` 则返回“通信错误” 27 | $response = $app->handleScannedNotify(function ($message, $fail, $alert) use ($app) { 28 | // 如:$alert('商品已售空'); 29 | // 如业务流程正常,则要调用“统一下单”接口,并返回 prepay_id 字符串,代码如下 30 | $result = $app->order->unify([ 31 | 'trade_type' => 'NATIVE', 32 | 'product_id' => $message['product_id'], // $message['product_id'] 则为生成二维码时的产品 ID 33 | // ... 34 | ]); 35 | 36 | return $result['prepay_id']; 37 | }); 38 | 39 | $response->send(); 40 | ``` 41 | 42 | 用户在手机上付完钱以后,你会再收到**付款结果通知**,这时候请参考:[处理微信支付通知](https://www.easywechat.com/docs/master/zh-CN/payment/notify) 更新您的订单状态。 43 | 44 | ### 模式二:先下单,生成订单后创建二维码 45 | 46 | > {warning} 请务必先熟悉流程:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5 47 | 48 | #### 根据用户选购的商品生成订单 49 | 50 | 调用[统一下单接口](https://www.easywechat.com/docs/master/zh-CN/payment/order)创建订单: 51 | 52 | ```php 53 | $result = $app->order->unify([ 54 | 'trade_type' => 'NATIVE', 55 | 'product_id' => $message['product_id'], // $message['product_id'] 则为生成二维码时的产品 ID 56 | // ... 57 | ]); 58 | ``` 59 | 60 | #### 生成二维码 61 | 62 | > {info} 版本 4.1.7+ 支持 63 | 64 | 从上一步得到的 `$result['code_url']` 得到二维码内容: 65 | 66 | 将 `$result['code_url']` 生成二维码图片向用户展示即可扫码,生成工具上面自己找一下即可。 SDK 不内置 67 | 68 | #### 支付通知 69 | 70 | 这种方式的通知就只有**付款结果通知**了,这时候请参考:[处理微信支付通知](https://www.easywechat.com/docs/master/zh-CN/payment/notify) 更新您的订单状态。 71 | -------------------------------------------------------------------------------- /open-platform/authorizer-delegate.md: -------------------------------------------------------------------------------- 1 | # 代授权方实现业务 2 | 3 | > 授权方已经把公众号、小程序授权给你的开放平台第三方平台了,接下来的代授权方实现业务只需一行代码即可获得授权方实例。 4 | 5 | ## 实例化 6 | 7 | ```php 8 | use EasyWeChat\Factory; 9 | 10 | $config = [ 11 | // ... 12 | ]; 13 | 14 | $openPlatform = Factory::openPlatform($config); 15 | ``` 16 | 17 | ### 获取授权方实例 18 | 19 | ```php 20 | // 代公众号实现业务 21 | $officialAccount = $openPlatform->officialAccount(string $appId, string $refreshToken); 22 | // 代小程序实现业务 23 | $miniProgram = $openPlatform->miniProgram(string $appId, string $refreshToken); 24 | ``` 25 | 26 | > $appId 为授权方公众号 APPID,非开放平台第三方平台 APPID 27 | > 28 | > $refreshToken 为授权方的 refresh_token,可通过 [获取授权方授权信息](#) 接口获得。 29 | 30 | ### 帮助授权方管理开放平台账号 31 | 32 | ```php 33 | // 代公众号实现业务 34 | $account = $officialAccount->account; 35 | // 代小程序实现业务 36 | $account = $miniProgram->account; 37 | 38 | // 创建开放平台账号 39 | // 并绑定公众号或小程序 40 | $result = $account->create(); 41 | 42 | // 将公众号或小程序绑定到指定开放平台帐号下 43 | $result = $account->bindTo($openAppId); 44 | 45 | // 将公众号/小程序从开放平台帐号下解绑 46 | $result = $account->unbindFrom($openAppid); 47 | 48 | // 获取公众号/小程序所绑定的开放平台帐号 49 | $result = $account->getBinding(); 50 | ``` 51 | 52 | > 授权第三方平台注册的开放平台帐号只可用于获取用户 unionid 实现用户身份打通。 53 | > 54 | > 第三方平台不可操作(包括绑定/解绑)通过 open.weixin.qq.com 线上流程注册的开放平台帐号。 55 | > 56 | > 公众号只可将此权限集授权给一个第三方平台,授权互斥。 57 | 58 | 接下来的 API 调用等操作和公众号、小程序的开发一致,请移步到[公众号](#)或[小程序](#)开发章节继续进行开发吧。 59 | 60 | ### 代码示例 61 | 62 | ```php 63 | // 假设你的公众号消息与事件接收 URL 为:https://easywechat.com/$APPID$/callback ... 64 | 65 | Route::post('{appId}/callback', function ($appId) { 66 | // ... 67 | $officialAccount = $openPlatform->officialAccount($appId); 68 | $server = $officialAccount->server; // ❗️❗️ 这里的 server 为授权方的 server,而不是开放平台的 server,请注意!!! 69 | 70 | $server->push(function () { 71 | return 'Welcome!'; 72 | }); 73 | 74 | return $server->serve(); 75 | }); 76 | 77 | // 调用授权方业务例子 78 | Route::get('how-to-use', function () { 79 | $officialAccount = $openPlatform->officialAccount('已授权的公众号 APPID', 'Refresh-token'); 80 | // 获取用户列表: 81 | $officialAccount->user->list(); 82 | 83 | $miniProgram = $openPlatform->miniProgram('已授权的小程序 APPID', 'Refresh-token'); 84 | // 根据 code 获取 session 85 | $miniProgram->auth->session('js-code'); 86 | // 其他同理 87 | }); 88 | ``` 89 | -------------------------------------------------------------------------------- /mini-program/express.md: -------------------------------------------------------------------------------- 1 | # 物流助手 电子面单 2 | 3 | ## 获取支持的快递公司列表 4 | 5 | > https://developers.weixin.qq.com/miniprogram/dev/api/getAllDelivery.html 6 | 7 | ```php 8 | 9 | $app->express->listProviders(); 10 | 11 | { 12 | "count": 8, 13 | "data": [ 14 | { 15 | "delivery_id": "BEST", 16 | "delivery_name": "百世快递" 17 | }, 18 | ... 19 | ] 20 | } 21 | 22 | ``` 23 | 24 | ## 生成运单 25 | 26 | > https://developers.weixin.qq.com/miniprogram/dev/api/addOrder.html 27 | 28 | ```php 29 | 30 | $app->express->createWaybill($data); 31 | 32 | 33 | // 成功返回 34 | 35 | { 36 | "order_id": "01234567890123456789", 37 | "waybill_id": "123456789", 38 | "waybill_data": [ 39 | { 40 | "key": "SF_bagAddr", 41 | "value": "广州" 42 | }, 43 | { 44 | "key": "SF_mark", 45 | "value": "101- 07-03 509" 46 | } 47 | ] 48 | } 49 | 50 | // 失败返回 51 | 52 | { 53 | "errcode": 9300501, 54 | "errmsg": "delivery logic fail", 55 | "delivery_resultcode": 10002, 56 | "delivery_resultmsg": "客户密码不正确" 57 | } 58 | 59 | ``` 60 | 61 | ## 取消运单 62 | 63 | > https://developers.weixin.qq.com/miniprogram/dev/api/cancelOrder.html 64 | 65 | ```php 66 | $app->express->deleteWaybill($data); 67 | 68 | ``` 69 | 70 | ## 获取运单数据 71 | 72 | > https://developers.weixin.qq.com/miniprogram/dev/api/getOrder.html 73 | 74 | ```php 75 | $app->express->getWaybill($data); 76 | 77 | ``` 78 | 79 | ## 查询运单轨迹 80 | 81 | > https://developers.weixin.qq.com/miniprogram/dev/api/getPath.html 82 | 83 | ```php 84 | $app->express->getWaybillTrack($data); 85 | 86 | ``` 87 | 88 | ## 获取电子面单余额。 89 | 90 | 仅在使用加盟类快递公司时,才可以调用。 91 | 92 | > https://developers.weixin.qq.com/miniprogram/dev/api/getQuota.html 93 | 94 | ```php 95 | 96 | $app->express->getBalance($deliveryId, $bizId); 97 | 98 | // 例如: 99 | 100 | $app->express->getBalance('YTO', 'xyz'); 101 | ``` 102 | 103 | ## 绑定打印员 104 | 105 | 若需要使用微信打单 PC 软件,才需要调用。 106 | 107 | > https://developers.weixin.qq.com/miniprogram/dev/api/updatePrinter.html 108 | 109 | ```php 110 | $app->express->bindPrinter($openid); 111 | ``` 112 | 113 | ## 解绑打印员 114 | 115 | 若需要使用微信打单 PC 软件,才需要调用。 116 | 117 | > https://developers.weixin.qq.com/miniprogram/dev/api/updatePrinter.html 118 | 119 | ```php 120 | $app->express->unbindPrinter($openid); 121 | ``` 122 | -------------------------------------------------------------------------------- /payment/transfer.md: -------------------------------------------------------------------------------- 1 | # 企业付款 2 | 3 | > EasyWeChat 4.0.7+ 4 | 5 | 该模块需要用到双向证书,请参考:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=4_3 6 | 7 | ## 企业付款到用户零钱 8 | 9 | ```php 10 | $app->transfer->toBalance([ 11 | 'partner_trade_no' => '1233455', // 商户订单号,需保持唯一性(只能是字母或者数字,不能包含有符号) 12 | 'openid' => 'oxTWIuGaIt6gTKsQRLau2M0yL16E', 13 | 'check_name' => 'FORCE_CHECK', // NO_CHECK:不校验真实姓名, FORCE_CHECK:强校验真实姓名 14 | 're_user_name' => '王小帅', // 如果 check_name 设置为FORCE_CHECK,则必填用户真实姓名 15 | 'amount' => 10000, // 企业付款金额,单位为分 16 | 'desc' => '理赔', // 企业付款操作说明信息。必填 17 | ]); 18 | ``` 19 | 20 | ## 查询付款到零钱的订单 21 | 22 | ```php 23 | $partnerTradeNo = 1233455; 24 | $app->transfer->queryBalanceOrder($partnerTradeNo); 25 | ``` 26 | 27 | 28 | ## 企业付款到银行卡 29 | 30 | 企业付款到银行卡需要对银行卡号与姓名进行 RSA 加密,所以这里需要先下载 RSA 公钥到本地(服务器),我们提供了一个命令行工具:[EasyWeChat/console](https://github.com/EasyWeChat/console),请使用 composer 安装完成。 31 | 32 | ```bash 33 | $ composer require easywechat/console -vvv 34 | ``` 35 | 36 | 然后,在项目根目录执行以下命令下载公钥: 37 | 38 | ```bash 39 | $ ./vendor/bin/easywechat payment:rsa_public_key \ 40 | > --mch_id=14339221228 \ 41 | > --api_key=36YTbDmLgyQ52noqdxgwGiYy \ 42 | > --cert_path=/Users/overtrue/www/demo/apiclient_cert.pem \ 43 | > --key_path=/Users/overtrue/www/demo/apiclient_key.pem 44 | ``` 45 | 46 | 将会在当前目录生成一个 `./public-14339221228.pem` 文件,你可以将它移动到敏感目录,然后在支付配置文件中加如以下选项: 47 | 48 | ```php 49 | use EasyWeChat\Factory; 50 | 51 | $config = [ 52 | // 必要配置 53 | 'app_id' => 'xxxx', 54 | 'mch_id' => 'your-mch-id', 55 | 'key' => 'key-for-signature', // API 密钥 56 | 57 | // 如需使用敏感接口(如退款、发送红包等)需要配置 API 证书路径(登录商户平台下载 API 证书) 58 | 'cert_path' => '/path/to/your/cert.pem', // XXX: 绝对路径!!!! 59 | 'key_path' => '/path/to/your/key', // XXX: 绝对路径!!!! 60 | 61 | // 将上面得到的公钥存放路径填写在这里 62 | 'rsa_public_key_path' => '/path/to/your/rsa/publick/key/public-14339221228.pem', // <<<------------------------ 63 | 64 | 'notify_url' => '默认的订单回调地址', // 你也可以在下单时单独设置来想覆盖它 65 | ]; 66 | 67 | $app = Factory::payment($config); 68 | ``` 69 | 70 | ```php 71 | $result = $app->transfer->toBankCard([ 72 | 'partner_trade_no' => '1229222022', 73 | 'enc_bank_no' => '6214830901234564', // 银行卡号 74 | 'enc_true_name' => '安正超', // 银行卡对应的用户真实姓名 75 | 'bank_code' => '1001', // 银行编号 76 | 'amount' => 100, // 单位:分 77 | 'desc' => '测试', 78 | ]); 79 | 80 | ``` 81 | 82 | ## 查询付款到银行卡的订单 83 | 84 | ```php 85 | $partnerTradeNo = 1233455; 86 | $app->transfer->queryBankCardOrder($partnerTradeNo); 87 | ``` 88 | 89 | -------------------------------------------------------------------------------- /official-account/customer_service.md: -------------------------------------------------------------------------------- 1 | # 客服 2 | 3 | 使用客服系统可以向用户发送消息以及群发消息,客服的管理等功能。 4 | 5 | ## 客服管理 6 | 7 | ### 获取所有客服 8 | 9 | ```php 10 | $app->customer_service->list(); 11 | ``` 12 | 13 | ### 获取所有在线的客服 14 | 15 | ```php 16 | $app->customer_service->online(); 17 | ``` 18 | 19 | ### 添加客服 20 | 21 | ```php 22 | $app->customer_service->create('foo@test', '客服1'); 23 | ``` 24 | 25 | ### 修改客服 26 | 27 | ```php 28 | $app->customer_service->update('foo@test', '客服1'); 29 | ``` 30 | 31 | ### 删除账号 32 | 33 | ```php 34 | $app->customer_service->delete('foo@test'); 35 | ``` 36 | 37 | ### 设置客服头像 38 | 39 | ```php 40 | $app->customer_service->setAvatar('foo@test', $avatarPath); // $avatarPath 为本地图片路径,非 URL 41 | ``` 42 | 43 | ### 获取客服与客户聊天记录 44 | 45 | ```php 46 | $app->customer_service->messages($startTime, $endTime, $msgId = 1, $number = 10000); 47 | ``` 48 | 49 | 示例: 50 | 51 | ```php 52 | $records = $app->customer_service->messages('2015-06-07', '2015-06-21', 1, 20000); 53 | ``` 54 | 55 | ### 主动发送消息给用户 56 | 57 | ```php 58 | $app->customer_service->message($message)->to($openId)->send(); 59 | ``` 60 | 61 | > `$message` 为消息对象或文本,请参考:[消息](messages) 62 | 63 | 示例: 64 | 65 | ```php 66 | $app->customer_service->message('hello') 67 | > ->to('oV-gpwdOIwSI958m9osAhGBFxxxx') 68 | > ->send(); 69 | ``` 70 | 71 | ### 指定客服发送消息 72 | 73 | ```php 74 | $app->customer_service->message($message) 75 | > ->from('account@test') 76 | > ->to($openId) 77 | > ->send(); 78 | ``` 79 | > `$message` 为消息对象或文本,请参考:[消息](messages.html) 80 | 81 | 示例: 82 | 83 | ```php 84 | $app->customer_service->message('hello') 85 | > ->from('kf2001@gh_176331xxxx') 86 | > ->to('oV-gpwdOIwSI958m9osAhGBFxxxx') 87 | > ->send(); 88 | ``` 89 | 90 | ### 邀请微信用户加入客服 91 | 92 | 以账号 `foo@test` 邀请 微信号 为 `xxxx` 的微信用户加入客服。 93 | 94 | ```php 95 | $app->customer_service->invite('foo@test', 'xxxx'); 96 | ``` 97 | 98 | ## 客服会话控制 99 | 100 | ## 创建会话 101 | 102 | ```php 103 | $app->customer_service_session->create('test1@test', 'OPENID'); 104 | ``` 105 | 106 | ### 关闭会话 107 | 108 | ```php 109 | $app->customer_service_session->close('test1@test', 'OPENID'); 110 | ``` 111 | 112 | ### 获取客户会话状态 113 | 114 | ```php 115 | $app->customer_service_session->get('OPENID'); 116 | ``` 117 | 118 | ### 获取客服会话列表 119 | 120 | ```php 121 | $app->customer_service_session->list('test1@test'); 122 | ``` 123 | 124 | ### 获取未接入会话列表 125 | 126 | ```php 127 | $app->customer_service_session->waiting(); 128 | ``` 129 | -------------------------------------------------------------------------------- /official-account/data_cube.md: -------------------------------------------------------------------------------- 1 | # 数据统计与分析 2 | 3 | 通过数据接口,开发者可以获取与公众平台官网统计模块类似但更灵活的数据,还可根据需要进行高级处理。 4 | 5 | > {info} 6 | > 1. 接口侧的公众号数据的数据库中仅存储了 **2014年12月1日之后**的数据,将查询不到在此之前的日期,即使有查到,也是不可信的脏数据; 7 | > 2. 请开发者在调用接口获取数据后,将数据保存在自身数据库中,即加快下次用户的访问速度,也降低了微信侧接口调用的不必要损耗。 8 | > 3. 额外注意,获取图文群发每日数据接口的结果中,只有**中间页阅读人数+原文页阅读人数+分享转发人数+分享转发次数+收藏次数 >=3** 的结果才会得到统计,过小的阅读量的图文消息无法统计。 9 | 10 | ## 示例 11 | 12 | ```php 13 | $userSummary = $app->data_cube->userSummary('2014-12-07', '2014-12-08'); 14 | 15 | var_dump($userSummary); 16 | // 17 | //[ 18 | // { 19 | // "ref_date": "2014-12-07", 20 | // "user_source": 0, 21 | // "new_user": 0, 22 | // "cancel_user": 0 23 | // } 24 | // //后续还有ref_date在begin_date和end_date之间的数据 25 | // ] 26 | 27 | ``` 28 | 29 | ## API 30 | 31 | $from 示例: `2014-02-13` 获取数据的起始日期 32 | $to 示例: `2014-02-18` 获取数据的结束日期,`$to`允许设置的最大值为昨日 33 | 34 | `$from` 和 `$to` 的差值需小于 “最大时间跨度”(比如最大时间跨度为 1 时,`$from` 和 `$to` 的差值只能为 0,才能小于 1 ),否则会报错 35 | 36 | + `array userSummary(string $from, string $to)` 获取用户增减数据, 最大时间跨度:**7**; 37 | + `array userCumulate(string $from, string $to)` 获取累计用户数据, 最大时间跨度:**7**; 38 | + `array articleSummary(string $from, string $to)` 获取图文群发每日数据, 最大时间跨度:**1**; 39 | + `array articleTotal(string $from, string $to)` 获取图文群发总数据, 最大时间跨度:**1**; 40 | + `array userReadSummary(string $from, string $to)` 获取图文统计数据, 最大时间跨度:**3**; 41 | + `array userReadHourly(string $from, string $to)` 获取图文统计分时数据, 最大时间跨度:**1**; 42 | + `array userShareSummary(string $from, string $to)` 获取图文分享转发数据, 最大时间跨度:**7**; 43 | + `array userShareHourly(string $from, string $to)` 获取图文分享转发分时数据, 最大时间跨度:**1**; 44 | + `array upstreamMessageSummary(string $from, string $to)` 获取消息发送概况数据, 最大时间跨度:**7**; 45 | + `array upstreamMessageHourly(string $from, string $to)` 获取消息发送分时数据, 最大时间跨度:**1**; 46 | + `array upstreamMessageWeekly(string $from, string $to)` 获取消息发送周数据, 最大时间跨度:**30**; 47 | + `array upstreamMessageMonthly(string $from, string $to)` 获取消息发送月数据, 最大时间跨度:**30**; 48 | + `array upstreamMessageDistSummary(string $from, string $to)` 获取消息发送分布数据, 最大时间跨度:**15**; 49 | + `array upstreamMessageDistWeekly(string $from, string $to)` 获取消息发送分布周数据, 最大时间跨度:**30**; 50 | + `array upstreamMessageDistMonthly(string $from, string $to)` 获取消息发送分布月数据, 最大时间跨度:**30**; 51 | + `array interfaceSummary(string $from, string $to)` 获取接口分析数据, 最大时间跨度:**30**; 52 | + `array interfaceSummaryHourly(string $from, string $to)` 获取接口分析分时数据, 最大时间跨度:**1**; 53 | + `array cardSummary(string $from, string $to, int $condSource = 0)` 获取普通卡券分析分时数据, 最大时间跨度:**1**; 54 | + `array freeCardSummary(string $from, string $to, int $condSource = 0, string $cardId = '')` 获取免费券分析分时数据, 最大时间跨度:**1**; 55 | + `array memberCardSummary(string $from, string $to, int $condSource = 0)` 获取会员卡分析分时数据, 最大时间跨度:**1**; 56 | -------------------------------------------------------------------------------- /official-account/user.md: -------------------------------------------------------------------------------- 1 | # 用户 2 | 3 | 用户信息的获取是微信开发中比较常用的一个功能了,以下所有的用户信息的获取与更新,都是**基于微信的 `openid` 的,并且是已关注当前账号的**,其它情况可能无法正常使用。 4 | 5 | ## 获取用户信息 6 | 7 | 获取单个: 8 | 9 | ```php 10 | $user = $app->user->get($openId); 11 | ``` 12 | 13 | 获取多个: 14 | 15 | ```php 16 | $users = $app->user->select([$openId1, $openId2, ...]); 17 | ``` 18 | 19 | ## 获取用户列表 20 | 21 | ```php 22 | $app->user->list($nextOpenId = null); // $nextOpenId 可选 23 | ``` 24 | 25 | 示例: 26 | 27 | ```php 28 | $users = $app->user->list(); 29 | 30 | // result 31 | { 32 | "total": 2, 33 | "count": 2, 34 | "data": { 35 | "openid": [ 36 | "OPENID1", 37 | "OPENID2" 38 | ] 39 | }, 40 | "next_openid": "NEXT_OPENID" 41 | } 42 | ``` 43 | 44 | ## 修改用户备注 45 | 46 | ```php 47 | $app->user->remark($openId, $remark); // 成功返回boolean 48 | ``` 49 | 50 | 示例: 51 | 52 | ```php 53 | $app->user->remark($openId, "僵尸粉"); 54 | ``` 55 | 56 | ## 拉黑用户 57 | 58 | ```php 59 | $app->user->block('openidxxxxx'); 60 | // 或者多个用户 61 | $app->user->block(['openid1', 'openid2', 'openid3', ...]); 62 | ``` 63 | 64 | ## 取消拉黑用户 65 | 66 | ```php 67 | $app->user->unblock('openidxxxxx'); 68 | // 或者多个用户 69 | $app->user->unblock(['openid1', 'openid2', 'openid3', ...]); 70 | ``` 71 | 72 | ## 获取黑名单 73 | 74 | ```php 75 | $app->user->blacklist($beginOpenid = null); // $beginOpenid 可选 76 | ``` 77 | 78 | ## 账号迁移 openid 转换 79 | 80 | 账号迁移请从这里了解:https://kf.qq.com/product/weixinmp.html#hid=2488 81 | 82 | 微信用户关注不同的公众号,对应的 OpenID 是不一样的,迁移成功后,粉丝的 OpenID 以目标帐号(即新公众号)对应的 OpenID 为准。但开发者可以通过开发接口转换 OpenID,开发文档可以参考: 83 | 提供一个 openid 转换的 API 接口,当帐号迁移后,可以通过该接口: 84 | 85 | 1. 将原帐号粉丝的 openid 转换为新帐号的 openid。 86 | 2. 将有授权关系用户的 openid 转换为新帐号的 openid。 87 | 3. 将卡券关联用户的 openid 转换为新帐号的 openid。 88 | 89 | > - ◆ 原帐号:准备要迁移的帐号,当审核完成且管理员确认后即被回收。 90 | > - ◆ 新帐号:用来接纳粉丝的帐号。新帐号在整个流程中均能正常使用。 91 | 92 | 一定要按照下面的步骤来操作。 93 | 94 | 1. 一定要在原帐号被冻结之前,最好是准备提交审核前,获取原帐号的用户列表。如果没有原帐号的用户列表,用不了转换工具。如果原账号被回收,这时候也没办法调用接口获取用户列表。 95 | 96 | {info} 如何获取用户列表见这里:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140840 97 | 98 | 2. 转换 openid 的 API 接口如下,可在帐号迁移审核完成后开始调用,并最多保留15天。若帐号迁移没完成,调用时无返回结果或报错。帐号迁移15天后,该转换接口将会失效、无法拉取到数据。 99 | 100 | ```php 101 | $app->user->changeOpenid($oldAppId, $openidList); 102 | ``` 103 | 104 | 返回值样例: 105 | 106 | ```json 107 | { 108 | "errcode":0, 109 | "errmsg":"ok", 110 | "result_list":[ 111 | { 112 | "ori_openid":"oEmYbwN-n24jxvk4Sox81qedINkQ", 113 | "new_openid":"o2FwqwI9xCsVadFah_HtpPfaR-X4", 114 | "err_msg":"ok" 115 | }, 116 | { 117 | "ori_openid":"oEmYbwH9uVd4RKJk7ZZg6SzL6tTo", 118 | "err_msg":"ori_openid error" 119 | } 120 | ] 121 | } 122 | ``` 123 | -------------------------------------------------------------------------------- /overview.md: -------------------------------------------------------------------------------- 1 | # EasyWeChat 2 | 3 | EasyWeChat 是一个开源的 [微信](http://www.wechat.com) 非官方 SDK。 4 | 5 | EasyWeChat 的安装非常简单,因为它是一个标准的 [Composer](https://getcomposer.org/) 包,这意味着任何满足下列安装条件的 PHP 项目支持 Composer 都可以使用它。 6 | 7 | ### 环境需求 8 | 9 | > - PHP >= 7.0 10 | > - [PHP cURL 扩展](http://php.net/manual/en/book.curl.php) 11 | > - [PHP OpenSSL 扩展](http://php.net/manual/en/book.openssl.php) 12 | > - [PHP SimpleXML 扩展](http://php.net/manual/en/book.simplexml.php) 13 | > - [PHP fileinfo 拓展](http://php.net/manual/en/book.fileinfo.php) 14 | 15 | 16 | 17 | ### 加入我们 18 | 19 | [EasyWeChat SDK 交流群](http://shang.qq.com/wpa/qunwpa?idkey=b4dcf3ec51a7e8c3c3a746cf450ce59895e5c4ec4fbcb0f80c2cd97c3c6e63e9) ID: 319502940 20 | 21 | > {warning} 为了避免广告及不看文档用户,加群需要付费,所以请使用 能支持群费的客户端。 22 | > 另外:付费加群不代表我们有责任在群里回答你的问题,所以请认真阅读微信官方文档与 SDK 使用文档再使用,否则提的低级问题不会有人理你 23 | > 不喜勿加,谢谢! 24 | > 除非你发现了明确的 Bug,否则不要在群里 @ 我 :pray: 25 | 26 | 你有以下两种方式加入到我们中来,为广大开发者提供更优质的免费开源的服务: 27 | 28 | > - **贡献代码**:我们的代码都在 [overtrue/wechat](https://github.com/overtrue/wechat) ,你可以提交 PR 到任何一个项目,当然,前提是代码质量必须是 OK 的。 29 | > - **翻译或补充文档**:我们的文档在:[EasyWeChat/docs](https://github.com/easywechat/docs/),你可以选择补充文档或者参与英文文档的翻译,目前有 `zh-cn` 与 `en` 两个分支,你可以提交对应的 PR 到目标分支参与翻译工作。 30 | 31 | ### 开始之前 32 | 33 | 我们提供了视频教程:https://www.easywechat.com/tutorials 当然,我还是建议你具备以下基础知识,否则可能没有那么快上手。 34 | 35 | 本 SDK 不是一个全新再造的东西,所以我不会从 0 开始教会你开发微信,你完全有必要在使用本 SDK 前做好以下工作: 36 | 37 | > - 具备 PHP 基础知识,不要连闭包是啥都不明白,可以参考我在知乎的回答: [想要开发自己的PHP框架需要那些知识储备?](http://www.zhihu.com/question/26635323/answer/33812516) 38 | > - 熟悉 PHP 常见的知识:自动加载、composer 的使用、JSON 处理、Curl 的使用等; 39 | > - **仔细阅读并看懂**[微信官方文档](http://mp.weixin.qq.com/wiki/13/80a1a25adbc46faf2716774c423b3151.html) [微信开放平台文档](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419318292&token=&lang=zh_CN); 40 | > - 明白微信接口的组成,自有服务器、微信服务器、公众号(还有其它各种号)、测试号、以及通信原理(交互过程); 41 | > - 了解基本的 HTTP 协议,Header 头、请求方式(GET\POST\PUT\PATCH\DELETE)等; 42 | > - 基本的 Debug 技能,查看 php 日志,nginx 日志等。 43 | 44 | 如果你不具备这些知识,请不要使用,因为用起来会比较痛苦。 45 | 46 | 另外你有必要看一下以下的链接: 47 | 48 | > - https://phphub.org/topics/535 49 | > - http://laravel-china.github.io/php-the-right-way/ 50 | 51 | 如果你在群里问以下类似的问题,这真的是你没有做好上面的工作: 52 | 53 | > - "为啥我的不行啊,请问服务器日志怎么看啊?" 54 | > - "请问这是什么原因啊?[结果/报错截图]" 55 | > - "请问这个SDK怎么用啊?" 56 | > - "谁能告诉我这个SDK是怎么安装的啊?" 57 | > - "怎么接收用户发的消息啊?" 58 | > - "为啥我的报这个错啊:Class XXXX not found..." 59 | > - ... 60 | 61 | 我们专门针对一些容易出现的通用问题已经做了汇总: [疑难解答](/docs/master/zh-CN/troubleshooting) ,如果你在问题疑难解答没找到你出现的问题,那么可以在这里提问 [GitHub](https://github.com/overtrue/wechat/issues),提问请描述清楚你用的版本,你的做法是什么,不然别人没法帮你。 62 | 63 | > {warning} 最后,请 **不要在QQ单独找我提问**,除非你是发现了明显的bug。有问题先审查代码,看文档, 再 google,然后 去群里发个问题,带上你的代码,重现流程,大家有空的会帮忙你解答。谢谢合作!:pray: 64 | 65 | 66 | ### 打赏支持 67 | 68 | 这是一个开源的项目,我们没有收费服务,你如果觉得你从中获益,简化了你的开发工作,你可以 [打赏](/donate) 来支持我们。 69 | -------------------------------------------------------------------------------- /mini-program/app_code.md: -------------------------------------------------------------------------------- 1 | # 小程序码 2 | 3 | ## 获取小程序码 4 | 5 | ### 接口A: 适用于需要的码数量较少的业务场景 6 | 7 | API: 8 | 9 | ``` 10 | $app->app_code->get(string $path, array $optional = []); 11 | ``` 12 | 13 | 其中 `$optional` 为以下可选参数: 14 | 15 | > - **width** Int - 默认 430 二维码的宽度 16 | > - **auto_color** 默认 false 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 17 | > - **line_color** 数组,`auto_color` 为 `false` 时生效,使用 rgb 设置颜色 例如 ,示例:`["r" => 0,"g" => 0,"b" => 0]`。 18 | 19 | 示例代码: 20 | 21 | ```php 22 | $response = $app->app_code->get('path/to/page'); 23 | // 或者 24 | $response = $app->app_code->get('path/to/page', [ 25 | 'width' => 600, 26 | //... 27 | ]); 28 | 29 | // 或者指定颜色 30 | $response = $app->app_code->get('path/to/page', [ 31 | 'width' => 600, 32 | 'line_color' => [ 33 | 'r' => 105, 34 | 'g' => 166, 35 | 'b' => 134, 36 | ], 37 | ]); 38 | 39 | // $response 成功时为 EasyWeChat\Kernel\Http\StreamResponse 实例,失败时为数组或者你指定的 API 返回格式 40 | 41 | // 保存小程序码到文件 42 | if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) { 43 | $filename = $response->save('/path/to/directory'); 44 | } 45 | 46 | // 或 47 | if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) { 48 | $filename = $response->saveAs('/path/to/directory', 'appcode.png'); 49 | } 50 | ``` 51 | 52 | ### 接口B:适用于需要的码数量极多,或仅临时使用的业务场景 53 | 54 | API: 55 | 56 | ``` 57 | $app->app_code->getUnlimit(string $scene, array $optional = []); 58 | ``` 59 | 60 | > 其中 $scene 必填,$optinal 与 get 方法一致,多一个 page 参数。 61 | 62 | 示例代码: 63 | 64 | ```php 65 | $response = $app->app_code->getUnlimit('scene-value', [ 66 | 'page' => 'path/to/page', 67 | 'width' => 600, 68 | ]); 69 | // $response 成功时为 EasyWeChat\Kernel\Http\StreamResponse 实例,失败为数组或你指定的 API 返回类型 70 | 71 | // 保存小程序码到文件 72 | if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) { 73 | $filename = $response->save('/path/to/directory'); 74 | } 75 | // 或 76 | if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) { 77 | $filename = $response->saveAs('/path/to/directory', 'appcode.png'); 78 | } 79 | ``` 80 | 81 | ## 获取小程序二维码 82 | 83 | API: 84 | 85 | ``` 86 | $app->app_code->getQrCode(string $path, int $width = null); 87 | ``` 88 | 89 | > 其中 $path 必填,其余参数可留空。 90 | 91 | 示例代码: 92 | 93 | ```php 94 | $response = $app->app_code->getQrCode('/path/to/page'); 95 | 96 | // $response 成功时为 EasyWeChat\Kernel\Http\StreamResponse 实例,失败为数组或你指定的 API 返回类型 97 | 98 | // 保存小程序码到文件 99 | if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) { 100 | $filename = $response->save('/path/to/directory'); 101 | } 102 | 103 | // 或 104 | if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) { 105 | $filename = $response->saveAs('/path/to/directory', 'appcode.png'); 106 | } 107 | ``` 108 | 109 | ## 110 | -------------------------------------------------------------------------------- /mini-program/nearby_poi.md: -------------------------------------------------------------------------------- 1 | # 附近的小程序 2 | 3 | > 微信文档:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/nearby-poi/nearbyPoi.add.html 4 | 5 | ## 添加地点 6 | 7 | ```php 8 | $params = [ 9 | 'kf_info' => '{"open_kf":true,"kf_headimg":"http://mmbiz.qpic.cn/mmbiz_jpg/kKMgNtnEfQzDKpLXYhgo3W3Gndl34gITqmP914zSwhajIEJzUPpx40P7R8fRe1QmicneQMhFzpZNhSLjrvU1pIA/0?wx_fmt=jpeg","kf_name":"Harden"}', 10 | '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"]}', 11 | 'service_infos' => '{"service_infos":[{"id":2,"type":1,"name":"快递","appid":"wx1373169e494e0c39","path":"index"},{"id":0,"type":2,"name":"自定义","appid":"wx1373169e494e0c39","path":"index"}]}', 12 | 'store_name' => '羊村小马烧烤', 13 | 'contract_phone' => '111111111', 14 | 'hour' => '00:00-11:11', 15 | 'company_name' => '深圳市腾讯计算机系统有限公司', 16 | 'credential' => '156718193518281', 17 | 'address' => '新疆维吾尔自治区克拉玛依市克拉玛依区碧水路15-1-8号(碧水云天广场)', 18 | 'qualification_list' => '3LaLzqiTrQcD20DlX_o-OV1-nlYMu7sdVAL7SV2PrxVyjZFZZmB3O6LPGaYXlZWq', 19 | ]; 20 | 21 | $app->nearby_poi->add($params); 22 | ``` 23 | 24 | ## 更新地点 25 | 26 | ```php 27 | $poiId = 'xxxxxxxx'; 28 | 29 | $params = [ 30 | 'kf_info' => '{"open_kf":true,"kf_headimg":"http://mmbiz.qpic.cn/mmbiz_jpg/kKMgNtnEfQzDKpLXYhgo3W3Gndl34gITqmP914zSwhajIEJzUPpx40P7R8fRe1QmicneQMhFzpZNhSLjrvU1pIA/0?wx_fmt=jpeg","kf_name":"Harden"}', 31 | '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"]}', 32 | 'service_infos' => '{"service_infos":[{"id":2,"type":1,"name":"快递","appid":"wx1373169e494e0c39","path":"index"},{"id":0,"type":2,"name":"自定义","appid":"wx1373169e494e0c39","path":"index"}]}', 33 | 'contract_phone' => '111111111', 34 | 'hour' => '00:00-11:11', 35 | 'company_name' => '深圳市腾讯计算机系统有限公司', 36 | 'credential' => '156718193518281', 37 | 'address' => '新疆维吾尔自治区克拉玛依市克拉玛依区碧水路15-1-8号(碧水云天广场)', 38 | 'qualification_list' => '3LaLzqiTrQcD20DlX_o-OV1-nlYMu7sdVAL7SV2PrxVyjZFZZmB3O6LPGaYXlZWq', 39 | ]; 40 | 41 | $app->nearby_poi->update($poiId, $params); 42 | ``` 43 | 44 | ## 删除地点 45 | 46 | ```php 47 | $poiId = 'xxxxxxxx'; 48 | 49 | $app->nearby_poi->delete($poiId); 50 | ``` 51 | 52 | ## 地点列表 53 | 54 | ```php 55 | $page = 1; 56 | $pageRows = 10; 57 | 58 | $app->nearby_poi->list($page, $pageRows); 59 | ``` 60 | 61 | ## 设置地点展示状态 62 | 63 | ```php 64 | $poiId = 'xxxxxxxx'; 65 | $status = 0; // 0: 不展示,1:展示 66 | 67 | $app->nearby_poi->setVisibility($poiId, $status); 68 | ``` 69 | -------------------------------------------------------------------------------- /payment/redpack.md: -------------------------------------------------------------------------------- 1 | # 红包 2 | 3 | 4 | 在阅读本文之前确认你已经仔细阅读了:[微信支付 | 现金红包文档 ](https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_1)。 5 | 6 | ## 配置 7 | 8 | 与支付接口一样,红包接口也需要配置如下参数,需要特别注意的是,红包相关的全部接口**都需要使用 SSL 证书**,因此**cert_path 以及 cert_key 必须正确配置**。 9 | 10 | ```php 11 | use EasyWeChat\Factory; 12 | 13 | $config = [ 14 | 'app_id' => 'you-app-id', 15 | 'mch_id' => 'your-mch-id', 16 | 'key' => 'key-for-signature', 17 | 'cert_path' => 'path/to/your/cert.pem', 18 | 'key_path' => 'path/to/your/key', 19 | // ... 20 | ]; 21 | 22 | $payment = Factory::payment($config); 23 | 24 | $redpack = $payment->redpack; 25 | ``` 26 | 27 | ## 发送红包 28 | 29 | 微信的现金红包分为**普通红包**和**裂变红包**两类。SDK 中对其分别进行了封装,同时也提供了一个统一的调用方法。 30 | 31 | **默认情况下,通过接口发送的红包金额应该在200元以内,但可以通过在调用发送接口时传递场景 ID (scene_id)来发送特定场景的红包,不同场景红包可以由商户自己登录商户平台设置最大金额。scene_id 的可选值及对应含义可参阅微信支付官方文档。** 32 | 33 | 34 | ### 发送普通红包接口 35 | 36 | ```php 37 | $redpackData = [ 38 | 'mch_billno' => 'xy123456', 39 | 'send_name' => '测试红包', 40 | 're_openid' => 'oxTWIuGaIt6gTKsQRLau2M0yL16E', 41 | 'total_num' => 1, //固定为1,可不传 42 | 'total_amount' => 100, //单位为分,不小于100 43 | 'wishing' => '祝福语', 44 | 'client_ip' => '192.168.0.1', //可不传,不传则由 SDK 取当前客户端 IP 45 | 'act_name' => '测试活动', 46 | 'remark' => '测试备注', 47 | // ... 48 | ]; 49 | 50 | $result = $redpack->sendNormal($redpackData); 51 | ``` 52 | 53 | ### 发送裂变红包接口 54 | 55 | ```php 56 | $redpackData = [ 57 | 'mch_billno' => 'xy123456', 58 | 'send_name' => '测试红包', 59 | 're_openid' => 'oxTWIuGaIt6gTKsQRLau2M0yL16E', 60 | 'total_num' => 3, //不小于3 61 | 'total_amount' => 300, //单位为分,不小于300 62 | 'wishing' => '祝福语', 63 | 'act_name' => '测试活动', 64 | 'remark' => '测试备注', 65 | 'amt_type' => 'ALL_RAND', //可不传 66 | // ... 67 | ]; 68 | 69 | $result = $redpack->sendGroup($redpackData); 70 | ``` 71 | 72 | ## 红包预下单接口 73 | 74 | 红包预下单接口是为摇一摇红包接口配合使用的,在开发摇一摇周边的摇红包相关功能时,需要调用本接口获取红包单号。详情参见[官方文档](http://mp.weixin.qq.com/wiki/7/0ddd50ed2421b99fedd071281c074aab.html#.E7.BA.A2.E5.8C.85.E9.A2.84.E4.B8.8B.E5.8D.95.E6.8E.A5.E5.8F.A3) 75 | 76 | 77 | ```php 78 | $redpackData = [ 79 | 'hb_type' => 'NORMAL', //NORMAL 或 GROUP 80 | 'mch_billno' => 'xy123456', 81 | 'send_name' => '测试红包', 82 | 're_openid' => 'oxTWIuGaIt6gTKsQRLau2M0yL16E', 83 | 'total_num' => 1, //普通红包固定为1,裂变红包不小于3 84 | 'total_amount' => 100, //单位为分,普通红包不小于100,裂变红包不小于300 85 | 'wishing' => '祝福语', 86 | 'client_ip' => '192.168.0.1', //可不传,不传则由 SDK 取当前客户端 IP 87 | 'act_name' => '测试活动', 88 | 'remark' => '测试备注', 89 | 'amt_type' => 'ALL_RAND', 90 | // ... 91 | ]; 92 | 93 | $result = $redpack->prepare($redpackData); 94 | ``` 95 | 96 | ## 查询红包信息 97 | 98 | 用于商户对已发放的红包进行查询红包的具体信息以及领取情况 ,普通红包和裂变包均使用这一接口进行查询。 99 | 100 | ```php 101 | $mchBillNo = "商户系统内部的订单号(mch_billno)"; 102 | $redpack->info($mchBillNo); 103 | ``` 104 | -------------------------------------------------------------------------------- /wework/group-robot.md: -------------------------------------------------------------------------------- 1 | # 群机器人 2 | 3 | ## 使用说明 4 | 使用前必须先在群组里面添加机器人,然后将 `Webhook 地址` 中的 `key` 取出来,作为示例中 `$groupKey` 的值。 5 | 6 | > Webhook 地址示例:https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=`ab4f609a-3feb-427c-ae9d-b319ca712d36` 7 | 8 | > 微信文档:https://work.weixin.qq.com/api/doc#90000/90136/91770 9 | 10 | ## 发送文本类型消息 11 | 12 | 快速发送文本消息 13 | 14 | ```php 15 | // 获取 Messenger 实例 16 | $messenger = $app->group_robot_messenger; 17 | 18 | // 群组 key 19 | $groupKey = 'ab4f609a-3feb-427c-ae9d-b319ca712d36'; 20 | 21 | $messenger->message('大家好,我是本群的"喝水提醒小助手"')->toGroup($groupKey)->send(); 22 | // 或者写成 23 | $messenger->toGroup($groupKey)->send('大家好,我是本群的"喝水提醒小助手"'); 24 | ``` 25 | 26 | 使用 `Text` 发送文本消息 27 | 28 | ```php 29 | use EasyWeChat\Work\GroupRobot\Messages\Text; 30 | 31 | // 准备消息 32 | $text = new Text('hello'); 33 | 34 | // 发送 35 | $messenger->message($text)->toGroup($groupKey)->send(); 36 | ``` 37 | 38 | @某人: 39 | 40 | ```php 41 | use EasyWeChat\Work\GroupRobot\Messages\Text; 42 | 43 | // 通过构造函数传参 44 | $text = new Text('hello', 'her-cat', '18700000000'); 45 | //$text = new Text('hello', ['her-cat', 'overtrue'], ['18700000000', '18700000001']); 46 | 47 | // 通过 userId 48 | $text->mention('her-cat'); 49 | //$text->mention(['her-cat', 'overtrue']); 50 | 51 | // 通过手机号 52 | $text->mentionByMobile('18700000000'); 53 | //$text->mentionByMobile(['18700000000', '18700000001']); 54 | 55 | // @所有人 56 | $text->mention('@all'); 57 | //$text->mentionByMobile('@all'); 58 | 59 | $messenger->message($text)->toGroup($groupKey)->send(); 60 | ``` 61 | 62 | ## 发送 Markdown 类型消息 63 | 64 | ```php 65 | use EasyWeChat\Work\GroupRobot\Messages\Markdown; 66 | 67 | $content = ' 68 | # 标题一 69 | ## 标题二 70 | 绿色 71 | 灰色 72 | 橙红色 73 | > 引用文字 74 | '; 75 | 76 | $markdown = new Markdown($content); 77 | 78 | $messenger->message($markdown)->toGroup($groupKey)->send(); 79 | ``` 80 | 81 | ## 发送图片类型消息 82 | 83 | ```php 84 | use EasyWeChat\Work\GroupRobot\Messages\Image; 85 | 86 | $img = file_get_contents('http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png'); 87 | 88 | $image = new Image(base64_encode($img), md5($img)); 89 | 90 | $result = $messenger->message($image)->toGroup($groupKey)->send(); 91 | ``` 92 | 93 | ## 发送图文类型消息 94 | 95 | ```php 96 | use EasyWeChat\Work\GroupRobot\Messages\News; 97 | use EasyWeChat\Work\GroupRobot\Messages\NewsItem; 98 | 99 | $items = [ 100 | new NewsItem([ 101 | 'title' => '中秋节礼品领取', 102 | 'description' => '今年中秋节公司有豪礼相送', 103 | 'url' => 'https://www.easywechat.com', 104 | 'image' => 'http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png', 105 | ]), 106 | 107 | //... 108 | ]; 109 | 110 | $news = new News($items); 111 | 112 | $messenger->message($news)->toGroup($groupKey)->send(); 113 | ``` 114 | 115 | ## 其他方式 116 | 117 | 使用 `group_robot` 发送消息。 118 | 119 | ```php 120 | $app->group_robot->message('大家好,我是本群的"喝水提醒小助手"')->toGroup($groupKey)->send(); 121 | ``` 122 | -------------------------------------------------------------------------------- /payment/order.md: -------------------------------------------------------------------------------- 1 | # 订单 2 | 3 | ## 统一下单 4 | 5 | 没错,什么 H5 支付,公众号支付,扫码支付,支付中签约,全部都是用这个接口下单。 6 | 7 | > {info} 参数 `appid`, `mch_id`, `nonce_str`, `sign`, `sign_type` 可不用传入 8 | 9 | ```php 10 | $result = $app->order->unify([ 11 | 'body' => '腾讯充值中心-QQ会员充值', 12 | 'out_trade_no' => '20150806125346', 13 | 'total_fee' => 88, 14 | 'spbill_create_ip' => '123.12.12.123', // 可选,如不传该参数,SDK 将会自动获取相应 IP 地址 15 | 'notify_url' => 'https://pay.weixin.qq.com/wxpay/pay.action', // 支付结果通知网址,如果不设置则会使用配置里的默认地址 16 | 'trade_type' => 'JSAPI', // 请对应换成你的支付方式对应的值类型 17 | 'openid' => 'oUpF8uMuAJO_M2pxb1Q9zNjWeS6o', 18 | ]); 19 | 20 | // $result: 21 | //{ 22 | // "return_code": "SUCCESS", 23 | // "return_msg": "OK", 24 | // "appid": "wx2421b1c4390ec4sb", 25 | // "mch_id": "10000100", 26 | // "nonce_str": "IITRi8Iabbblz1J", 27 | // "openid": "oUpF8uMuAJO_M2pxb1Q9zNjWeSs6o", 28 | // "sign": "7921E432F65EB8ED0CE9755F0E86D72F2", 29 | // "result_code": "SUCCESS", 30 | // "prepay_id": "wx201411102639507cbf6ffd8b0779950874", 31 | // "trade_type": "JSAPI" 32 | //} 33 | ``` 34 | 35 | 36 | **第二个参数**为是否[支付中签约](https://pay.weixin.qq.com/wiki/doc/api/pap.php?chapter=18_13&index=5),默认 `false` 37 | 38 | > {info} 支付中签约相关参数 `contract_mchid`, `contract_appid`, `request_serial` 可不用传入 39 | 40 | ```php 41 | $isContract = true; 42 | 43 | $result = $app->order->unify([ 44 | 'body' => '腾讯充值中心-QQ会员充值', 45 | 'out_trade_no' => '20150806125346', 46 | 'total_fee' => 88, 47 | 'spbill_create_ip' => '123.12.12.123', // 可选,如不传该参数,SDK 将会自动获取相应 IP 地址 48 | 'notify_url' => 'https://pay.weixin.qq.com/wxpay/pay.action', // 支付结果通知网址,如果不设置则会使用配置里的默认地址 49 | 'trade_type' => 'JSAPI', // 请对应换成你的支付方式对应的值类型 50 | 'openid' => 'oUpF8uMuAJO_M2pxb1Q9zNjWeS6o', 51 | 52 | 'plan_id' => 123,// 协议模板id 53 | 'contract_code' => 100001256,// 签约协议号 54 | 'contract_display_account' => '腾讯充值中心',// 签约用户的名称 55 | 'contract_notify_url' => 'http://easywechat.org/contract_notify' 56 | ], $isContract); 57 | 58 | //$result: 59 | //{ 60 | // "return_code": "SUCCESS", 61 | // "return_msg": "OK", 62 | // "appid": "wx123456", 63 | // "mch_id": "10000100", 64 | // "nonce_str": "CfOcMkDFblzulYvI", 65 | // "sign": "B53F4AFEE7FA6AD5739581486A5CB9C9", 66 | // "result_code": "SUCCESS", 67 | // "prepay_id": "wx08175759731015754a5c13791522969400", 68 | // "trade_type": "JSAPI", 69 | // "plan_id": "123", 70 | // "request_serial": "1565258279", 71 | // "contract_code": "100001256", 72 | // "contract_display_account": "腾讯充值中心", 73 | // "out_trade_no": "201908088195558331565258279", 74 | // "contract_result_code": "SUCCESS" 75 | //} 76 | ``` 77 | 78 | ## 查询订单 79 | 80 | 该接口提供所有微信支付订单的查询,商户可以通过该接口主动查询订单状态,完成下一步的业务逻辑。 81 | 82 | 需要调用查询接口的情况: 83 | 84 | > - 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知; 85 | > - 调用支付接口后,返回系统错误或未知交易状态情况; 86 | > - 调用被扫支付 API,返回 USERPAYING 的状态; 87 | > - 调用关单或撤销接口 API 之前,需确认支付状态; 88 | 89 | ### 根据商户订单号查询 90 | 91 | ```php 92 | $app->order->queryByOutTradeNumber("商户系统内部的订单号(out_trade_no)"); 93 | ``` 94 | 95 | ### 根据微信订单号查询 96 | 97 | ```php 98 | $app->order->queryByTransactionId("微信订单号(transaction_id)"); 99 | ``` 100 | 101 | ## 关闭订单 102 | 103 | > {warning} 注意:订单生成后不能马上调用关单接口,最短调用时间间隔为5分钟。 104 | 105 | ```php 106 | $app->order->close(商户系统内部的订单号(out_trade_no)); 107 | ``` 108 | -------------------------------------------------------------------------------- /official-account/poi.md: -------------------------------------------------------------------------------- 1 | # 门店 2 | 3 | ## 创建门店 4 | 5 | 用 POI 接口新建门店时所使用的图片 url 必须为微信自己域名的 url,因此需要先用上传图片接 口上传图片并获取 url,再创建门店。上传的图片限制文件大小限制 1MB,支持 JPG 格式,图片接口请参考:[临时素材](media) 6 | 7 | ```php 8 | $app->poi->create($baseInfo); 9 | ``` 10 | 11 | > - `$baseInfo` 为门店的基本信息数组 12 | 13 | 示例: 14 | 15 | ```php 16 | "33788392", 20 | "business_name" => "麦当劳", 21 | "branch_name" => "艺苑路店", 22 | "province" => "广东省", 23 | "city" => "广州市", 24 | "district" => "海珠区", 25 | "address" => "艺苑路 11 号", 26 | "telephone" => "020-12345678", 27 | "categories" => array("美食,快餐小吃"), 28 | "offset_type" => 1, 29 | "longitude" => 115.32375, 30 | "latitude" => 25.097486, 31 | "photo_list" => array( 32 | array("photo_url" => "https://XXX.com"), 33 | array("photo_url" => "https://XXX.com"), 34 | ), 35 | "recommend" => "麦辣鸡腿堡套餐,麦乐鸡,全家桶", 36 | "special" => "免费 wifi,外卖服务", 37 | "introduction" => "麦当劳是全球大型跨国连锁餐厅,1940 年创立于美国,在世界上大约拥有 3 万间分店。主要售卖汉堡包,以及薯条、炸鸡、汽水、冰品、沙拉、水果等 快餐食品", 38 | "open_time" => "8:00-20:00", 39 | "avg_price" => 35, 40 | ); 41 | 42 | $result = $app->poi->create($info); // true or exception 43 | ``` 44 | 45 | > {warning} 注意:新创建的门店在审核通过后,会以事件形式推送给商户填写的回调 URL 46 | 47 | ## 获取指定门店信息 48 | 49 | ```php 50 | $app->poi->get($poiId); 51 | ``` 52 | > - `$poiId` 为门店ID 53 | 54 | 示例: 55 | 56 | ```php 57 | $info = $app->poi->get(271262077); 58 | ``` 59 | 60 | ## 获取门店列表 61 | 62 | ```php 63 | $app->poi->list($begin, $limit);// begin:0, limit:10 64 | ``` 65 | 66 | > - `$begin` 就是查询起点,`MySQL` 里的 `offset`; 67 | > - `$limit` 查询条数,同 `MySQL` 里的 `limit`; 68 | 69 | > 两参数均可选 70 | 71 | 示例: 72 | 73 | ```php 74 | $pois = $app->poi->list(0, 2);// 取2条记录 75 | // 76 | //[ 77 | // { 78 | // "sid": "100", 79 | // "poi_id": "271864249", 80 | // "business_name": "麦当劳", 81 | // "branch_name": "艺苑路店", 82 | // "address": "艺苑路 11 号", 83 | // "available_state": 3 84 | // }, 85 | // { 86 | // "sid": "101", 87 | // "business_name": "麦当劳", 88 | // "branch_name": "赤岗路店", 89 | // "address": "赤岗路 102 号", 90 | // "available_state": 4 91 | // } 92 | //] 93 | ``` 94 | 95 | ## 修改门店信息 96 | 97 | 商户可以通过该接口,修改门店的服务信息,包括:图片列表、营业时间、推荐、特色服务、简 介、人均价格、电话 7 个字段。目前基础字段包括(名称、坐标、地址等不可修改)。 98 | 99 | ```php 100 | $app->poi->update($poiId, $data); 101 | ``` 102 | 103 | > - `$poiId` 为门店ID 104 | > - `$data` 需要更新的部分数据,**若有填写内容则为覆盖更新,若无内容则视为不 修改,维持原有内容。photo_list 字段为全列表覆盖,若需要增加图片,需将之前图片同样放入 list 中,在其后增加新增图片。如:已有 A、B、C 三张图片,又要增加 D、E 两张图,则需要调 用该接口,photo_list 传入 A、B、C、D、E 五张图片的链接。** 105 | 106 | 示例: 107 | 108 | ```php 109 | $data = array( 110 | "telephone" => "020-12345678", 111 | "recommend" => "麦辣鸡腿堡套餐,麦乐鸡,全家桶", 112 | //... 113 | ); 114 | 115 | $res = $app->poi->update(271262077, $data); //true or exception 116 | ``` 117 | 118 | ## 删除门店 119 | 120 | ```php 121 | $app->poi->delete($poiId); 122 | ``` 123 | 124 | 示例: 125 | 126 | ```php 127 | $app->poi->delete(271262077);// true or exception 128 | ``` -------------------------------------------------------------------------------- /payment/notify.md: -------------------------------------------------------------------------------- 1 | # 通知 2 | 3 | ## 支付结果通知 4 | 5 | 在用户成功支付后,微信服务器会向该 **订单中设置的回调URL** 发起一个 POST 请求,请求的内容为一个 XML。里面包含了所有的详细信息,具体请参考:[支付结果通知](https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7) 6 | 7 | 而对于用户的退款操作,在退款成功之后也会有一个异步回调通知。 8 | 9 | 本 SDK 内预置了相关方法,以方便开发者处理这些通知,具体用法如下: 10 | 11 | 只需要在控制器中使用 `handlePaidNotify()` 方法,在其中对自己的业务进行处理并向微信服务器发送一个响应。 12 | 13 | ```php 14 | $response = $app->handlePaidNotify(function ($message, $fail) { 15 | // 你的逻辑 16 | return true; 17 | // 或者错误消息 18 | $fail('Order not exists.'); 19 | }); 20 | 21 | $response->send(); // Laravel 里请使用:return $response; 22 | ``` 23 | 24 | 这里需要注意的有几个点: 25 | 26 | 0. 退款结果通知和扫码支付通知的使用方法均类似。 27 | 1. `handlePaidNotify` 只接收一个 [`Closure`](http://php.net/manual/zh/class.closure.php) 匿名函数。 28 | 2. 该匿名函数接收两个参数,这两个参数分别为: 29 | > - `$message` 为微信推送过来的通知信息,为一个数组; 30 | > - `$fail` 为一个函数,触发该函数可向微信服务器返回对应的错误信息,**微信会稍后重试再通知**。 31 | 32 | 3. 该函数返回值就是告诉微信 **“我是否处理完成”**。如果你触发 `$fail` 函数,那么微信会在稍后再次继续通知你,直到你明确的告诉它:“我已经处理完成了”,**只有**在函数里 `return true;` 才代表处理完成。 33 | 34 | 4. `handlePaidNotify` 返回值 `$response` 是一个 Response 对象,如果你要直接输出,使用 `$response->send()`, 在一些框架里(如 Laravel)不是输出而是返回:`return $response`。 35 | 36 | 通常我们的处理逻辑大概是下面这样(**以下只是伪代码**): 37 | 38 | ```php 39 | $response = $app->handlePaidNotify(function($message, $fail){ 40 | // 使用通知里的 "微信支付订单号" 或者 "商户订单号" 去自己的数据库找到订单 41 | $order = 查询订单($message['out_trade_no']); 42 | 43 |    if (!$order || $order->paid_at) { // 如果订单不存在 或者 订单已经支付过了 44 |        return true; // 告诉微信,我已经处理完了,订单没找到,别再通知我了 45 | } 46 | 47 |    ///////////// <- 建议在这里调用微信的【订单查询】接口查一下该笔订单的情况,确认是已经支付 ///////////// 48 | 49 |    if ($message['return_code'] === 'SUCCESS') { // return_code 表示通信状态,不代表支付状态 50 |        // 用户是否支付成功 51 | if (array_get($message, 'result_code') === 'SUCCESS') { 52 | $order->paid_at = time(); // 更新支付时间为当前时间 53 | $order->status = 'paid'; 54 | 55 | // 用户支付失败 56 | } elseif (array_get($message, 'result_code') === 'FAIL') { 57 | $order->status = 'paid_fail'; 58 | } 59 | } else { 60 |        return $fail('通信失败,请稍后再通知我'); 61 |    } 62 | 63 | $order->save(); // 保存订单 64 | 65 | return true; // 返回处理完成 66 | }); 67 | 68 | $response->send(); // return $response; 69 | ``` 70 | 71 | > {warning} 注意:请把 “支付成功与否” 与 “是否处理完成” 分开,它俩没有必然关系。 72 | > 比如:微信通知你用户支付完成,但是支付失败了(result_code 为 'FAIL'),你应该**更新你的订单为支付失败**,但是要**告诉微信处理完成**。 73 | 74 | ## 退款结果通知 75 | 76 | 使用示例: 77 | 78 | ```php 79 | $response = $app->handleRefundedNotify(function ($message, $reqInfo, $fail) { 80 | // 其中 $message['req_info'] 获取到的是加密信息 81 | // $reqInfo 为 message['req_info'] 解密后的信息 82 | // 你的业务逻辑... 83 | return true; // 返回 true 告诉微信“我已处理完成” 84 | // 或返回错误原因 $fail('参数格式校验错误'); 85 | }); 86 | 87 | $response->send(); 88 | ``` 89 | 90 | ## 扫码支付通知 91 | 92 | 扫码支付【模式一】:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4 93 | 94 | ```php 95 | // 扫码支付通知接收第三个参数 `$alert`,如果触发该函数,会返回“业务错误”到微信服务器,触发 `$fail` 则返回“通信错误” 96 | $response = $app->handleScannedNotify(function ($message, $fail, $alert) use ($app) { 97 | // 如:$alert('商品已售空'); 98 | // 如业务流程正常,则要调用“统一下单”接口,并返回 prepay_id 字符串,代码如下 99 | $result = $app->order->unify([ 100 | 'trade_type' => 'NATIVE', 101 | 'product_id' => $message['product_id'], 102 | // ... 103 | ]); 104 | 105 | return $result['prepay_id']; 106 | }); 107 | 108 | $response->send(); 109 | ``` 110 | -------------------------------------------------------------------------------- /official-account/goods.md: -------------------------------------------------------------------------------- 1 | # 返佣商品 2 | 3 | > 微信文档:https://mp.weixin.qq.com/cgi-bin/announce?action=getannouncement&key=11533749572M9ODP&version=1&lang=zh_CN&platform=2 4 | 5 | ## 导入商品 6 | 7 | 每次调用支持批量导入不超过1000条的商品信息。每分钟单个商户全局调用次数不得超过200次。每天调用次数不得超过100万次。每次请求包大小不超过2M。 8 | 9 | ```php 10 | $data = [ 11 | [ 12 | 'pid' => 'pid001', 13 | 'image_info' => [ 14 | 'main_image_list' => [ 15 | [ 16 | 'url' => 'http://www.google.com/a.jpg', 17 | ], 18 | [ 19 | 'url' => 'http://www.google.com/b.jpg', 20 | ], 21 | ], 22 | ], 23 | 24 | //... 25 | ], 26 | 27 | //... 28 | ]; 29 | 30 | $result = $app->goods->add($data); 31 | 32 | // $result: 33 | //{ 34 | // "errcode": 0, 35 | // "errmsg": "ok", 36 | // "status_ticket": "115141102647330200" 37 | //} 38 | ``` 39 | 40 | `status_ticket` 用于获取此次导入的详细结果。 41 | 42 | ## 更新商品 43 | 44 | 更新时,字段不填代表不更新该字段(此处的字段不填,代表无此字段,而不是把字段的值设为空,设为空即代表更新该字段为空)。 45 | 46 | 对于字符串类型的选填字段,如副标题,若清空不展示,则可设置为空;对于数字类型的选填字段,如原价,若清空不展示,则需设置为0。 47 | 48 | > 基本字段更新中 `pid` 为必填字段,且无法修改 49 | 50 | ```php 51 | $data = [ 52 | [ 53 | 'pid' => 'pid001', 54 | 'image_info' => [ 55 | 'main_image_list' => [ 56 | [ 57 | 'url' => 'http://www.baidu.com/c.jpg', 58 | ], 59 | [ 60 | 'url' => 'http://www.baidu.com/d.jpg', 61 | ], 62 | ], 63 | ], 64 | 65 | //... 66 | ], 67 | 68 | //... 69 | ]; 70 | 71 | $result = $app->goods->update($data); 72 | 73 | // $result: 74 | //{ 75 | // "errcode": 0, 76 | // "errmsg": "ok", 77 | // "status_ticket": "115141102647330200" 78 | //} 79 | ``` 80 | 81 | > 说明:导入商品和更新商品使用的是同一个接口。 82 | 83 | ## 查询导入/更新商品状态 84 | 85 | 用于查询导入或更新商品的结果,当导入或更新商品失败时,若为系统错误可进行重试;若为其他错误,请排查解决后进行重试。 86 | 87 | ```php 88 | $status_ticket = '115141102647330200'; 89 | 90 | $result = $app->goods->status($status_ticket); 91 | 92 | // $result: 93 | //{ 94 | // "errcode": 0, 95 | // "errmsg": "ok", 96 | // "result": { 97 | // "succ_cnt": 2, 98 | // "fail_cnt": 0, 99 | // "total_cnt": 2, 100 | // "progress": "100.00%", 101 | // "statuses": [ 102 | // { 103 | // "pid": "pid001", 104 | // "ret": 0, 105 | // "err_msg": "success", 106 | // "err_msg_zh_cn": "成功" 107 | // }, 108 | // { 109 | // "pid": "pid002", 110 | // "ret": 0, 111 | // "err_msg": "success", 112 | // "err_msg_zh_cn": "成功" 113 | // } 114 | // ] 115 | // } 116 | //} 117 | ``` 118 | 119 | ## 获取单个商品信息 120 | 121 | 使用该接口获取已导入的商品信息,供验证信息及抽查导入情况使用。 122 | 123 | ```php 124 | $pid = 'pid001'; 125 | 126 | $app->goods->get($pid); 127 | ``` 128 | 129 | > 返回结果中的 `product` 字段内容与 `导入商品接口` 字段一致,导入时未设置的值有可能获取时仍会返回,但显示为空 130 | 131 | ## 分页获取商品信息 132 | 133 | 使用该接口可获取已导入的全量商品信息,供全量验证信息使用。 134 | 135 | ```php 136 | $context = ''; // page 为 1 时传空即可。当 page 大于 1 时必填,填入上一次访问本接口返回的 page_context。 137 | $page = 1; // 页码 138 | $size = 10; // 每页数据大小,目前限制为100以内,注意一次全量验证过程中该参数的值需保持不变 139 | 140 | $app->goods->list($context, $page, $size); 141 | ``` 142 | 143 | > 返回结果中的 `product` 字段内容与 `导入商品接口` 字段一致,导入时未设置的值有可能获取时仍会返回,但显示为空。 144 | > `page_context` 字段用于获取下一页数据时使用。 145 | -------------------------------------------------------------------------------- /payment/jssdk.md: -------------------------------------------------------------------------------- 1 | # JSSDK 2 | 3 | JSSDK 模块用于生成调起微信支付以及共享收货地址的调用所需的配置参数。 4 | 5 | ## 配置 6 | 7 | ```php 8 | use EasyWeChat\Factory; 9 | 10 | $config = [ 11 | // 前面的appid什么的也得保留哦 12 | 'app_id' => 'xxxx', 13 | 'mch_id' => 'your-mch-id', 14 | 'key' => 'key-for-signature', 15 | 'cert_path' => 'path/to/your/cert.pem', // XXX: 绝对路径!!!! 16 | 'key_path' => 'path/to/your/key', // XXX: 绝对路径!!!! 17 | 'notify_url' => '默认的订单回调地址', // 你也可以在下单时单独设置来想覆盖它 18 | // 'device_info' => '013467007045764', 19 | // 'sub_app_id' => '', 20 | // 'sub_merchant_id' => '', 21 | // ... 22 | ]; 23 | 24 | $payment = Factory::payment($config); 25 | 26 | $jssdk = $payment->jssdk; 27 | ``` 28 | 29 | ## 生成支付 JS 配置 30 | 31 | 有三种发起支付的方式:[WeixinJSBridge](https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6), [JSSDK](https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_1), [小程序](https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7) 32 | 33 | 1. WeixinJSBridge: 34 | 35 | ```php 36 | $json = $jssdk->bridgeConfig($prepayId); // 返回 json 字符串,如果想返回数组,传第二个参数 false 37 | ``` 38 | 39 | javascript: 40 | 41 | ```js 42 | ... 43 | WeixinJSBridge.invoke( 44 | 'getBrandWCPayRequest', , 45 | function(res){ 46 | if(res.err_msg == "get_brand_wcpay_request:ok" ) { 47 | // 使用以上方式判断前端返回,微信团队郑重提示: 48 | // res.err_msg将在用户支付成功后返回 49 | // ok,但并不保证它绝对可靠。 50 | } 51 | } 52 | ); 53 | ... 54 | ``` 55 | 56 | 2. JSSDK: 57 | 58 | ```php 59 | $config = $jssdk->sdkConfig($prepayId); // 返回数组 60 | ``` 61 | 62 | javascript: 63 | 64 | ```js 65 | wx.chooseWXPay({ 66 | timestamp: , 67 | nonceStr: '', 68 | package: '', 69 | signType: '', 70 | paySign: '', // 支付签名 71 | success: function (res) { 72 | // 支付成功后的回调函数 73 | } 74 | }); 75 | ``` 76 | 77 | 3. 小程序: 78 | 79 | ```php 80 | $config = $jssdk->bridgeConfig($prepayId, false); // 返回数组 81 | ``` 82 | 83 | javascript: 84 | 85 | ```js 86 | wx.requestPayment({ 87 | timeStamp: , //注意 timeStamp 的格式 88 | nonceStr: '', 89 | package: '', 90 | signType: '', 91 | paySign: '', // 支付签名 92 | success: function (res) { 93 | // 支付成功后的回调函数 94 | } 95 | }); 96 | ``` 97 | 98 | ## 生成共享收货地址 JS 配置 99 | 100 | 1. 发起 OAuth 授权,获取用户 `$accessToken`,参考网页授权章节。 101 | 102 | 2. 使用 `$accessToken` 获取配置 103 | 104 | ```php 105 | $configForPickAddress = $jssdk->shareAddressConfig($token); 106 | 107 | // 拿着这个生成好的配置 $configForPickAddress 去订单页(或者直接显示订单页)写 js 调用了 108 | // ... 109 | ``` 110 | 111 | ## 生成 APP 支付配置 112 | 113 | ```php 114 | $config = $jssdk->appConfig($prepayId); 115 | ``` 116 | 117 | `$config` 为数组格式,你可以用 API 返回给客户端 118 | 119 | # 二维码生成工具推荐 120 | 121 | 你也许需要生成二维码,那么以下这些供参考: 122 | 123 | > - https://github.com/endroid/QrCode 124 | > - https://github.com/Bacon/BaconQrCode 125 | > - https://github.com/SimpleSoftwareIO/simple-qrcode (Bacon/BaconQrCode 的 Laravel 版本) 126 | > - https://github.com/aferrandini/PHPQRCode 127 | -------------------------------------------------------------------------------- /customize/cache.md: -------------------------------------------------------------------------------- 1 | # 缓存 2 | 3 | 4 | 本项目使用 [symfony/cache](https://github.com/symfony/cache) 来完成缓存工作,它支持基本目前所有的缓存引擎。 5 | 6 | 在我们的 SDK 中的所有缓存默认使用文件缓存,缓存路径取决于 PHP 的临时目录,如果你需要自定义缓存,那么你需要做如下的事情: 7 | 8 | 你可以参考[symfony/cache官方文档](https://symfony.com/doc/current/components/cache.html) 来替换掉应用中默认的缓存配置: 9 | 10 | 11 | ## 以 redis 为例 12 | 13 | 14 | ### Symfony 4.3 + 15 | 16 | > 请先安装 redis 拓展:`composer require predis/predis` 17 | 18 | ```php 19 | 20 | use Symfony\Component\Cache\Adapter\RedisAdapter; 21 | 22 | // 创建 redis 实例 23 | $client = new \Predis\Client('tcp://10.0.0.1:6379'); 24 | 25 | // 创建缓存实例 26 | $cache = new RedisAdapter($redis); 27 | 28 | // 替换应用中的缓存 29 | $app->rebind('cache', $cache); 30 | ``` 31 | 32 | ### Symfony 3.4 + 33 | 34 | > 请先安装 redis 拓展:https://github.com/phpredis/phpredis 35 | 36 | ```php 37 | 38 | use Symfony\Component\Cache\Simple\RedisCache; 39 | 40 | // 创建 redis 实例 41 | $redis = new Redis(); 42 | $redis->connect('redis_host', 6379); 43 | 44 | // 创建缓存实例 45 | $cache = new RedisCache($redis); 46 | 47 | // 替换应用中的缓存 48 | $app->rebind('cache', $cache); 49 | ``` 50 | 51 | 52 | ### Laravel 中使用 53 | 54 | 在 Laravel 中框架使用 [predis/predis](https://github.com/nrk/predis): 55 | 56 | ### Symfony 4.3 + 57 | 58 | > 请先安装 redis 拓展:`composer require predis/predis` 59 | 60 | ```php 61 | 62 | use Symfony\Component\Cache\Adapter\RedisAdapter; 63 | 64 | // 创建缓存实例 65 | $cache = new RedisAdapter(app('redis')->connection()->client()); 66 | $app->rebind('cache', $cache); 67 | 68 | ``` 69 | 70 | ### Symfony 3.4 + 71 | 72 | ```php 73 | 74 | use Symfony\Component\Cache\Simple\RedisCache; 75 | 76 | $predis = app('redis')->connection()->client(); // connection($name), $name 默认为 `default` 77 | $cache = new RedisCache($predis); 78 | 79 | $app->rebind('cache', $cache); 80 | ``` 81 | 82 | > 上面提到的 `app('redis')->connection($name)`, 这里的 `$name` 是 laravel 项目中配置文件 `database.php` 中 `redis` 配置名 `default`:https://github.com/laravel/laravel/blob/master/config/database.php#L118 83 | > 如果你使用的其它连接,对应传名称就好了。 84 | 85 | ## 使用自定义的缓存方式 86 | 87 | 如果你发现 symfony 提供的十几种缓存方式都满足不了你的需求的话,那么你可以自己建立一个类来完成缓存操作,前提这个类得实现接口:[PSR-16](http://www.php-fig.org/psr/psr-16/) 88 | 89 | 该接口有以下方法需要实现: 90 | 91 | ```php 92 | public function get($key, $default = null); 93 | public function set($key, $value, $ttl = null); 94 | public function delete($key); 95 | public function clear(); 96 | public function getMultiple($keys, $default = null); 97 | public function setMultiple($values, $ttl = null); 98 | public function deleteMultiple($keys); 99 | public function has($key); 100 | ``` 101 | 102 | 下面为一个示例: 103 | 104 | ```php 105 | rebind('cache', new MyCustomCache()); 157 | ``` 158 | 159 | OK,这样就完成了自定义缓存的操作。 160 | -------------------------------------------------------------------------------- /wework/contacts.md: -------------------------------------------------------------------------------- 1 | # 通讯录 2 | 3 | ```php 4 | $config = [ 5 | 'corp_id' => 'xxxxxxxxxxxxxxxxx', 6 | 'secret' => 'xxxxxxxxxx', // 通讯录的 secret 7 | //... 8 | ]; 9 | 10 | $contacts = Factory::work($config); 11 | ``` 12 | 13 | ## 成员管理 14 | ### 创建成员 15 | 16 | ```php 17 | $data = [ 18 | "userid" => "overtrue", 19 | "name" => "超哥", 20 | "english_name" => "overtrue" 21 | "mobile" => "1818888888", 22 | ]; 23 | $contacts->user->create($data); 24 | ``` 25 | 26 | ### 读取成员 27 | 28 | ```php 29 | $contacts->user->get('overtrue'); 30 | ``` 31 | 32 | ### 更新成员 33 | 34 | ```php 35 | $contacts->user->update('overtrue', [ 36 | "isleader": 0, 37 | 'position' => 'PHP 酱油工程师', 38 | //... 39 | ]); 40 | ``` 41 | 42 | ### 删除成员 43 | 44 | ```php 45 | $contacts->user->delete('overtrue'); 46 | // 或者删除多个 47 | $contacts->user->delete(['overtrue', 'zhangsan', 'wangwu']); 48 | ``` 49 | 50 | ### 获取部门成员 51 | 52 | ```php 53 | $contacts->user->getDepartmentUsers($departmentId); 54 | // 递归获取子部门下面的成员 55 | $contacts->user->getDepartmentUsers($departmentId, true); 56 | ``` 57 | 58 | ### 获取部门成员详情 59 | 60 | ```php 61 | $contacts->user->getDetailedDepartmentUsers($departmentId); 62 | // 递归获取子部门下面的成员 63 | $contacts->user->getDetailedDepartmentUsers($departmentId, true); 64 | ``` 65 | 66 | ### 用户 ID 转为 openid 67 | 68 | ```php 69 | $contacts->user->userIdToOpenid($userId); 70 | // 或者指定应用 ID 71 | $contacts->user->userIdToOpenid($userId, $agentId); 72 | ``` 73 | 74 | ### openid 转为用户 ID 75 | 76 | ```php 77 | $contacts->user->openidToUserId($openid); 78 | ``` 79 | 80 | ### 手机号转为用户 ID 81 | 82 | ```php 83 | $contacts->user->mobileToUserId($mobile); 84 | ``` 85 | 86 | ### 二次验证 87 | 88 | 企业在成员验证成功后,调用如下接口即可让成员加入成功 89 | 90 | ```php 91 | $contacts->user->accept($userId); 92 | ``` 93 | 94 | ### 邀请成员 95 | 96 | 企业可通过接口批量邀请成员使用企业微信,邀请后将通过短信或邮件下发通知。 97 | 98 | ```php 99 | $params = [ 100 | 'user' => ['UserID1', 'UserID2', 'UserID3'], // 成员ID列表, 最多支持1000个 101 | 'party' => ['PartyID1', 'PartyID2'], // 部门ID列表,最多支持100个 102 | 'tag' => ['TagID1', 'TagID2'], // 标签ID列表,最多支持100个 103 | ]; 104 | 105 | $contacts->user->invite($params); 106 | ``` 107 | 108 | > `user`, `party`, `tag` 三者不能同时为空 109 | 110 | ### 获取邀请二维码 111 | 112 | ```php 113 | $sizeType = 1; // qrcode尺寸类型,1: 171 x 171; 2: 399 x 399; 3: 741 x 741; 4: 2052 x 2052 114 | 115 | $contacts->user->getInvitationQrCode($sizeType); 116 | ``` 117 | 118 | ## 部门管理 119 | 120 | ### 创建部门 121 | 122 | ```php 123 | $contacts->department->create([ 124 | 'name' => '广州研发中心', 125 | 'parentid' => 1, 126 | 'order' => 1, 127 | 'id' => 2, 128 | ]); 129 | ``` 130 | 131 | ### 更新部门 132 | 133 | ```php 134 | $contacts->department->update($id, [ 135 | 'name' => '广州研发中心', 136 | 'parentid' => 1, 137 | 'order' => 1, 138 | ]); 139 | ``` 140 | 141 | ### 删除部门 142 | 143 | ```php 144 | $contacts->department->delete($id); 145 | ``` 146 | 147 | ### 获取部门列表 148 | 149 | ```php 150 | $contacts->department->list(); 151 | // 获取指定部门及其下的子部门 152 | $contacts->department->list($id); 153 | ``` 154 | 155 | ## 标签管理 156 | 157 | ### 创建标签 158 | 159 | ```php 160 | $contacts->tag->create($tagName, $tagId); 161 | ``` 162 | 163 | ### 更新标签名字 164 | 165 | ```php 166 | $contacts->tag->update($tagId, $tagName); 167 | ``` 168 | 169 | ### 删除标签 170 | 171 | ```php 172 | $contacts->tag->delete($tagId); 173 | ``` 174 | 175 | ### 获取标签列表 176 | 177 | ```php 178 | $contacts->tag->list(); 179 | ``` 180 | 181 | ### 获取标签成员(标签详情) 182 | 183 | ```php 184 | $contacts->tag->get($tagId); 185 | ``` 186 | 187 | ### 增加标签成员 188 | 189 | ```php 190 | $contacts->tag->tagUsers($tagId, [$userId1, $userId2, ...]); 191 | 192 | // 指定部门 193 | $contacts->tag->tagDepartments($tagId, [$departmentId1, $departmentId2, ...]); 194 | ``` 195 | 196 | 197 | ### 删除标签成员 198 | 199 | ```php 200 | $contacts->tag->untagUsers($tagId, [$userId1, $userId2, ...]); 201 | 202 | // 指定部门 203 | $contacts->tag->untagDepartments($tagId, [$departmentId1, $departmentId2, ...]); 204 | ``` 205 | 206 | 207 | 208 | 209 | -------------------------------------------------------------------------------- /official-account/store.md: -------------------------------------------------------------------------------- 1 | # 门店小程序 2 | 3 | ## 拉取门店小程序类目 4 | 5 | ```php 6 | $app->store->categories(); 7 | ``` 8 | 9 | ## 创建门店小程序 10 | 11 | > 说明:创建门店小程序提交后需要公众号管理员确认通过后才可进行审核。如果主管理员24小时超时未确认,才能再次提交。 12 | 13 | ```php 14 | $app->store->createMerchant($baseInfo); 15 | ``` 16 | 17 | > - `$baseInfo` 为门店小程序的基本信息数组,**`qualification_list` 字段为类目相关证件的临时素材 `mediaid` 如果 `second_catid` 对应的 `sensitive_type` 为 1 ,则 `qualification_list` 字段需要填 支持 0~5 个 `mediaid`,例如 `mediaid1`。`headimg_mediaid` 字段为头像 --- 临时素材 `mediaid`。`mediaid` 用现有的 `media/upload` 接口得到的,获取链接: [临时素材](media) ( 支持PNG\JPEG\JPG\GIF格式的图片,后续加上其他格式)** 18 | 19 | 示例: 20 | 21 | ```php 22 | 23 | $info = [ 24 | "first_catid" => 476, //categories 接口获取的一级类目id 25 | "second_catid" => 477, //categories 接口获取的二级类目id 26 | "qualification_list" => "RTZgKZ386yFn5kQSWLTxe4bqxwgzGBjs3OE02cg9CVQk1wRVE3c8fjUFX7jvpi-P", 27 | "headimg_mediaid" => "RTZgKZ386yFn5kQSWLTxe4bqxwgzGBjs3OE02cg9CVQk1wRVE3c8fjUFX7jvpi-P", 28 | "nickname" => "hardenzhang308", 29 | "intro" => "hardenzhangtest", 30 | "org_code" => "", 31 | "other_files" => "" 32 | ]; 33 | 34 | $result = $app->store->createMerchant($info); 35 | ``` 36 | 37 | > {warning} 注意:创建门店小程序的审核结果,会以事件形式推送给商户填写的回调 URL 38 | 39 | ## 查询门店小程序审核结果 40 | 41 | ```php 42 | $app->store->getStatus($baseInfo); 43 | ``` 44 | 45 | ## 修改门店小程序信息 46 | 47 | ```php 48 | $app->store->updateMerchant($data); 49 | ``` 50 | 51 | > - `$data` 需要更新的部分数据,目前仅支持门店头像和门店小程序介绍,**若有填写内容则为覆盖更新,若无内容则视为不修改,维持原有内容。`headimg_mediaid`、`intro` 字段参考创建门店小程序** 52 | 53 | 示例: 54 | 55 | ```php 56 | $data = [ 57 | "headimg_mediaid" => "RTZgKZ386yFn5kQSWLTxe4bqxwgzGBjs3OE02cg9CVQk1wRVE3c8fjUFX7jvpi-P", 58 | "intro" => "麦辣鸡腿堡套餐,麦乐鸡,全家桶", 59 | ]; 60 | 61 | $result = $app->store->updateMerchant($data); 62 | ``` 63 | 64 | ## 从腾讯地图拉取省市区信息 65 | 66 | ```php 67 | $app->store->districts(); 68 | ``` 69 | 70 | ## 在腾讯地图中搜索门店 71 | 72 | ```php 73 | $app->store->searchFromMap($districtId, $keyword); 74 | ``` 75 | > - `$districtId` 为从腾讯地图拉取的地区 `id` 76 | > - `$keyword` 为搜索的关键词 77 | 78 | ## 在腾讯地图中创建门店 79 | 80 | ```php 81 | $app->store->createFromMap($baseInfo); 82 | ``` 83 | 84 | 示例: 85 | 86 | ```php 87 | $baseInfo = [ 88 | "name" => "hardenzhang", 89 | "longitude" => "113.323753357", 90 | "latitude" => "23.0974903107", 91 | "province" => "广东省", 92 | "city" => "广州市", 93 | "district" => "海珠区", 94 | "address" => "TIT", 95 | "category" => "类目1:类目2", 96 | "telephone" => "12345678901", 97 | "photo" => "http://mmbiz.qpic.cn/mmbiz_png/tW66AWE2K6ECFPcyAcIZTG8RlcR0sAqBibOm8gao5xOoLfIic9ZJ6MADAktGPxZI7MZLcadZUT36b14NJ2cHRHA/0?wx_fmt=png", 98 | "license" => "http://mmbiz.qpic.cn/mmbiz_png/tW66AWE2K6ECFPcyAcIZTG8RlcR0sAqBibOm8gao5xOoLfIic9ZJ6MADAktGPxZI7MZLcadZUT36b14NJ2cHRHA/0?wx_fmt=png", 99 | "introduct" => "test", 100 | "districtid" => "440105", 101 | ]; 102 | ``` 103 | 104 | > - `$baseInfo`: 门店相关信息 105 | 106 | > 事件推送 --- 腾讯地图中创建门店的审核结果。腾讯地图审核周期为3个工作日,请在期间内留意审核结果事件推送。提交后未当即返回事件推送即为审核中,请耐心等待。 107 | 108 | ## 添加门店 109 | 110 | ```php 111 | $app->store->create($baseInfo); 112 | ``` 113 | 114 | 示例: 115 | 116 | ```php 117 | $baseInfo = [ 118 | "poi_id" => "", 119 | "map_poi_id" => "2880741500279549033", 120 | "pic_list" => "['list' => ['http://mmbiz.qpic.cn/mmbiz_jpg/tW66AWvE2K4EJxIYOVpiaGOkfg0iayibiaP2xHOChvbmKQD5uh8ymibbEKlTTPmjTdQ8ia43sULLeG1pT2psOfPic4kTw/0?wx_fmt=jpeg']]", 121 | "contract_phone" => "1111222222", 122 | "credential" => "22883878-0", 123 | "qualification_list" => "RTZgKZ386yFn5kQSWLTxe4bqxwgzGBjs3OE02cg9CVQk1wRVE3c8fjUFX7jvpi-P" 124 | ]; 125 | ``` 126 | 127 | > - `$baseInfo`: 门店相关信息。`pic_list` 门店图片,可传多张图片 `pic_list` 128 | 129 | > 事件推送 - 创建门店的审核结果 130 | 131 | ## 更新门店信息 132 | 133 | ```php 134 | $app->store->update($baseInfo); 135 | ``` 136 | 137 | > - `$baseInfo`: 门店相关信息。 138 | 139 | > {warning} 需要注意的是,如果要更新门店的图片,实际相当于走一次重新为门店添加图片的流程,之前的旧图片会全部废弃。并且如果重新添加的图片中有与之前旧图片相同的,此时这个图片不需要重新审核。 140 | -------------------------------------------------------------------------------- /official-account/tutorial.md: -------------------------------------------------------------------------------- 1 | # 快速开始 2 | 3 | 在我们已经安装完成后,即可很快的开始使用它了,当然你还是有必要明白 PHP 基本知识,如命名空间等,我这里就不赘述了。 4 | 5 | 我们以完成服务器端验证与接收响应用户发送的消息为例来演示,首先你有必要了解一下微信交互的运行流程: 6 | 7 | ``` 8 | +-----------------+ +---------------+ 9 | +----------+ | | POST/GET/PUT | | 10 | | | ------------------> | | -------------------> | | 11 | | user | | wechat server | | your server | 12 | | | < - - - - - - - - - | | | | 13 | +----------+ | | <- - - - - - - - - - | | 14 | +-----------------+ +---------------+ 15 | 16 | ``` 17 | 18 | 那么我们要做的就是图中 **微信服务器把用户消息转到我们的自有服务器(虚线返回部分)** 后的处理过程。 19 | 20 | ## 服务端验证 21 | 22 | 在微信接入开始有一个 “服务器验证” 的过程,这一步呢,其实就是微信服务器向我们服务器发起一个请求(上图实线部分),传了一个名称为 `echostr` 的字符串过来,我们只需要原样返回就好了。 23 | 24 | 你也知道,微信后台只能填写一个服务器地址,所以 **服务器验证** 与 **消息的接收与回复**,都在这一个链接内完成交互。 25 | 26 | 考虑到这些,我已经把验证这一步给封装到 SDK 里了,你可以完全忽略这一步。 27 | 28 | 下面我们来配置一个基本的服务端,这里假设我们自己的服务器域名叫 `easywechat.com`,我们在服务器上准备这么一个文件`server.php`: 29 | 30 | // server.php 31 | 32 | ```php 33 | use EasyWeChat\Factory; 34 | 35 | $config = [ 36 | 'app_id' => 'wx3cf0f39249eb0xxx', 37 | 'secret' => 'f1c242f4f28f735d4687abb469072xxx', 38 | 'token' => 'TestToken', 39 | 'response_type' => 'array', 40 | //... 41 | ]; 42 | 43 | $app = Factory::officialAccount($config); 44 | 45 | $response = $app->server->serve(); 46 | 47 | // 将响应输出 48 | $response->send();exit; // Laravel 里请使用:return $response; 49 | 50 | ``` 51 | 52 | > :heart: 安全模式下请一定要配置 `aes_key` 53 | 54 | 一个服务端带验证功能的代码已经完成,当然没有对消息做处理,别着急,后面我们再讲。 55 | 56 | 我们先来分析上面的代码: 57 | 58 | ```php 59 | // 引入我们的主项目工厂类。 60 | use EasyWeChat\Factory; 61 | 62 | // 一些配置 63 | $config = [...]; 64 | 65 | // 使用配置来初始化一个公众号应用实例。 66 | $app = Factory::officialAccount($config); 67 | 68 | $response = $app->server->serve(); 69 | 70 | // 将响应输出 71 | $response->send(); exit; // Laravel 里请使用:return $response; 72 | ``` 73 | 74 | 最后这一行我有必要详细讲一下: 75 | 76 | 77 | >1. 我们的 `$app->server->serve()` 就是执行服务端业务了,那么它的返回值是一个 `Symfony\Component\HttpFoundation\Response` 实例。 78 | >2. 我这里是直接调用了它的 `send()` 方法,它就是直接输出(echo)了,我们在一些框架就不能直接输出了,那你就直接拿到 Response 实例后做相应的操作即可,比如 Laravel 里你就可以直接 `return $app->server->serve();` 79 | 80 | OK, 有了上面的代码,那么请你按 **[微信官方的接入指引](http://mp.weixin.qq.com/wiki/)** 在公众号后台完成配置并启用,并相应修改上面的 `$config` 的相关配置。 81 | 82 | > URL 就是我们的 `http://easywechat.com/server.php`,这里我是举例哦,你可不要填写我的域名。 83 | 84 | 这样,点击提交验证就OK了。 85 | 86 | > :heart: 请一定要将微信后台的开发者模式 “**启用**” !!!!!!看到红色 “**停用**” 才真正的是启用了。 87 | > 最后,请不要用浏览器访问这个地址,它是给微信服务器访问的,不是给人访问的。 88 | 89 | ## 接收 & 回复用户消息 90 | 91 | 那服务端验证通过了,我们就来试一下接收消息吧。 92 | 93 | > 在刚刚上面代码最后一行 `$app->server->serve()->send();` 前面,我们调用 `$app->server` 的 `push()` 方法来注册一个消息处理器,这里用到了 **[PHP 闭包](http://php.net/manual/zh/functions.anonymous.php)** 的知识,如果你不熟悉赶紧补课去。 94 | 95 | ```php 96 | // ... 97 | 98 | $app->server->push(function ($message) { 99 | return "您好!欢迎使用 EasyWeChat!"; 100 | }); 101 | 102 | $response = $app->server->serve(); 103 | 104 | // 将响应输出 105 | $response->send(); // Laravel 里请使用:return $response; 106 | 107 | ``` 108 | 109 | > {warning} 注意:send() 方法里已经包含 echo 了,请不要再加 echo 在前面。 110 | 111 | 好吧,打开你的微信客户端,向你的公众号发送任意一条消息,你应该会收到回复:`您好!欢迎使用 EasyWeChat!`。 112 | 113 | > {warning} 没有收到回复?看到了“你的公众号暂时无法提供服务” ?, 好,那检查一下你的日志吧,日志在哪儿?我们的配置里写了日志路径了(`__DIR__.'/wechat.log'`)。 没有这个文件?看看权限哦。 114 | 115 | 一个基本的服务端验证就完成了。 116 | 117 | ## 总结 118 | 119 | 1. 所有的应用服务都通过主入口 `EasyWeChat\Factory` 类来创建: 120 | 121 | ```php 122 | 123 | // 公众号 124 | $app = Factory::officialAccount($config); 125 | 126 | // 小程序 127 | $app = Factory::miniProgram($config); 128 | 129 | // 开放平台 130 | $app = Factory::openPlatform($config); 131 | 132 | // 企业微信 133 | $app = Factory::work($config); 134 | 135 | // 企业微信开放平台 136 | $app = Factory::openWork($config); 137 | 138 | // 微信支付 139 | $app = Factory::payment($config); 140 | 141 | ``` 142 | 143 | ## 最后 144 | 145 | 希望你在使用本 SDK 的时候如果你发现 SDK 的不足,欢迎提交 PR 或者给我[提建议 & 报告问题](https://github.com/overtrue/wechat/issues)。 146 | -------------------------------------------------------------------------------- /official-account/configuration.md: -------------------------------------------------------------------------------- 1 | # 配置 2 | 3 | 常用的配置参数会比较少,因为除非你有特别的定制,否则基本上默认值就可以了: 4 | 5 | ```php 6 | use EasyWeChat\Factory; 7 | 8 | $config = [ 9 | 'app_id' => 'wx3cf0f39249eb0exx', 10 | 'secret' => 'f1c242f4f28f735d4687abb469072axx', 11 | 12 | // 指定 API 调用返回结果的类型:array(default)/collection/object/raw/自定义类名 13 | 'response_type' => 'array', 14 | 15 | //... 16 | ]; 17 | 18 | $app = Factory::officialAccount($config); 19 | ``` 20 | 21 | 下面是一个完整的配置样例: 22 | 23 | > 不建议你在配置的时候弄这么多,用到啥就配置啥才是最好的,因为大部分用默认值即可。 24 | 25 | ```php 26 | 'your-app-id', // AppID 33 | 'secret' => 'your-app-secret', // AppSecret 34 | 'token' => 'your-token', // Token 35 | 'aes_key' => '', // EncodingAESKey,兼容与安全模式下请一定要填写!!! 36 | 37 | /** 38 | * 指定 API 调用返回结果的类型:array(default)/collection/object/raw/自定义类名 39 | * 使用自定义类名时,构造函数将会接收一个 `EasyWeChat\Kernel\Http\Response` 实例 40 | */ 41 | 'response_type' => 'array', 42 | 43 | /** 44 | * 日志配置 45 | * 46 | * level: 日志级别, 可选为: 47 | * debug/info/notice/warning/error/critical/alert/emergency 48 | * path:日志文件位置(绝对路径!!!),要求可写权限 49 | */ 50 | 'log' => [ 51 | 'default' => 'dev', // 默认使用的 channel,生产环境可以改为下面的 prod 52 | 'channels' => [ 53 | // 测试环境 54 | 'dev' => [ 55 | 'driver' => 'single', 56 | 'path' => '/tmp/easywechat.log', 57 | 'level' => 'debug', 58 | ], 59 | // 生产环境 60 | 'prod' => [ 61 | 'driver' => 'daily', 62 | 'path' => '/tmp/easywechat.log', 63 | 'level' => 'info', 64 | ], 65 | ], 66 | ], 67 | 68 | /** 69 | * 接口请求相关配置,超时时间等,具体可用参数请参考: 70 | * http://docs.guzzlephp.org/en/stable/request-config.html 71 | * 72 | * - retries: 重试次数,默认 1,指定当 http 请求失败时重试的次数。 73 | * - retry_delay: 重试延迟间隔(单位:ms),默认 500 74 | * - log_template: 指定 HTTP 日志模板,请参考:https://github.com/guzzle/guzzle/blob/master/src/MessageFormatter.php 75 | */ 76 | 'http' => [ 77 | 'max_retries' => 1, 78 | 'retry_delay' => 500, 79 | 'timeout' => 5.0, 80 | // 'base_uri' => 'https://api.weixin.qq.com/', // 如果你在国外想要覆盖默认的 url 的时候才使用,根据不同的模块配置不同的 uri 81 | ], 82 | 83 | /** 84 | * OAuth 配置 85 | * 86 | * scopes:公众平台(snsapi_userinfo / snsapi_base),开放平台:snsapi_login 87 | * callback:OAuth授权完成后的回调页地址 88 | */ 89 | 'oauth' => [ 90 | 'scopes' => ['snsapi_userinfo'], 91 | 'callback' => '/examples/oauth_callback.php', 92 | ], 93 | ]; 94 | ``` 95 | 96 | > :heart: 安全模式下请一定要填写 `aes_key` 97 | 98 | ## 日志配置 99 | 100 | 你可以配置多个日志的 channel,每个 channel 里的 `driver` 对应不同的日志驱动,内置可用的 `driver` 如下表: 101 | 102 | 名称 | 描述 103 | ------------- | ------------- 104 | `stack` | 复合型,可以包含下面多种驱动的混合模式 105 | `single` | 基于 `StreamHandler` 的单一文件日志,参数有 `path`,`level` 106 | `daily` | 基于 `RotatingFileHandler` 按日期生成日志文件,参数有 `path`,`level`,`days`(默认 7 天) 107 | `slack` | 基于 `SlackWebhookHandler` 的 Slack 组件,参数请参考源码:[LogManager.php](https://github.com/overtrue/wechat/blob/master/src/Kernel/Log/LogManager.php#L247) 108 | `syslog` | 基于 `SyslogHandler` Monolog 驱动,参数有 `facility` 默认为 `LOG_USER`,`level` 109 | `errorlog` | 记录日志到系统错误日志,基于 `ErrorLogHandler`,参数有 `type`,默认为 `ErrorLogHandler::OPERATING_SYSTEM` 110 | 111 | ### 自定义日志驱动 112 | 113 | 由于日志使用的是 [Monolog](https://github.com/Seldaek/monolog),所以,除了默认的文件式日志外,你可以自定义日志处理器: 114 | 115 | ```php 116 | use Monolog\Logger; 117 | use Monolog\Handler\RotatingFileHandler; 118 | 119 | 120 | // 注册自定义日志 121 | $app->logger->extend('mylog', function($app, $config){ 122 | return new Logger($this->parseChannel($config), [ 123 | $this->prepareHandler(new RotatingFileHandler( 124 | $config['path'], $config['days'], $this->level($config) 125 | )), 126 | ]); 127 | }); 128 | ``` 129 | 130 | > {info} 在你自定义的闭包函数中,可以使用 `EasyWeChat\Kernel\LogLogManager` 中的方法,具体请查看 SDK 源代码。 131 | 132 | 配置文件中在 `driver` 部分即可使用你自定义的驱动了: 133 | 134 | ```php 135 | 'log' => [ 136 | 'default' => 'dev', // 默认使用的 channel,生产环境可以改为下面的 prod 137 | 'channels' => [ 138 | // 测试环境 139 | 'dev' => [ 140 | 'driver' => 'mylog', 141 | 'path' => '/tmp/easywechat.log', 142 | 'level' => 'debug', 143 | 'days' => 5, 144 | ], 145 | 146 | //... 147 | ], 148 | ], 149 | ``` 150 | 151 | -------------------------------------------------------------------------------- /index.md: -------------------------------------------------------------------------------- 1 | - ## 开始使用 2 | - [概述](/docs/{{version}}/overview) 3 | - [安装](/docs/{{version}}/installation) 4 | - [在框架中使用](/docs/{{version}}/integration) 5 | - [常见问题汇总](/docs/{{version}}/troubleshooting) 6 | - ## 公众号 7 | - [入门](/docs/{{version}}/official-account/index) 8 | - [快速开始](/docs/{{version}}/official-account/tutorial) 9 | - [配置](/docs/{{version}}/official-account/configuration) 10 | - [基础接口](/docs/{{version}}/official-account/base) 11 | - [服务端](/docs/{{version}}/official-account/server) 12 | - [消息](/docs/{{version}}/official-account/messages) 13 | - [多客服消息转发](/docs/{{version}}/official-account/message-transfer) 14 | - [消息群发](/docs/{{version}}/official-account/broadcasting) 15 | - [模板消息](/docs/{{version}}/official-account/template_message) 16 | - [用户](/docs/{{version}}/official-account/user) 17 | - [用户标签](/docs/{{version}}/official-account/user-tag) 18 | - [网页授权](/docs/{{version}}/official-account/oauth) 19 | - [JSSDK](/docs/{{version}}/basic-services/jssdk) 20 | - [临时素材](/docs/{{version}}/basic-services/media) 21 | - [二维码](/docs/{{version}}/basic-services/qrcode) 22 | - [短网址](/docs/{{version}}/basic-services/url) 23 | - [素材管理](/docs/{{version}}/official-account/material) 24 | - [菜单](/docs/{{version}}/official-account/menu) 25 | - [卡券](/docs/{{version}}/official-account/card) 26 | - [门店](/docs/{{version}}/official-account/poi) 27 | - [客服](/docs/{{version}}/official-account/customer_service) 28 | - [摇一摇周边](/docs/{{version}}/official-account/shake-around) 29 | - [数据统计与分析](/docs/{{version}}/official-account/data_cube) 30 | - [语义理解](/docs/{{version}}/official-account/semantic) 31 | - [自动回复](/docs/{{version}}/official-account/reply) 32 | - [评论数据管理](/docs/{{version}}/official-account/comment) 33 | - [返佣商品](/docs/{{version}}/official-account/goods) 34 | - ## 微信支付 35 | - [入门](/docs/{{version}}/payment/index) 36 | - [订单](/docs/{{version}}/payment/order) 37 | - [退款](/docs/{{version}}/payment/refund) 38 | - [账单](/docs/{{version}}/payment/bill) 39 | - [通知](/docs/{{version}}/payment/notify) 40 | - [红包](/docs/{{version}}/payment/redpack) 41 | - [扫码支付](/docs/{{version}}/payment/scan-pay) 42 | - [JSSDK](/docs/{{version}}/payment/jssdk) 43 | - [企业付款](/docs/{{version}}/payment/transfer) 44 | - [撤销订单](/docs/{{version}}/payment/reverse) 45 | - [安全工具](/docs/{{version}}/payment/security) 46 | - ## 小程序 47 | - [入门](/docs/{{version}}/mini-program/index) 48 | - [小程序码](/docs/{{version}}/mini-program/app_code) 49 | - [客服消息](/docs/{{version}}/mini-program/customer_service) 50 | - [数据统计与分析](/docs/{{version}}/mini-program/data_cube) 51 | - [微信登录](/docs/{{version}}/mini-program/auth) 52 | - [模板消息](/docs/{{version}}/mini-program/template_message) 53 | - [消息解密](/docs/{{version}}/mini-program/decrypt) 54 | - [内容安全](/docs/{{version}}/basic-services/content_security) 55 | - [物流助手](/docs/{{version}}/mini-program/express) 56 | - [生物认证](/docs/{{version}}/mini-program/soter) 57 | - [插件管理](/docs/{{version}}/mini-program/plugin) 58 | - [附近的小程序](/docs/{{version}}/mini-program/nearby_poi) 59 | - ## 开放平台 60 | - [入门](/docs/{{version}}/open-platform/index) 61 | - [服务端](/docs/{{version}}/open-platform/server) 62 | - [代授权](/docs/{{version}}/open-platform/authorizer-delegate) 63 | - ## 企业微信 64 | - [入门](/docs/{{version}}/wework/index) 65 | - [服务端](/docs/{{version}}/wework/server) 66 | - [应用管理](/docs/{{version}}/wework/agents) 67 | - [消息发送](/docs/{{version}}/wework/message) 68 | - [通讯录](/docs/{{version}}/wework/contacts) 69 | - [网页授权](/docs/{{version}}/wework/oauth) 70 | - [外部联系人管理](/docs/{{version}}/wework/external-contact) 71 | - [自定义菜单](/docs/{{version}}/wework/menu) 72 | - [素材管理](/docs/{{version}}/wework/media) 73 | - [OA](/docs/{{version}}/wework/oa) 74 | - [电子发票](/docs/{{version}}/wework/invoice) 75 | - [JSSDK](/docs/{{version}}/basic-services/jssdk) 76 | - [群机器人](/docs/{{version}}/wework/group-robot) 77 | - ## 企业微信开放平台 78 | - [入门](/docs/{{version}}/open-work/index) 79 | - [服务商接口](/docs/{{version}}/open-work/provider) 80 | - [服务商](/docs/{{version}}/open-work/server) 81 | - [第三方应用接口](/docs/{{version}}/open-work/service) 82 | - [企业相关](/docs/{{version}}/open-work/work) 83 | - ## 小微商户 84 | - [入门](/docs/{{version}}/micro-merchant/index) 85 | - [获取平台证书](/docs/{{version}}/micro-merchant/certficates) 86 | - [图片上传](/docs/{{version}}/micro-merchant/media) 87 | - [商户入驻](/docs/{{version}}/micro-merchant/submit-application) 88 | - [商户升级](/docs/{{version}}/micro-merchant/upgrade) 89 | - [商户信息修改](/docs/{{version}}/micro-merchant/material) 90 | - [提现相关](/docs/{{version}}/micro-merchant/withdraw) 91 | - [商户配置](/docs/{{version}}/micro-merchant/merchant-config) 92 | - ## 自定义 93 | - [Access Token](/docs/{{version}}/customize/access_token) 94 | - [缓存](/docs/{{version}}/customize/cache) 95 | - [模块替换](/docs/{{version}}/customize/replace-service) 96 | - ## 其他 97 | - [常见问题](/docs/{{version}}/troubleshooting) 98 | - [参与贡献](/docs/{{version}}/contributing) 99 | -------------------------------------------------------------------------------- /wework/external-contact.md: -------------------------------------------------------------------------------- 1 | # 外部联系人管理 2 | 3 | ## 获取实例 4 | 5 | ```php 6 | $config = [ 7 | 'corp_id' => 'xxxxxxxxxxxxxxxxx', 8 | 'secret' => 'xxxxxxxxxx', 9 | ... 10 | ]; 11 | 12 | $app = Factory::work($config); 13 | 14 | // 基础接口 15 | $app->external_contact; 16 | 17 | // 「联系我」 18 | $app->contact_way; 19 | 20 | // 消息管理 21 | $app->external_contact_message; 22 | 23 | // 数据统计 24 | $app->external_contact_statistics; 25 | ``` 26 | 27 | ## 基础接口 28 | 29 | ### 获取配置了客户联系功能的成员列表 30 | 31 | ```php 32 | $app->external_contact->getFollowUsers(); 33 | ``` 34 | 35 | ### 获取外部联系人列表 36 | 37 | ```php 38 | $userId = 'zhangsan'; 39 | 40 | $app->external_contact->list($userId); 41 | ``` 42 | 43 | ### 获取外部联系人详情 44 | 45 | ```php 46 | $externalUserId = 'woAJ2GCAAAXtWyujaWJHDDGi0mACH71w'; 47 | 48 | $app->external_contact->get($externalUserId); 49 | ``` 50 | 51 | 52 | ### 获取离职成员的客户列表 53 | 54 | ```php 55 | $pageId = 0; 56 | $pageSize = 1000; 57 | $app->external_contact->getUnassigned($pageId, $pageSize); 58 | ``` 59 | 60 | ### 离职成员的外部联系人再分配 61 | 62 | ```php 63 | $externalUserId = 'woAJ2GCAAAXtWyujaWJHDDGi0mACH71w'; 64 | $handoverUserId = 'zhangsan'; 65 | $takeoverUserId = 'lisi'; 66 | 67 | $app->external_contact->transfer($externalUserId, $handoverUserId, $takeoverUserId); 68 | ``` 69 | 70 | 71 | ## 配置客户联系「联系我」方式 72 | 73 | > {warning} 注意: 74 | > 1. 通过API添加的「联系我」不会在管理端进行展示。 75 | > 2. 每个企业可通过API最多配置10万个「联系我」。 76 | > 3. 截止 2019-06-21 官方文档没有提供获取所有「联系我」列表的接口,请开发者注意自行保管处理 configId,避免无法溯源。 77 | 78 | ### 增加「联系我」方式 79 | 80 | ```php 81 | $type = 1; 82 | $scene = 1; 83 | $config = [ 84 | 'style' => 1, 85 | 'remark' => '渠道客户', 86 | 'skip_verify' => true, 87 | 'state' => 'teststate', 88 | 'user' => ['UserID1', 'UserID2', 'UserID3'], 89 | ]; 90 | 91 | $app->contact_way->create($type, $scene, $config); 92 | 93 | // { 94 | // "errcode": 0, 95 | // "errmsg": "ok", 96 | // "config_id":"42b34949e138eb6e027c123cba77fad7"   97 | // } 98 | ``` 99 | 100 | ### 获取「联系我」方式 101 | 102 | ```php 103 | $configId = '42b34949e138eb6e027c123cba77fad7'; 104 | 105 | $app->contact_way->get($configId); 106 | ``` 107 | 108 | ### 更新「联系我」方式 109 | 110 | ```php 111 | $configId = '42b34949e138eb6e027c123cba77fad7'; 112 | 113 | $config = [ 114 | 'style' => 1, 115 | 'remark' => '渠道客户2', 116 | 'skip_verify' => true, 117 | 'state' => 'teststate2', 118 | 'user' => ['UserID4', 'UserID5', 'UserID6'], 119 | ]; 120 | 121 | $app->contact_way->update($configId, $config); 122 | ``` 123 | 124 | ### 删除「联系我」方式 125 | 126 | ```php 127 | $configId = '42b34949e138eb6e027c123cba77fad7'; 128 | 129 | $app->contact_way->delete($configId); 130 | ``` 131 | 132 | ## 消息管理 133 | 134 | ### 添加企业群发消息模板 135 | 136 | ```php 137 | $msg = [ 138 | 'external_userid' => [ 139 | 'woAJ2GCAAAXtWyujaWJHDDGi0mACas1w', 140 | 'wmqfasd1e1927831291723123109r712', 141 | ], 142 | 'sender' => 'zhangsan', 143 | 'text' => [ 144 | 'content' => '文本消息内容', 145 | ], 146 | 'image' => [ 147 | 'media_id' => 'MEDIA_ID', 148 | ], 149 | 'link' => [ 150 | 'title' => '消息标题', 151 | 'picurl' => 'https://example.pic.com/path', 152 | 'desc' => '消息描述', 153 | 'url' => 'https://example.link.com/path', 154 | ], 155 | 'miniprogram' => [ 156 | 'title' => '消息标题', 157 | 'pic_media_id' => 'MEDIA_ID', 158 | 'appid' => 'wx8bd80126147df384', 159 | 'page' => '/path/index', 160 | ], 161 | ]; 162 | 163 | $app->external_contact_message->submit($msg); 164 | 165 | // { 166 | // "errcode": 0, 167 | // "errmsg": "ok", 168 | // "fail_list":["wmqfasd1e19278asdasdasd"], 169 | // "msgid":"msgGCAAAXtWyujaWJHDDGi0mACas1w" 170 | // } 171 | ``` 172 | 173 | ### 获取企业群发消息发送结果 174 | 175 | ```php 176 | $msgId = 'msgGCAAAXtWyujaWJHDDGi0mACas1w'; 177 | 178 | $app->external_contact_message->get($msgId); 179 | ``` 180 | 181 | ### 发送新客户欢迎语 182 | 183 | ```php 184 | $welcomeCode = 'WELCOMECODE'; 185 | 186 | $msg = [ 187 | 'text' => [ 188 | 'content' => '文本消息内容', 189 | ], 190 | 'image' => [ 191 | 'media_id' => 'MEDIA_ID', 192 | ], 193 | 'link' => [ 194 | 'title' => '消息标题', 195 | 'picurl' => 'https://example.pic.com/path', 196 | 'desc' => '消息描述', 197 | 'url' => 'https://example.link.com/path', 198 | ], 199 | 'miniprogram' => [ 200 | 'title' => '消息标题', 201 | 'pic_media_id' => 'MEDIA_ID', 202 | 'appid' => 'wx8bd80126147df384', 203 | 'page' => '/path/index', 204 | ], 205 | ]; 206 | 207 | $app->external_contact_message->sendWelcome($welcomeCode, $msg); 208 | ``` 209 | 210 | 211 | ## 数据统计 212 | 213 | ### 获取员工行为数据 214 | 215 | ```php 216 | $userIds = [ 217 | 'zhangsan', 218 | 'lisi' 219 | ]; 220 | 221 | $from = 1536508800; 222 | $to = 1536940800; 223 | 224 | $app->external_contact_statistics->userBehavior($userIds, $from, $to); 225 | ``` 226 | 227 | 228 | -------------------------------------------------------------------------------- /official-account/material.md: -------------------------------------------------------------------------------- 1 | # 素材管理 2 | 3 | 4 | 在微信里的图片,音乐,视频等等都需要先上传到微信服务器作为素材才可以在消息中使用。 5 | 6 | ### 上传图片 7 | 8 | > {warning} 注意:微信图片上传服务有敏感检测系统,图片内容如果含有敏感内容,如色情,商品推广,虚假信息等,上传可能失败。 9 | 10 | ```php 11 | $result = $app->material->uploadImage("/path/to/your/image.jpg"); 12 | // { 13 | // "media_id":MEDIA_ID, 14 | // "url":URL 15 | // } 16 | ``` 17 | 18 | > `url` 只有上传图片素材有返回值。 19 | 20 | ### 上传语音 21 | 22 | 语音 **大小不超过 5M**,**长度不超过 60 秒**,支持 `mp3/wma/wav/amr` 格式。 23 | 24 | ```php 25 | $result = $app->material->uploadVoice("/path/to/your/voice.mp3"); 26 | // { 27 | // "media_id":MEDIA_ID, 28 | // } 29 | ``` 30 | 31 | ### 上传视频 32 | 33 | ```php 34 | $result = $app->material->uploadVideo("/path/to/your/video.mp4", "视频标题", "视频描述"); 35 | // { 36 | // "media_id":MEDIA_ID, 37 | // } 38 | ``` 39 | 40 | ### 上传缩略图 41 | 42 | 用于视频封面或者音乐封面。 43 | 44 | ```php 45 | $result = $app->material->uploadThumb("/path/to/your/thumb.jpg"); 46 | // { 47 | // "media_id":MEDIA_ID, 48 | // } 49 | ``` 50 | 51 | ### 上传图文消息 52 | 53 | ```php 54 | use EasyWeChat\Kernel\Messages\Article; 55 | 56 | // 上传单篇图文 57 | $article = new Article([ 58 | 'title' => 'xxx', 59 | 'thumb_media_id' => $mediaId, 60 | //... 61 | ]); 62 | $app->material->uploadArticle($article); 63 | 64 | // 或者多篇图文 65 | $app->material->uploadArticle([$article, $article2, ...]); 66 | ``` 67 | 68 | ### 修改图文消息 69 | 70 | 有三个参数: 71 | 72 | > - `$mediaId` 要更新的文章的 `mediaId` 73 | > - `$article` 文章内容,`Article` 实例或者 全字段数组 74 | > - `$index` 要更新的文章在图文消息中的位置(多图文消息时,此字段才有意义,单图片忽略此参数),第一篇为 0; 75 | 76 | ```php 77 | $result = $app->material->updateArticle($mediaId, new Article(...)); 78 | 79 | // or 80 | 81 | $result = $app->material->updateArticle($mediaId, [ 82 | 'title' => 'EasyWeChat 4.0 发布了!', 83 | 'thumb_media_id' => 'qQFxUQGO21Li4YrSn3MhnrqtRp9Zi3cbM9uBsepvDmE', // 封面图片 mediaId 84 | 'author' => 'overtrue', // 作者 85 | 'show_cover' => 1, // 是否在文章内容显示封面图片 86 | 'digest' => '这里是文章摘要', 87 | 'content' => '这里是文章内容,你可以放很长的内容', 88 | 'source_url' => 'https://www.easywechat.com', 89 | ]); 90 | 91 | // 指定更新多图文中的第 2 篇 92 | $result = $app->material->updateArticle($mediaId, new Article(...), 1); // 第 2 篇 93 | ``` 94 | 95 | 96 | ### 上传图文消息图片 97 | 98 | 返回值中 url 就是上传图片的 URL,可用于后续群发中,放置到图文消息中。 99 | 100 | ```php 101 | $result = $app->material->uploadArticleImage($path); 102 | //{ 103 | // "url": "http://mmbiz.qpic.cn/mmbiz/gLO17UPS6FS2xsypf378iaNhWacZ1G1UplZYWEYfwvuU6Ont96b1roYsCNFwaRrSaKTPCUdBK9DgEHicsKwWCBRQ/0" 104 | //} 105 | ``` 106 | 107 | ### 获取永久素材 108 | 109 | ```php 110 | $resource = $app->material->get($mediaId); 111 | ``` 112 | 113 | 如果请求的素材为图文消息,则响应如下: 114 | 115 | ```json 116 | { 117 | "news_item": [ 118 | { 119 | "title":TITLE, 120 | "thumb_media_id"::THUMB_MEDIA_ID, 121 | "show_cover_pic":SHOW_COVER_PIC(0/1), 122 | "author":AUTHOR, 123 | "digest":DIGEST, 124 | "content":CONTENT, 125 | "url":URL, 126 | "content_source_url":CONTENT_SOURCE_URL 127 | }, 128 | //多图文消息有多篇文章 129 | ] 130 | } 131 | ``` 132 | 133 | 如果返回的是视频消息素材,则内容如下: 134 | 135 | ```json 136 | { 137 | "title":TITLE, 138 | "description":DESCRIPTION, 139 | "down_url":DOWN_URL, 140 | } 141 | ``` 142 | 143 | 其他类型的素材消息,则响应为 `EasyWeChat\Kernel\Http\StreamResponse` 实例,开发者可以自行保存为文件。例如 144 | 145 | ```php 146 | $stream = $app->material->get($mediaId); 147 | 148 | if ($stram instanceof \EasyWeChat\Kernel\Http\StreamResponse) { 149 | // 以内容 md5 为文件名 150 | $stream->save('保存目录'); 151 | 152 | // 自定义文件名,不需要带后缀 153 | $stream->saveAs('保存目录', '文件名'); 154 | } 155 | ``` 156 | 157 | ### 获取永久素材列表 158 | 159 | > - `$type` 素材的类型,图片(`image`)、视频(`video`)、语音 (`voice`)、图文(`news`) 160 | > - `$offset` 从全部素材的该偏移位置开始返回,可选,默认 `0`,0 表示从第一个素材 返回 161 | > - `$count` 返回素材的数量,可选,默认 `20`, 取值在 1 到 20 之间 162 | 163 | ```php 164 | $app->material->list($type, $offset, $count); 165 | ``` 166 | 167 | 示例: 168 | 169 | ```php 170 | $list = $app->material->list('image', 0, 10); 171 | ``` 172 | 173 | 图片、语音、视频 等类型的返回如下 174 | 175 | ```json 176 | { 177 | "total_count": TOTAL_COUNT, 178 | "item_count": ITEM_COUNT, 179 | "item": [{ 180 | "media_id": MEDIA_ID, 181 | "name": NAME, 182 | "update_time": UPDATE_TIME, 183 | "url":URL 184 | }, 185 | //可能会有多个素材 186 | ] 187 | } 188 | ``` 189 | 190 | 永久图文消息素材列表的响应如下: 191 | 192 | ```json 193 | { 194 | "total_count": TOTAL_COUNT, 195 | "item_count": ITEM_COUNT, 196 | "item": [{ 197 | "media_id": MEDIA_ID, 198 | "content": { 199 | "news_item": [{ 200 | "title": TITLE, 201 | "thumb_media_id": THUMB_MEDIA_ID, 202 | "show_cover_pic": SHOW_COVER_PIC(0 / 1), 203 | "author": AUTHOR, 204 | "digest": DIGEST, 205 | "content": CONTENT, 206 | "url": URL, 207 | "content_source_url": CONTETN_SOURCE_URL 208 | }, 209 | //多图文消息会在此处有多篇文章 210 | ] 211 | }, 212 | "update_time": UPDATE_TIME 213 | }, 214 | //可能有多个图文消息item结构 215 | ] 216 | } 217 | ``` 218 | 219 | 220 | ### 获取素材计数 221 | 222 | ```php 223 | $stats = $app->material->stats(); 224 | 225 | // { 226 | // "voice_count":COUNT, 227 | // "video_count":COUNT, 228 | // "image_count":COUNT, 229 | // "news_count":COUNT 230 | // } 231 | ``` 232 | 233 | ### 删除永久素材; 234 | 235 | ```php 236 | $app->material->delete($mediaId); 237 | ``` 238 | 239 | ### 文章预览 240 | 241 | 文章预览请参阅 “消息群发” 章节。 242 | -------------------------------------------------------------------------------- /troubleshooting.md: -------------------------------------------------------------------------------- 1 | # 疑难解答 2 | 3 | 4 | 在微信公众平台开发的道路上,遍布着各种大大小小的坑,有的人掉坑里,几经折腾又爬出来了,然后拍拍屁股走人。然而坑还在那里,还会继续有后来人掉进去…… 5 | 6 | 这,是我们不愿看到的。 7 | 8 | 所以在这里,我们将陆续将微信开发中可能遇到的各种疑难问题进行汇总,并给出对应的解决办法。一般情况下,这些问题都可以对号入座,轻松地解决。但也不排除特殊情况,这时候你遇到的问题与文中某一个症状一致,但文中所给的解决方案并不凑效,这种情况下就需要发挥你自己的智慧,去……折腾了…… 9 | 10 | 我们期待这一版块为各位的开发带来便利,同时也希望各位本着开源、分享的精神对其进行补充和完善,将各种坑一一填小、填平,让微信开发变得不那么痛苦,甚至,变成一件快乐的事…… 11 | 12 | ## 时区不对 13 | 14 | 使用命令 `date` 可以在服务器上查看当前时间,如果发现时区不对则需要修改时区:[Setting The Correct Timezone In CentOS And Ubuntu Servers With NTP](https://www.liberiangeek.net/2013/02/setting-the-correct-timezone-in-centos-and-ubuntu-servers-with-ntp/) 15 | 16 | ## curl: (60) SSL certificate problem: unable to get local issuer certificate 17 | 18 | 这是 SSL 证书问题所致,在使用 SDK 调用微信支付等相关的操作时可能会遇到报 “SSL certificate problem: unable to get local issuer certificate” 的错误。 19 | 20 | 微信公众平台提供的文档中建议对部分较敏感的操作接口使用 https 协议进行访问,例如微信支付和红包等接口中涉及到操作商户资金的一些操作。 21 | wechat SDK 遵循了官方建议,所以在调用这些接口时,除了按照官方文档设置操作证书文件外,还需要保证服务器正确安装了 CA 证书。 22 | 23 | 1. 下载 CA 证书 24 | 25 | 你可以从 http://curl.haxx.se/ca/cacert.pem 下载 或者 使用[微信官方提供的证书](https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=4_3)中的 CA 证书 `rootca.pem` 也是同样的效果。 26 | 27 | 2. 在 `php.ini` 中配置 CA 证书 28 | 29 | 只需要将上面下载好的 CA 证书放置到您的服务器上某个位置,然后修改 `php.ini` 的 `curl.cainfo` 为该路径(**绝对路径!**),重启 `php-fpm` 服务即可。 30 | 31 | ```ini 32 | curl.cainfo = /path/to/downloaded/cacert.pem 33 | ``` 34 | > {warning} 注意证书文件**路径为绝对路径**!以自己实际情况为准。 35 | 36 | 其它修改 HTTP 类源文件的方式是不允许的。 37 | 38 | ## cURL error 56: SSLRead() return error -9806 39 | 40 | 目前在 OSX 下,发现使用 HomeBrew 装的 PHP 7.0 有这个问题,解决方案是重新 brew 安装 PHP: 41 | 42 | ```shell 43 | $ brew install homebrew/php/php70 --with-homebrew-openssl --with-homebrew-curl --without-snmp -vvv 44 | ``` 45 | 46 | 验证: 47 | 48 | ```shell 49 | $ php -i | grep 'OpenSSL support' 50 | 51 | OpenSSL support => enabled 52 | OpenSSL support => enabled 53 | ``` 54 | 55 | 56 | ## 支付失败!当前页面的 URL 未注册 57 | 58 | 这是由于微信支付授权目录未正确配置引起的。此时开发者应该登录微信公众平台,进入**【微信支付】->【开发设置】**进行设置。 59 | 60 | 1. 公众号可添加3个支付授权目录,满足不同应用使用同一个公众号进行支付的业务需求。 61 | 62 | 2. 正确的**【支付授权目录】**应以 `http://` 或 `https://` 开头,并以正斜杠 `/` 结尾,授权目录所包含的域名**必须经过 ICP 备案**。 63 | 64 | 3. 支付授权目录需**细化至二级或三级目录**。 65 | 66 | 4. 所有**实际调起微信支付请求的页面都必须要所配置的支付授权目录之下**。 67 | 68 | 5. 在开发过程中,也可以使用测试授权目录进行开发测试,此时还**应该将参与测试的个人微信号添加到测试白名单中**,否则将出现对应的错误提示…… 69 | 70 | > {warning} 配置前请先理解**页面**、**目录**、**URL **以及**域名**等几个基本概念,并对自己所使用的框架的路由机制有一个大致了解。这样你才会知道自己正在配置的参数是个啥玩意儿,有什么卵用…… :smile: 71 | 72 | 73 | ## redirect_url 参数错误 74 | 75 | 这是由于程序使用了**网页授权**而公众号没有正确配置**【网页授权域名】**所致。此时你需要登录[微信公众平台](https://mp.weixin.qq.com/),在【开发】->【接口权限】页面找到**网页授权获取用户基本信息**进行配置并保存。 76 | 77 | 1. 网页授权域名应该为通过 ICP 备案的有效域名,否则保存时无法通过安全监测。 78 | 79 | 2. 网页授权域名即程序完成授权获得授权 code 后跳转到的页面的域名,一般情况下为你的业务域名。 80 | 81 | 3. 网页授权域名配置成功后会立即生效。 82 | 83 | 4. 公众号的网页授权域名只可配置一个,请合理规划你的业务,否则你会发现……授权域名不够用哈。 84 | 85 | 86 | ## [JSAPI] config: invalid url domain 87 | 在使用 JS-SDK 进行开发时,每个页面都需要调用 wx.config() 方法配置 JSPAI 参数。如果没有正确配置 **JSAPI 安全域名**并且开启了调试模式,此时就报此错误。遇到这个问题时,开发者需要登录微信公众平台,进入【公众号设置】->【功能设置】页面,将项目所使用的域名添加至 **【JSAPI 安全域名】**列表中。 88 | 89 | 1. 一个公众号同时最多可绑定**三个**安全域名,并且这些域名必须为通过 **ICP 备案**的**一级或一级以上**的有效域名。 90 | 91 | 2. JSAPI 安全域名每个月**限修改三次**,修改任何一个都算,所以,请谨慎操作。 92 | 93 | 3. 如果需要使用 JSAPI 调起支付功能,则支付目录必须也在所配置的**安全域名之下**,并且需要将支付目录添加至**支付授权目录**。 94 | 95 | ## token验证失败、向公众号发送消息无任何反应 96 | 97 | 相信对接公众号一般是微信开发者进行开发过程中最先进行的工作,而在这看似简单的配置操作中,也可能会掉坑里。 98 | 最常见的两种情况就如下: 99 | 100 | 1. 确认你 “**启用**” 了开发模式, token 验证通过不代表启用,保存后也不代表启用。看到红色 “**停用**” 才真正的是启用了。 101 | 102 | 2. 配置好URL(服务器地址)以及Token(令牌)后,点击保存时提示**token验证失败**,出现这种情况的原因有多种,其中之一便是网络不稳定,所以**可尝试多次保存**,若始终无法通过再排查其它可能因素。 103 | 104 | 3. 配置保存成功之后,向公众号发送消息无任何反应,自己的消息处理程序也没有被调用的记录(无对应日志)。这种情况下如果你尝试**反复停用和启用服务器配置**,可能突然间惊奇地了现,问题莫名其妙的解决了。 105 | 106 | 4. 使用在线调试工具的消息接口,http://mp.weixin.qq.com/debug/, 只要返回绿色的“**请求成功**”,就代表你的代码没有问题,请**重复上面第3项**再测试。 107 | 108 | 5. **如果你在用什么本地开发工具,或者什么 ngrok 代理到本机这样的开发方式,那么失败就很正常了,微信服务器到你机器的网络延迟太大(还是用服务器开发吧)。** 109 | 110 | > {warning} 请开发者理解服务器 TOKEN 验证原理(官方文档有说明)并谨记服务器验证时使用 GET 方式访问,而公众平台向你的服务器发送消息/数据则使用 POST 方式,所以服务器验证成功之后,在某些启用了 CSRF 验证的框架里,接收消息时可能还会遇到 CSRF 相关的问题,请根据自己项目实际情况进行排查。 111 | > 另外有的朋友的 Laravel 里使用了 laravel-debugbar,这个组件的原理是在页面输出时在后面添加 HTML 来实现的,所以它会改变我们返回给微信的内容,此时要么卸载,要么禁用掉它。 112 | 113 | 114 | ## Maximum function nesting level of '100' reached, aborting! 115 | 116 | 在使用了 Xdebug 的环境下可能出现这个问题。这是由于 Xdebug 限制函数嵌套的最大层级数(默认为100),当嵌套次数达到该值便会触发 Xdebug 跳出嵌套并报此错误。 117 | 118 | 为避免这个问题,**可以将 Xdebug 的 max_nesting_level 参数适当设置大一些**,通常设置为200就可以了(当然可根据自己实际情况设置为更大的值)。 119 | 120 | 如下,修改 php.ini 配置文件后,重启 Apache 或 php-fpm 服务即可。 121 | 122 | ```ini 123 | xdebug.max_nesting_level=200 124 | ``` 125 | 126 | ## 扫码支付 获取商户订单信息超时或商户返回httpcode非200! 127 | 128 | 1.确定签名正确,使用SDK基本上不会出什么问题 129 | 2.微信调用扫码支付回调链接,使用POST方式,确定服务器回调方法是否取消csrf验证 130 | 131 | ## Request access_token fail:{"errcode":61023,"errmsg":"refresh_token is invalid hint: [zDNUIA07582974]"}! 132 | 133 | 在用户授权时会获得该authorizer_refresh_token刷新令牌,而当缓存或数据库存储的该authorizer_refresh_token刷新令牌丢失后,可能会出现该问题,微信文档中说明 134 | 135 | 1.接口调用凭据刷新令牌(在授权的公众号具备API权限时,才有此返回值),刷新令牌主要用于第三方平台获取和刷新已授权用户的access_token,只会在授权时刻提供,请妥善保存。 136 | 137 | 2.一旦丢失,只能让用户重新授权,才能再次拿到新的刷新令牌(https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1453779503&token=&lang=)。 138 | 139 | 3.为避免该问题,请将存储该刷新令牌的缓存有效期设置为0(永久存储),并尽量不要去将该缓存或数据库清空。 140 | 141 | 如下:以redis为例。 142 | 143 | ```php 144 | 'expire' => 0, 145 | ``` 146 | 147 | ## 替换Handler,让easywechat支持协程 148 | 149 | 在Swoft、IMI等基于Swoole的协程框架中使用easywechat时,不免会有一个问题,就是guzzle客户端内置的handler不支持协程的问题。 150 | 这里,提供一个办法主动替换容器内的 guzzle_handler. 151 | 152 | ```php 153 | $app = Factory::miniProgram($config); 154 | $app['guzzle_handler'] = CoroutineHandler::class; 155 | ``` 156 | 157 | 鉴于有些同学找不到可用的 `CoroutineHandler`,这里提供几个,供大家使用。 158 | 159 | - hyperf/guzzle 160 | - yurunsoft/guzzle-swoole 161 | - mix/guzzle-hook 162 | -------------------------------------------------------------------------------- /official-account/oauth.md: -------------------------------------------------------------------------------- 1 | # 网页授权 2 | 3 | ## 关于 OAuth2.0 4 | 5 | OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版。 6 | 7 | 8 | 9 | > 摘自:[RFC 6749](https://datatracker.ietf.org/doc/rfc6749/?include_text=1) 10 | 11 | 步骤解释: 12 | 13 | (A)用户打开客户端以后,客户端要求用户给予授权。 14 | (B)用户同意给予客户端授权。 15 | (C)客户端使用上一步获得的授权,向认证服务器申请令牌。 16 | (D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。 17 | (E)客户端使用令牌,向资源服务器申请获取资源。 18 | (F)资源服务器确认令牌无误,同意向客户端开放资源。 19 | 20 | 关于 OAuth 协议我们就简单了解到这里,如果还有不熟悉的同学,请 [Google 相关资料](https://www.google.com.hk/?gws_rd=ssl#safe=strict&q=OAuth2) 21 | 22 | ## 微信 OAuth 23 | 24 | 在微信里的 OAuth 其实有两种:[公众平台网页授权获取用户信息](http://mp.weixin.qq.com/wiki/9/01f711493b5a02f24b04365ac5d8fd95.html)、[开放平台网页登录](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN)。 25 | 26 | 它们的区别有两处,授权地址不同,`scope` 不同。 27 | 28 | > - **公众平台网页授权获取用户信息** 29 | **授权 URL**: `https://open.weixin.qq.com/connect/oauth2/authorize` 30 | **Scopes**: `snsapi_base` 与 `snsapi_userinfo` 31 | 32 | > - **开放平台网页登录** 33 | **授权 URL**: `https://open.weixin.qq.com/connect/qrconnect` 34 | **Scopes**: `snsapi_login` 35 | 36 | 他们的逻辑都一样: 37 | 38 | 1. 用户尝试访问一个我们的业务页面,例如: `/user/profile` 39 | 2. 如果用户已经登录,则正常显示该页面 40 | 2. 系统检查当前访问的用户并未登录(从 session 或者其它方式检查),则跳转到**跳转到微信授权服务器**(上面的两种中一种**授权 URL** ),并告知微信授权服务器我的**回调URL(redirect_uri=callback.php)**,此时用户看到蓝色的授权确认页面(`scope` 为 `snsapi_base` 时不显示) 41 | 4. 用户点击确定完成授权,浏览器跳转到**回调URL**: `callback.php` 并带上 `code`: `?code=CODE&state=STATE`。 42 | 5. 在 `callback.php` 中得到 `code` 后,通过 `code` 再次向微信服务器请求得到 **网页授权 access_token** 与 `openid` 43 | 6. 你可以选择拿 `openid` 去请求 API 得到用户信息(可选) 44 | 7. 将用户信息写入 SESSION。 45 | 8. 跳转到第 3 步写入的 `target_url` 页面(`/user/profile`)。 46 | 47 | > {warning} 看懵了?没事,使用 SDK,你不用管这么多。:smile: 48 | > 49 | > 注意,上面的第3步:redirect_uri=callback.php实际上我们会在 `callback.php` 后面还会带上授权目标页面 `user/profile`,所以完整的 `redirect_uri` 应该是下面的这样的PHP去拼出来:`'redirect_uri='.urlencode('callback.php?target=user/profile')` 50 | > 结果:redirect_uri=callback.php%3Ftarget%3Duser%2Fprofile 51 | 52 | ## 逻辑组成 53 | 54 | 从上面我们所描述的授权流程来看,我们至少有3个页面: 55 | 56 | 1. **业务页面**,也就是需要授权才能访问的页面。 57 | 2. **发起授权页**,此页面其实可以省略,可以做成一个中间件,全局检查未登录就发起授权。 58 | 3. **授权回调页**,接收用户授权后的状态,并获取用户信息,写入用户会话状态(SESSION)。 59 | 60 | ## 开始之前 61 | 62 | 在开始之前请一定要记住,先登录公众号后台,找到**边栏 “开发”** 模块下的 **“接口权限”**,点击 **“网页授权获取用户基本信息”** 后面的修改,添加你的网页授权域名。 63 | 64 | > 如果你的授权地址为:`http://www.abc.com/xxxxx`,那么请填写 `www.abc.com`,也就是说请填写与网址匹配的域名,前者如果填写 `abc.com` 是通过不了的。 65 | 66 | ## SDK 中 OAuth 模块的 API 67 | 68 | 在 SDK 中,我们使用名称为 `oauth` 的模块来完成授权服务,我们主要用到以下两个 API: 69 | 70 | ### 发起授权 71 | 72 | ```php 73 | $response = $app->oauth->scopes(['snsapi_userinfo']) 74 | ->redirect(); 75 | ``` 76 | 77 | 当你的应用是分布式架构且没有会话保持的情况下,你需要自行设置请求对象以实现会话共享。比如在 [Laravel](http://laravel.com) 框架中支持Session储存在Redis中,那么需要这样: 78 | 79 | ```php 80 | $response = $app->oauth->scopes(['snsapi_userinfo']) 81 | ->setRequest($request) 82 | ->redirect(); 83 | 84 | //回调后获取user时也要设置$request对象 85 | //$user = $app->oauth->setRequest($request)->user(); 86 | ``` 87 | 88 | 当然你也可以在发起授权的时候指定回调URL,比如设置回调URL为当前页面: 89 | 90 | ```php 91 | $response = $app->oauth->scopes(['snsapi_userinfo']) 92 | ->redirect($request->fullUrl()); 93 | ``` 94 | 95 | 它的返回值 `$response` 是一个 [Symfony\Component\HttpFoundation\RedirectResponse](http://api.symfony.com/3.0/Symfony/Component/HttpFoundation/RedirectResponse.html) 实例。 96 | 97 | 你可以选择在框架中做一些正确的响应,比如在 [Laravel](http://laravel.com) 框架中控制器方法是要求返回响应值的,那么你就直接: 98 | 99 | ```php 100 | return $response; 101 | ``` 102 | 103 | 在有的框架 (比如yii2) 中是直接 `echo` 或者 `$this->display()` 这种的时候,你就直接: 104 | 105 | ```php 106 | $response->send(); // Laravel 里请使用:return $response; 107 | ``` 108 | 109 | ### 获取已授权用户 110 | 111 | ```php 112 | $user = $app->oauth->user(); 113 | // $user 可以用的方法: 114 | // $user->getId(); // 对应微信的 OPENID 115 | // $user->getNickname(); // 对应微信的 nickname 116 | // $user->getName(); // 对应微信的 nickname 117 | // $user->getAvatar(); // 头像网址 118 | // $user->getOriginal(); // 原始API返回的结果 119 | // $user->getToken(); // access_token, 比如用于地址共享时使用 120 | ``` 121 | 122 | 返回的 `$user` 是 [Overtrue\Socialite\User](https://github.com/overtrue/socialite/blob/master/src/User.php) 对象,你可以从该对象拿到[更多的信息](https://github.com/overtrue/socialite#user-interface)。 123 | 124 | > {warning} 注意:`$user` 里没有 `openid`, `$user->id` 便是 `openid`. 125 | > 如果你想拿微信返回给你的原样的全部信息,请使用:$user->getOriginal(); 126 | 127 | 当 `scope` 为 `snsapi_base` 时 `$oauth->user();` 对象里只有 `id`,没有其它信息。 128 | 129 | ## 网页授权实例 130 | 131 | 我们这里来用原生 PHP 写法举个例子,`oauth_callback` 是我们的授权回调URL (未urlencode编码的URL), `user/profile` 是我们需要授权才能访问的页面,它的 PHP 代码如下: 132 | 133 | ```php 134 | // http://easywechat.org/user/profile 135 | [ 142 | 'scopes' => ['snsapi_userinfo'], 143 | 'callback' => '/oauth_callback', 144 | ], 145 | // .. 146 | ]; 147 | 148 | $app = Factory::officialAccount($config); 149 | $oauth = $app->oauth; 150 | 151 | // 未登录 152 | if (empty($_SESSION['wechat_user'])) { 153 | 154 | $_SESSION['target_url'] = 'user/profile'; 155 | 156 | return $oauth->redirect(); 157 | // 这里不一定是return,如果你的框架action不是返回内容的话你就得使用 158 | // $oauth->redirect()->send(); 159 | } 160 | 161 | // 已经登录过 162 | $user = $_SESSION['wechat_user']; 163 | 164 | // ... 165 | 166 | ``` 167 | 168 | 授权回调页: 169 | 170 | ```php 171 | // http://easywechat.org/oauth_callback 172 | oauth; 182 | 183 | // 获取 OAuth 授权结果用户信息 184 | $user = $oauth->user(); 185 | 186 | $_SESSION['wechat_user'] = $user->toArray(); 187 | 188 | $targetUrl = empty($_SESSION['target_url']) ? '/' : $_SESSION['target_url']; 189 | 190 | header('location:'. $targetUrl); // 跳转到 user/profile 191 | ``` 192 | 193 | 上面的例子呢都是基于 `$_SESSION` 来保持会话的,在微信客户端中,你可以结合 COOKIE 来存储,但是有效期平台不一样时间也不一样,好像 Android 的失效会快一些,不过基本也够用了。 194 | -------------------------------------------------------------------------------- /official-account/server.md: -------------------------------------------------------------------------------- 1 | # 服务端 2 | 3 | 我们在入门小教程一节以服务端为例讲解了一个基本的消息的处理,这里就不再讲服务器验证的流程了,请直接参考前面的入门实例即可。 4 | 5 | 服务端的作用呢,在整个微信开发中主要是负责 **[接收用户发送过来的消息](http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html)**,还有 **[用户触发的一系列事件](http://mp.weixin.qq.com/wiki/2/5baf56ce4947d35003b86a9805634b1e.html)**。 6 | 7 | 首先我们得厘清一下消息与事件的回复,当你收到用户消息后(消息由微信服务器推送到你的服务器),在你对消息进行一些处理后,不管是选择回复一个消息还是什么不都回给用户,你也应该给微信服务器一个 “答复”,如果是选择回复一条消息,就直接返回一个消息xml就好,如果选择不作任何回复,你也得回复一个空字符串或者字符串 `SUCCESS`(不然用户就会看到 `该公众号暂时无法提供服务`)。 8 | 9 | ## 基本使用 10 | 11 | 在 SDK 中使用 `$app->server->push(callable $callback)` 来设置消息处理器: 12 | 13 | ```php 14 | $app->server->push(function ($message) { 15 | // $message['FromUserName'] // 用户的 openid 16 | // $message['MsgType'] // 消息类型:event, text.... 17 | return "您好!欢迎使用 EasyWeChat"; 18 | }); 19 | 20 | // 在 laravel 中: 21 | $response = $app->server->serve(); 22 | 23 | // $response 为 `Symfony\Component\HttpFoundation\Response` 实例 24 | // 对于需要直接输出响应的框架,或者原生 PHP 环境下 25 | $response->send(); 26 | 27 | // 而 laravel 中直接返回即可: 28 | 29 | return $response; 30 | ``` 31 | 32 | 这里我们使用 `push` 传入了一个 **闭包([Closure](http://php.net/manual/en/class.closure.php))**,该闭包接收一个参数 `$message` 为消息对象(类型取决于你的配置中 `response_type`),你可以在全局消息处理器中对消息类型进行筛选: 33 | 34 | ```php 35 | $app->server->push(function ($message) { 36 | switch ($message['MsgType']) { 37 | case 'event': 38 | return '收到事件消息'; 39 | break; 40 | case 'text': 41 | return '收到文字消息'; 42 | break; 43 | case 'image': 44 | return '收到图片消息'; 45 | break; 46 | case 'voice': 47 | return '收到语音消息'; 48 | break; 49 | case 'video': 50 | return '收到视频消息'; 51 | break; 52 | case 'location': 53 | return '收到坐标消息'; 54 | break; 55 | case 'link': 56 | return '收到链接消息'; 57 | break; 58 | case 'file': 59 |            return '收到文件消息'; 60 | // ... 其它消息 61 | default: 62 | return '收到其它消息'; 63 | break; 64 | } 65 | 66 | // ... 67 | }); 68 | ``` 69 | 70 | 当然,因为这里 `push` 接收一个 [`callable`](http://php.net/manual/zh/language.types.callable.php) 的参数,所以你不一定要传入一个 Closure 闭包,你可以选择传入一个函数名,一个 `[$class, $method]` 或者 `Foo::bar` 这样的类型。 71 | 72 | 某些情况,我们需要直接使用 `$message` 参数,那么怎么在 `push` 的闭包外调用呢? 73 | 74 | ```php 75 | $message = $server->getMessage(); 76 | ``` 77 | > {warning} 注意:`$message` 的类型取决于你的配置中 `response_type` 78 | 79 | ## 注册多个消息处理器 80 | 81 | 有时候你可能需要对消息记日志,或者一系列的自定义操作,你可以注册多个 handler: 82 | 83 | ```php 84 | $app->server->push(MessageLogHandler::class); 85 | $app->server->push(MessageReplyHandler::class); 86 | $app->server->push(OtherHandler::class); 87 | $app->server->push(...); 88 | ``` 89 | 90 | > {warning} 注意: 91 | 1. 最后一个非空返回值将作为最终应答给用户的消息内容,如果中间某一个 handler 返回值 false, 则将终止整个调用链,不会调用后续的 handlers。 92 | 2. 传入的自定义 Handler 类需要实现 `\EasyWeChat\Kernel\Contracts\EventHandlerInterface`。 93 | 94 | ## 注册指定消息类型的消息处理器 95 | 96 | 我们想对特定类型的消息应用不同的处理器,可以在第二个参数传入类型筛选: 97 | 98 | > 注意,第二个参数必须是 `\EasyWeChat\Kernel\Messages\Message` 类的常量。 99 | 100 | ```php 101 | use EasyWeChat\Kernel\Messages\Message; 102 | 103 | $app->server->push(ImageMessageHandler::class, Message::IMAGE); // 图片消息 104 | $app->server->push(TextMessageHandler::class, Message::TEXT); // 文本消息 105 | 106 | // 同时处理多种类型的处理器 107 | $app->server->push(MediaMessageHandler::class, Message::VOICE|Message::VIDEO|Message::SHORT_VIDEO); // 当消息为 三种中任意一种都可触发 108 | ``` 109 | 110 | ## 请求消息的属性 111 | 112 | 当你接收到用户发来的消息时,可能会提取消息中的相关属性,参考: 113 | 114 | 请求消息基本属性(以下所有消息都有的基本属性): 115 | 116 | >> - `ToUserName` 接收方帐号(该公众号 ID) 117 | >> - `FromUserName` 发送方帐号(OpenID, 代表用户的唯一标识) 118 | >> - `CreateTime` 消息创建时间(时间戳) 119 | >> - `MsgId` 消息 ID(64位整型) 120 | 121 | ### 文本: 122 | 123 | > - `MsgType` text 124 | > - `Content` 文本消息内容 125 | 126 | ### 图片: 127 | 128 | > - `MsgType` image 129 | > - `MediaId` 图片消息媒体id,可以调用多媒体文件下载接口拉取数据。 130 | > - `PicUrl` 图片链接 131 | 132 | ### 语音: 133 | 134 | > - `MsgType` voice 135 | > - `MediaId` 语音消息媒体id,可以调用多媒体文件下载接口拉取数据。 136 | > - `Format` 语音格式,如 amr,speex 等 137 | > - `Recognition` * 开通语音识别后才有 138 | 139 | > {warning} 请注意,开通语音识别后,用户每次发送语音给公众号时,微信会在推送的语音消息XML数据包中,增加一个 `Recongnition` 字段 140 | 141 | ### 视频: 142 | 143 | > - `MsgType` video 144 | > - `MediaId` 视频消息媒体id,可以调用多媒体文件下载接口拉取数据。 145 | > - `ThumbMediaId` 视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。 146 | 147 | ### 小视频: 148 | 149 | > - `MsgType` shortvideo 150 | > - `MediaId` 视频消息媒体id,可以调用多媒体文件下载接口拉取数据。 151 | > - `ThumbMediaId` 视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。 152 | 153 | ### 事件: 154 | 155 | > - `MsgType` event 156 | > - `Event` 事件类型 (如:subscribe(订阅)、unsubscribe(取消订阅) ..., CLICK 等) 157 | 158 | #### 扫描带参数二维码事件 159 | > - `EventKey` 事件KEY值,比如:qrscene_123123,qrscene_为前缀,后面为二维码的参数值 160 | > - `Ticket` 二维码的 ticket,可用来换取二维码图片 161 | 162 | #### 上报地理位置事件 163 | > - `Latitude` 23.137466 地理位置纬度 164 | > - `Longitude` 113.352425 地理位置经度 165 | > - `Precision` 119.385040 地理位置精度 166 | 167 | #### 自定义菜单事件 168 | > - `EventKey` 事件KEY值,与自定义菜单接口中KEY值对应,如:CUSTOM_KEY_001, www.qq.com 169 | 170 | ### 地理位置: 171 | 172 | > - `MsgType` location 173 | > - `Location_X` 地理位置纬度 174 | > - `Location_Y` 地理位置经度 175 | > - `Scale` 地图缩放大小 176 | > - `Label` 地理位置信息 177 | 178 | ### 链接: 179 | 180 | > - `MsgType` link 181 | > - `Title` 消息标题 182 | > - `Description` 消息描述 183 | > - `Url` 消息链接 184 | 185 | ### 文件: 186 | 187 | `MsgType`      file 188 | `Title`        文件名 189 | `Description` 文件描述,可能为null 190 | `FileKey`      文件KEY 191 | `FileMd5`      文件MD5值 192 | `FileTotalLen` 文件大小,单位字节 193 | 194 | ## 回复消息 195 | 196 | 回复的消息可以为 `null`,此时 SDK 会返回给微信一个 "SUCCESS",你也可以回复一个普通字符串,比如:`欢迎关注 overtrue.`,此时 SDK 会对它进行一个封装,产生一个 [`EasyWeChat\Kernel\Messages\Text`](https://github.com/EasyWeChat/message/blob/master/src/Kernel/Messages/Text.php) 类型的消息并在最后的 `$app->server->serve();` 时生成对应的消息 XML 格式。 197 | 198 | 如果你想返回一个自己手动拼的原生 XML 格式消息,请返回一个 [`EasyWeChat\Kernel\Messages\Raw`](https://github.com/EasyWeChat/message/blob/master/src/Kernel/Messages/Raw.php) 实例即可。 199 | 200 | ## 消息转发给客服系统 201 | 202 | 参见:[多客服消息转发](message-transfer) 203 | 204 | 关于消息的使用,请参考 [`消息`](messages) 章节。 205 | -------------------------------------------------------------------------------- /official-account/broadcasting.md: -------------------------------------------------------------------------------- 1 | # 群发 2 | 3 | 微信的群发消息接口有各种乱七八糟的注意事项及限制,具体请阅读微信官方文档。 4 | 5 | ## 发送消息 6 | 7 | 以下所有方法均有第二个参数 `$to` 用于指定接收对象: 8 | 9 | > - 当 `$to` 为整型时为标签 id 10 | > - 当 `$to` 为数组时为用户的 openid 列表(至少两个用户的 openid) 11 | > - 当 `$to` 为 `null` 时表示全部用户 12 | 13 | ```php 14 | $app->broadcasting->sendMessage(Message $message, array | int $to = null); 15 | ``` 16 | 17 | 下面的别名方法 `sendXXX` 都是基于上面 `sendMessage` 方法的封装。 18 | 19 | ### 文本消息 20 | 21 | ```php 22 | $app->broadcasting->sendText("大家好!欢迎使用 EasyWeChat。"); 23 | 24 | // 指定目标用户 25 | // 至少两个用户的 openid,必须是数组。 26 | $app->broadcasting->sendText("大家好!欢迎使用 EasyWeChat。", [$openid1, $openid2]); 27 | 28 | // 指定标签组用户 29 | $app->broadcasting->sendText("大家好!欢迎使用 EasyWeChat。", $tagId); // $tagId 必须是整型数字 30 | ``` 31 | 32 | ### 图文消息 33 | 34 | ```php 35 | $app->broadcasting->sendNews($mediaId); 36 | $app->broadcasting->sendNews($mediaId, [$openid1, $openid2]); 37 | $app->broadcasting->sendNews($mediaId, $tagId); 38 | ``` 39 | 40 | ### 图片消息 41 | 42 | ```php 43 | $app->broadcasting->sendImage($mediaId); 44 | $app->broadcasting->sendImage($mediaId, [$openid1, $openid2]); 45 | $app->broadcasting->sendImage($mediaId, $tagId); 46 | ``` 47 | 48 | ### 语音消息 49 | 50 | ```php 51 | $app->broadcasting->sendVoice($mediaId); 52 | $app->broadcasting->sendVoice($mediaId, [$openid1, $openid2]); 53 | $app->broadcasting->sendVoice($mediaId, $tagId); 54 | ``` 55 | 56 | ### 视频消息 57 | 58 | 用于群发的视频消息,需要先创建消息对象, 59 | 60 | ```php 61 | // 1. 先上传视频素材用于群发: 62 | $video = '/path/to/video.mp4'; 63 | $videoMedia = $app->media->uploadVideoForBroadcasting($video, '视频标题', '视频描述'); 64 | 65 | // 结果如下: 66 | //{ 67 | // "type":"video", 68 | // "media_id":"IhdaAQXuvJtGzwwc0abfXnzeezfO0NgPK6AQYShD8RQYMTtfzbLdBIQkQziv2XJc", 69 | // "created_at":1398848981 70 | //} 71 | 72 | // 2. 使用上面得到的 media_id 群发视频消息 73 | $app->broadcasting->sendVideo($videoMedia['media_id']); 74 | ``` 75 | 76 | ### 卡券消息 77 | 78 | ```php 79 | $app->broadcasting->sendCard($cardId); 80 | $app->broadcasting->sendCard($cardId, [$openid1, $openid2]); 81 | $app->broadcasting->sendCard($cardId, $tagId); 82 | ``` 83 | 84 | ### 发送预览群发消息给指定的 `openId` 用户 85 | 86 | ```php 87 | $app->broadcasting->previewText($text, $openId); 88 | $app->broadcasting->previewNews($mediaId, $openId); 89 | $app->broadcasting->previewVoice($mediaId, $openId); 90 | $app->broadcasting->previewImage($mediaId, $openId); 91 | $app->broadcasting->previewVideo($message, $openId); 92 | $app->broadcasting->previewCard($cardId, $openId); 93 | ``` 94 | 95 | ### 发送预览群发消息给指定的微信号用户 96 | 97 | > $wxanme 是用户的微信号,比如:notovertrue 98 | 99 | ```php 100 | $app->broadcasting->previewTextByName($text, $wxname); 101 | $app->broadcasting->previewNewsByName($mediaId, $wxname); 102 | $app->broadcasting->previewVoiceByName($mediaId, $wxname); 103 | $app->broadcasting->previewImageByName($mediaId, $wxname); 104 | $app->broadcasting->previewVideoByName($message, $wxname); 105 | $app->broadcasting->previewCardByName($cardId, $wxname); 106 | ``` 107 | 108 | ### 删除群发消息 109 | 110 | ```php 111 | $app->broadcasting->delete($msgId); 112 | ``` 113 | 114 | ### 查询群发消息发送状态 115 | 116 | ```php 117 | $app->broadcasting->status($msgId); 118 | ``` 119 | ======= 120 | # 消息群发 121 | 122 | 微信的群发消息接口有各种乱七八糟的注意事项及限制,具体请阅读微信官方文档。 123 | 124 | ## 发送消息 125 | 126 | 以下所有方法均有第二个参数 `$to` 用于指定接收对象: 127 | 128 | - 当 `$to` 为整型时为标签 id 129 | - 当 `$to` 为数组时为用户的 openid 列表(至少两个用户的 openid) 130 | - 当 `$to` 为 `null` 时表示全部用户 131 | 132 | ```php 133 | $app->broadcasting->sendMessage(Message $message, array | int $to = null); 134 | ``` 135 | 136 | 下面的别名方法 `sendXXX` 都是基于上面 `sendMessage` 方法的封装。 137 | 138 | ### 文本消息 139 | 140 | ```php 141 | $app->broadcasting->sendText("大家好!欢迎使用 EasyWeChat。"); 142 | 143 | // 指定目标用户 144 | // 至少两个用户的 openid,必须是数组。 145 | $app->broadcasting->sendText("大家好!欢迎使用 EasyWeChat。", [$openid1, $openid2]); 146 | 147 | // 指定标签组用户 148 | $app->broadcasting->sendText("大家好!欢迎使用 EasyWeChat。", $tagId); // $tagId 必须是整型数字 149 | ``` 150 | 151 | ### 图文消息 152 | 153 | ```php 154 | $app->broadcasting->sendNews($mediaId); 155 | $app->broadcasting->sendNews($mediaId, [$openid1, $openid2]); 156 | $app->broadcasting->sendNews($mediaId, $tagId); 157 | ``` 158 | 159 | ### 图片消息 160 | 161 | ```php 162 | $app->broadcasting->sendImage($mediaId); 163 | $app->broadcasting->sendImage($mediaId, [$openid1, $openid2]); 164 | $app->broadcasting->sendImage($mediaId, $tagId); 165 | ``` 166 | 167 | ### 语音消息 168 | 169 | ```php 170 | $app->broadcasting->sendVoice($mediaId); 171 | $app->broadcasting->sendVoice($mediaId, [$openid1, $openid2]); 172 | $app->broadcasting->sendVoice($mediaId, $tagId); 173 | ``` 174 | 175 | ### 视频消息 176 | 177 | 用于群发的视频消息,需要先创建消息对象, 178 | 179 | ```php 180 | // 1. 先上传视频素材用于群发: 181 | $video = '/path/to/video.mp4'; 182 | $videoMedia = $app->media->uploadVideoForBroadcasting($video, '视频标题', '视频描述'); 183 | 184 | // 结果如下: 185 | //{ 186 | // "type":"video", 187 | // "media_id":"IhdaAQXuvJtGzwwc0abfXnzeezfO0NgPK6AQYShD8RQYMTtfzbLdBIQkQziv2XJc", 188 | // "created_at":1398848981 189 | //} 190 | 191 | // 2. 使用上面得到的 media_id 群发视频消息 192 | $app->broadcasting->sendVideo($videoMedia['media_id']); 193 | ``` 194 | 195 | ### 卡券消息 196 | 197 | ```php 198 | $app->broadcasting->sendCard($cardId); 199 | $app->broadcasting->sendCard($cardId, [$openid1, $openid2]); 200 | $app->broadcasting->sendCard($cardId, $tagId); 201 | ``` 202 | 203 | ### 发送预览群发消息给指定的 `openId` 用户 204 | 205 | ```php 206 | $app->broadcasting->previewText($text, $openId); 207 | $app->broadcasting->previewNews($mediaId, $openId); 208 | $app->broadcasting->previewVoice($mediaId, $openId); 209 | $app->broadcasting->previewImage($mediaId, $openId); 210 | $app->broadcasting->previewVideo($message, $openId); 211 | $app->broadcasting->previewCard($cardId, $openId); 212 | ``` 213 | 214 | ### 发送预览群发消息给指定的微信号用户 215 | 216 | > $wxanme 是用户的微信号,比如:notovertrue 217 | 218 | ```php 219 | $app->broadcasting->previewTextByName($text, $wxname); 220 | $app->broadcasting->previewNewsByName($mediaId, $wxname); 221 | $app->broadcasting->previewVoiceByName($mediaId, $wxname); 222 | $app->broadcasting->previewImageByName($mediaId, $wxname); 223 | $app->broadcasting->previewVideoByName($message, $wxname); 224 | $app->broadcasting->previewCardByName($cardId, $wxname); 225 | ``` 226 | 227 | ### 删除群发消息 228 | 229 | ```php 230 | $app->broadcasting->delete($msgId); 231 | ``` 232 | 233 | ### 查询群发消息发送状态 234 | 235 | ```php 236 | $app->broadcasting->status($msgId); 237 | ``` -------------------------------------------------------------------------------- /official-account/messages.md: -------------------------------------------------------------------------------- 1 | # 消息 2 | 3 | 我把微信的 API 里的所有“消息”都按类型抽象出来了,也就是说,你不用区分它是回复消息还是主动推送消息,免去了你去手动拼装微信的 XML 以及乱七八糟命名不统一的 JSON 了。 4 | 5 | 在阅读以下内容时请忽略是 **接收消息** 还是 **回复消息**,后面我会给你讲它们的区别。 6 | 7 | ## 消息类型 8 | 9 | 消息分为以下几种:`文本`、`图片`、`视频`、`声音`、`链接`、`坐标`、`图文`、`文章` 和一种特殊的 `原始消息`。 10 | 11 | 另外还有一种特殊的消息类型:**素材消息**,用于群发或者客服时发送已有素材用。 12 | 13 | > {warning} 注意:回复消息与客服消息里的图文类型为:**图文**,群发与素材中的图文为**文章** 14 | 15 | 所有的消息类都在 `EasyWeChat\Kernel\Messages` 这个命名空间下, 下面我们来分开讲解: 16 | 17 | ### 文本消息 18 | 19 | 属性列表: 20 | 21 | > - `content` 文本内容 22 | 23 | ```php 24 | use EasyWeChat\Kernel\Messages\Text; 25 | 26 | $text = new Text('您好!overtrue。'); 27 | 28 | // or 29 | $text = new Text(); 30 | $text->content = '您好!overtrue。'; 31 | 32 | // or 33 | $text = new Text(); 34 | $text->setAttribute('content', '您好!overtrue。'); 35 | ``` 36 | 37 | ### 图片消息 38 | 39 | 属性列表: 40 | 41 | ``` 42 | - media_id 媒体资源 ID 43 | ``` 44 | 45 | ```php 46 | 47 | use EasyWeChat\Kernel\Messages\Image; 48 | 49 | $image = new Image($mediaId); 50 | ``` 51 | 52 | 53 | ### 视频消息 54 | 55 | 属性列表: 56 | 57 | > - `title` 标题 58 | > - `description` 描述 59 | > - `media_id` 媒体资源 ID 60 | > - `thumb_media_id` 封面资源 ID 61 | 62 | ```php 63 | 64 | use EasyWeChat\Kernel\Messages\Video; 65 | 66 | $video = new Video($mediaId, [ 67 | 'title' => $title, 68 | 'description' => '...', 69 | ]); 70 | ``` 71 | 72 | ### 声音消息 73 | 74 | 属性列表: 75 | 76 | > - `media_id` 媒体资源 ID 77 | 78 | ```php 79 | use EasyWeChat\Kernel\Messages\Voice; 80 | 81 | $voice = new Voice($mediaId); 82 | ``` 83 | 84 | ### 链接消息 85 | 86 | > {warning} 微信目前不支持回复链接消息 87 | 88 | ### 坐标消息 89 | 90 | > {warning} 微信目前不支持回复坐标消息 91 | 92 | ### 图文消息 93 | 94 | 图文消息分为 `NewsItem` 与 `News`,`NewsItem` 为图文内容条目。 95 | 96 | > {warning} [10月12日起,被动回复消息与客服消息接口的图文消息类型中图文数目只能为一条](https://mp.weixin.qq.com/cgi-bin/announce?action=getannouncement&announce_id=115383153198yAvN&version=&lang=zh_CN&token=) 97 | 98 | `NewsItem` 属性: 99 | 100 | > - `title` 标题 101 | > - `description` 描述 102 | > - `image` 图片链接 103 | > - `url` 链接 URL 104 | 105 | ```php 106 | use EasyWeChat\Kernel\Messages\News; 107 | use EasyWeChat\Kernel\Messages\NewsItem; 108 | 109 | $items = [ 110 | new NewsItem([ 111 | 'title' => $title, 112 | 'description' => '...', 113 | 'url' => $url, 114 | 'image' => $image, 115 | // ... 116 | ]), 117 | ]; 118 | $news = new News($items); 119 | ``` 120 | 121 | ### 文章 122 | 123 | 属性列表: 124 | 125 | > - `title` 标题 126 | > - `author` 作者 127 | > - `content` 具体内容 128 | > - `thumb_media_id` 图文消息的封面图片素材id(必须是永久mediaID) 129 | > - `digest` 图文消息的摘要,仅有单图文消息才有摘要,多图文此处为空 130 | > - `source_url` 来源 URL 131 | > - `show_cover` 是否显示封面,0 为 false,即不显示,1 为 true,即显示 132 | 133 | ```php 134 | use EasyWeChat\Kernel\Messages\Article; 135 | 136 | $article = new Article([ 137 | 'title' => 'EasyWeChat', 138 | 'author' => 'overtrue', 139 | 'content' => 'EasyWeChat 是一个开源的微信 SDK,它... ...', 140 | // ... 141 | ]); 142 | 143 | // or 144 | $article = new Article(); 145 | $article->title = 'EasyWeChat'; 146 | $article->author = 'overtrue'; 147 | $article->content = '微信 SDK ...'; 148 | // ... 149 | ``` 150 | 151 | 152 | ### 素材消息 153 | 154 | 素材消息用于群发与客服消息时使用。 155 | > 素材消息不支持被动回复,如需被动回复素材消息,首先组装后,再 News 方法返回。 156 | 157 | 属性就一个:`media_id`。 158 | 159 | 在构造时有两个参数: 160 | 161 | > - `$type` 素材类型,目前只支持:`mpnews`、 `mpvideo`、`voice`、`image` 等。 162 | > - `$mediaId` 素材 ID,从接口查询或者上传后得到。 163 | 164 | 165 | ```php 166 | use EasyWeChat\Kernel\Messages\Media; 167 | 168 | $media = new Media($mediaId, 'mpnews'); 169 | ``` 170 | 171 | 以上呢,是所有微信支持的基本消息类型。 172 | 173 | > {info} 需要注意的是,你不需要关心微信的消息字段叫啥,因为这里我们使用了更标准的命名,然后最终在中间做了转换,所以你不需要关注。 174 | 175 | ### 原始消息 176 | 177 | 原始消息是一种特殊的消息,它的场景是:**你不想使用其它消息类型,你想自己手动拼消息**。比如,回复消息时,你想自己拼 XML,那么你就直接用它就可以了: 178 | 179 | ```php 180 | use EasyWeChat\Kernel\Messages\Raw; 181 | 182 | $message = new Raw(' 183 | 184 | 185 | 12345678 186 | 187 | 188 | 189 | 190 | '); 191 | ``` 192 | 193 | 比如,你要用于客服消息(客服消息是JSON结构): 194 | 195 | ```php 196 | use EasyWeChat\Kernel\Messages\Raw; 197 | 198 | $message = new Raw('{ 199 | "touser":"OPENID", 200 | "msgtype":"text", 201 | "text": 202 | { 203 | "content":"Hello World" 204 | } 205 | }'); 206 | ``` 207 | 208 | 总之,就是直接写微信接口要求的格式内容就好,此类型消息在 SDK 中不存在转换行为,所以请注意不要写错格式。 209 | 210 | ## 在 SDK 中使用消息 211 | 212 | ### 在服务端回复消息 213 | 214 | 在 [服务端](server) 一节中,我们讲了回复消息的写法: 215 | 216 | ```php 217 | // ... 前面部分省略 218 | $app->server->push(function ($message) { 219 | return "您好!欢迎关注我!"; 220 | }); 221 | 222 | $response = $server->serve(); 223 | ``` 224 | 225 | 上面 `return` 了一句普通的文本内容,这里只是为了方便大家,实际上最后会有一个隐式转换为 `Text` 类型的动作。 226 | 227 | 如果你要回复其它类型的消息,就需要返回一个具体的实例了,比如回复一个图片类型的消息: 228 | 229 | ```php 230 | use EasyWeChat\Kernel\Messages\Image; 231 | // ... 232 | $app->server->push(function ($message) { 233 | return new Image('media-id'); 234 | }); 235 | // ... 236 | ``` 237 | 238 | #### 回复多图文消息 239 | 240 | > {warning} [10月12日起,被动回复消息与客服消息接口的图文消息类型中图文数目只能为一条](https://mp.weixin.qq.com/cgi-bin/announce?action=getannouncement&announce_id=115383153198yAvN&version=&lang=zh_CN&token=) 241 | 242 | 多图文消息其实就是单图文消息的一个数组而已了: 243 | 244 | ```php 245 | use EasyWeChat\Kernel\Messages\News; 246 | use EasyWeChat\Kernel\Messages\NewsItem; 247 | 248 | // ... 249 | $app->server->push(function ($message) { 250 | $news = new NewsItem(...); 251 | return new News([$news]); 252 | }); 253 | // ... 254 | ``` 255 | 256 | 257 | ### 作为客服消息发送 258 | 259 | 在客服消息里的使用也一样,都是直接传入消息实例即可: 260 | 261 | ```php 262 | use EasyWeChat\Kernel\Messages\Text; 263 | 264 | $message = new Text('Hello world!'); 265 | 266 | $result = $app->customer_service->message($message)->to($openId)->send(); 267 | //... 268 | ``` 269 | 270 | #### 发送多图文消息 271 | 272 | > {warning} [10月12日起,被动回复消息与客服消息接口的图文消息类型中图文数目只能为一条](https://mp.weixin.qq.com/cgi-bin/announce?action=getannouncement&announce_id=115383153198yAvN&version=&lang=zh_CN&token=) 273 | 274 | 多图文消息其实就是单图文消息组成的一个 News 对象而已: 275 | 276 | ```php 277 | $news1 = new NewsItem(...); 278 | $news = new News([$news1]); 279 | 280 | $app->customer_service->message($news)->to($openId)->send(); 281 | ``` 282 | 283 | ### 群发消息 284 | 285 | 请参考:[群发消息](broadcasting) 286 | 287 | ## 消息转发给客服系统 288 | 289 | 参见:[多客服消息转发](message-transfer) 290 | -------------------------------------------------------------------------------- /official-account/card.md: -------------------------------------------------------------------------------- 1 | # 卡券 2 | - 3 | 4 | ## 获取实例 5 | 6 | ```php 7 | $card = $app->card; 8 | ``` 9 | 10 | 11 | ## 通用功能 12 | 13 | ### 获取卡券颜色 14 | 15 | ```php 16 | $card->colors(); 17 | ``` 18 | 19 | ### 卡券开放类目查询 20 | 21 | ```php 22 | $card->categories(); 23 | ``` 24 | 25 | 26 | ### 创建卡券 27 | 28 | 创建卡券接口是微信卡券的基础接口,用于创建一类新的卡券,获取card_id,创建成功并通过审核后,商家可以通过文档提供的其他接口将卡券下发给用户,每次成功领取,库存数量相应扣除。 29 | 30 | ```php 31 | $card->create($cardType = 'member_card', array $attributes); 32 | ``` 33 | 34 | > - `attributes` array 卡券信息 35 | 36 | 示例: 37 | 38 | ```php 39 | [ 45 | 'brand_name' => '微信餐厅', 46 | 'code_type' => 'CODE_TYPE_TEXT', 47 | 'title' => '132元双人火锅套餐', 48 | //... 49 | ], 50 | 'advanced_info' => [ 51 | 'use_condition' => [ 52 | 'accept_category' => '鞋类', 53 | 'reject_category' => '阿迪达斯', 54 | 'can_use_with_other_discount' => true, 55 | ], 56 | //... 57 | ], 58 | ]; 59 | 60 | $result = $card->create($cardType, $attributes); 61 | ``` 62 | 63 | ### 获取卡券详情 64 | 65 | ```php 66 | $cardInfo = $card->get($cardId); 67 | ``` 68 | 69 | 70 | ### 批量查询卡列表 71 | 72 | ```php 73 | $card->list($offset = 0, $count = 10, $statusList = 'CARD_STATUS_VERIFY_OK'); 74 | ``` 75 | 76 | > - `offset` int - 查询卡列表的起始偏移量,从0开始 77 | > - `count` int - 需要查询的卡片的数量 78 | > - `statusList` - 支持开发者拉出指定状态的卡券列表,详见 example 79 | 80 | 示例: 81 | 82 | ```php 83 | // CARD_STATUS_NOT_VERIFY, 待审核; 84 | // CARD_STATUS_VERIFY_FAIL, 审核失败; 85 | // CARD_STATUS_VERIFY_OK, 通过审核; 86 | // CARD_STATUS_USER_DELETE,卡券被商户删除; 87 | // CARD_STATUS_DISPATCH,在公众平台投放过的卡券; 88 | 89 | $result = $card->list($offset, $count, 'CARD_STATUS_NOT_VERIFY'); 90 | ``` 91 | 92 | 93 | ### 更改卡券信息接口 94 | 95 | 支持更新所有卡券类型的部分通用字段及特殊卡券中特定字段的信息。 96 | 97 | ```php 98 | $card->update($cardId, $type, $attributes = []); 99 | ``` 100 | 101 | > - `type` string - 卡券类型 102 | 103 | 示例: 104 | 105 | ```php 106 | $cardId = 'pdkJ9uCzKWebwgNjxosee0ZuO3Os'; 107 | 108 | $type = 'groupon'; 109 | 110 | $attributes = [ 111 | 'base_info' => [ 112 | 'logo_url' => 'http://mmbiz.qpic.cn/mmbiz/2aJY6aCPatSeibYAyy7yct9zJXL9WsNVL4JdkTbBr184gNWS6nibcA75Hia9CqxicsqjYiaw2xuxYZiaibkmORS2oovdg/0', 113 | 'center_title' => '顶部居中按钮', 114 | 'center_sub_title' => '按钮下方的wording', 115 | 'center_url' => 'http://www.easywechat.com', 116 | 'custom_url_name' => '立即使用', 117 | 'custom_url' => 'http://www.qq.com', 118 | 'custom_url_sub_title' => '6个汉字tips', 119 | 'promotion_url_name' => '更多优惠', 120 | 'promotion_url' => 'http://www.qq.com', 121 | ], 122 | //... 123 | ]; 124 | 125 | $result = $card->update($cardId, $type, $attributes); 126 | ``` 127 | 128 | ### 删除卡券 129 | 130 | ```php 131 | $card->delete($cardId); 132 | ``` 133 | 134 | ### 创建二维码 135 | 136 | 开发者可调用该接口生成一张卡券二维码供用户扫码后添加卡券到卡包。 137 | 138 | 自定义 Code 码的卡券调用接口时,POST 数据中需指定 code,非自定义 code 不需指定,指定 openid 同理。指定后的二维码只能被用户扫描领取一次。 139 | 140 | ```php 141 | $card->createQrCode($cards); 142 | ``` 143 | 144 | > - `cards` array - 卡券相关信息 145 | 146 | 示例: 147 | 148 | ```php 149 | // 领取单张卡券 150 | $cards = [ 151 | 'action_name' => 'QR_CARD', 152 | 'expire_seconds' => 1800, 153 | 'action_info' => [ 154 | 'card' => [ 155 | 'card_id' => 'pdkJ9uFS2WWCFfbbEfsAzrzizVyY', 156 | 'is_unique_code' => false, 157 | 'outer_id' => 1, 158 | ], 159 | ], 160 | ]; 161 | 162 | $result = $card->createQrCode($cards); 163 | ``` 164 | 165 | ```php 166 | // 领取多张卡券 167 | $cards = [ 168 | 'action_name' => 'QR_MULTIPLE_CARD', 169 | 'action_info' => [ 170 | 'multiple_card' => [ 171 | 'card_list' => [ 172 | ['card_id' => 'pdkJ9uFS2WWCFfbbEfsAzrzizVyY'], 173 | ], 174 | ], 175 | ], 176 | ]; 177 | 178 | $result = $card->createQrCode($cards); 179 | ``` 180 | 181 | 请求成功返回值示例: 182 | 183 | ```json 184 | { 185 | "errcode": 0, 186 | "errmsg": "ok", 187 | "ticket": "gQHB8DoAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL0JIV3lhX3psZmlvSDZmWGVMMTZvAAIEsNnKVQMEIAMAAA==",//获取ticket后需调用换取二维码接口获取二维码图片,详情见字段说明。 188 | "expire_seconds": 1800, 189 | "url": "http://weixin.qq.com/q/BHWya_zlfioH6fXeL16o ", 190 | "show_qrcode_url": "https://mp.weixin.qq.com/cgi-bin/showqrcode? ticket=gQH98DoAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL0czVzRlSWpsamlyM2plWTNKVktvAAIE6SfgVQMEgDPhAQ%3D%3D" 191 | } 192 | ``` 193 | 194 | 195 | ### ticket 换取二维码图片 196 | 197 | 获取二维码 ticket 后,开发者可用 ticket 换取二维码图片。 198 | 199 | ```php 200 | $card->getQrCode($ticket); 201 | ``` 202 | 203 | > - `ticket` string> - 获取的二维码 ticket,凭借此 ticket 可以在有效时间内换取二维码。 204 | 205 | 示例: 206 | 207 | ```php 208 | $ticket = 'gQFF8DoAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL01VTzN0T0hsS1BwUlBBYUszbVN5AAIEughxVwMEAKd2AA=='; 209 | $result = $card->getQrCode($ticket); 210 | ``` 211 | 212 | 213 | ### ticket 换取二维码链接 214 | 215 | ```php 216 | $card->getQrCodeUrl($ticket); 217 | ``` 218 | 219 | 示例: 220 | 221 | ```php 222 | $ticket = 'gQFF8DoAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL01VTzN0T0hsS1BwUlBBYUszbVN5AAIEughxVwMEAKd2AA=='; 223 | $card->getQrCodeUrl($ticket); 224 | ``` 225 | 226 | ### 创建货架接口 227 | 228 | 开发者需调用该接口创建货架链接,用于卡券投放。创建货架时需填写投放路径的场景字段。 229 | 230 | ```php 231 | $card->createLandingPage($banner, $pageTitle, $canShare, $scene, $cards); 232 | ``` 233 | 234 | > - `banner` string -页面的 banner 图; 235 | > - `pageTitle` string - 页面的 title 236 | > - `canShare` bool - 页面是不是可以分享,true 或 false 237 | > - `scene` string - 投放页面的场景值,具体值请参考下面的 example 238 | > - `cards` array - 卡券列表,每个元素有两个字段 239 | 240 | 示例: 241 | 242 | ```php 243 | $banner = 'http://mmbiz.qpic.cn/mmbiz/iaL1LJM1mF9aRKPZJkmG8xXhiaHqkKSVMMWeN3hLut7X7hicFN'; 244 | $pageTitle = '惠城优惠大派送'; 245 | $canShare = true; 246 | 247 | //SCENE_NEAR_BY 附近 248 | //SCENE_MENU 自定义菜单 249 | //SCENE_QRCODE 二维码 250 | //SCENE_ARTICLE 公众号文章 251 | //SCENE_H5 h5页面 252 | //SCENE_IVR 自动回复 253 | //SCENE_CARD_CUSTOM_CELL 卡券自定义cell 254 | $scene = 'SCENE_NEAR_BY'; 255 | 256 | $cardList = [ 257 | ['card_id' => 'pdkJ9uLRSbnB3UFEjZAgUxAJrjeY', 'thumb_url' => 'http://test.digilinx.cn/wxApi/Uploads/test.png'], 258 | ['card_id' => 'pdkJ9uJ37aU-tyRj4_grs8S45k1c', 'thumb_url' => 'http://test.digilinx.cn/wxApi/Uploads/aa.jpg'], 259 | ]; 260 | 261 | $result = $card->createLandingPage($banner, $pageTitle, $canShare, $scene, $cardList); 262 | ``` 263 | 264 | 265 | ### 图文消息群发卡券 266 | 267 | > {warning} 特别注意:目前该接口仅支持填入非自定义 code 的卡券,自定义 code 的卡券需先进行 code 导入后调用。 268 | 269 | ```php 270 | $card->getHtml($cardId); 271 | ``` 272 | 273 | 示例: 274 | 275 | ```php 276 | $cardId = 'pdkJ9uLCEF_HSKO7JdQOUcZ-PUzo'; 277 | 278 | $result = $card->getHtml($cardId); 279 | ``` 280 | 281 | ### 设置测试白名单 282 | 283 | 同时支持“openid”、“username”两种字段设置白名单,总数上限为10个。 284 | 285 | ```php 286 | $card->setTestWhitelist($openids); // 使用 openid 287 | $card->setTestWhitelistByName($usernames); // 使用 username 288 | ``` 289 | 290 | > - `openids` array - 测试的openid列表 291 | > - `usernames` array> - 测试的微信号列表 292 | 293 | 示例: 294 | 295 | ```php 296 | // by openid 297 | $openids = [$openId, $openId2, $openid3...]; 298 | $result = $card->setTestWhitelist($openids); 299 | 300 | // by username 301 | $usernames = ['tianye0327', 'iovertrue']; 302 | $result = $card->setTestWhitelistByName($usernames); 303 | ``` 304 | 305 | ### 获取用户已领取卡券接口 306 | 307 | 用于获取用户卡包里的,属于该appid下所有**可用卡券,包括正常状态和未生效状态**。 308 | 309 | ```php 310 | $card->getUserCards($openid, $cardId); 311 | ``` 312 | 313 | 示例: 314 | 315 | ```php 316 | $openid = 'odkJ9uDUz26RY-7DN1mxkznfo9xU'; 317 | $cardId = ''; // 卡券ID。不填写时默认查询当前 appid 下的卡券。 318 | 319 | $result = $card->getUserCards($openid, $cardId); 320 | ``` 321 | 322 | 323 | ### 设置微信买单接口 324 | 325 | ```php 326 | $card->setPayCell($cardId, $isOpen = true); 327 | ``` 328 | 329 | > - `isOpen` string - 是否开启买单功能,填 true/false,不填默认 true 330 | 331 | 示例: 332 | 333 | ```php 334 | $cardId = 'pdkJ9uH7u11R-Tu1kilbaW_zDFow'; 335 | 336 | $result = $card->setPayCell($cardId); // isOpen = true 337 | $result = $card->setPayCell($cardId, $isOpen); 338 | ``` 339 | 340 | 341 | 342 | ### 修改库存接口 343 | 344 | ```php 345 | $card->increaseStock($cardId, $amount); // 增加库存 346 | $card->reductStock($cardId, $amount); // 减少库存 347 | ``` 348 | 349 | > - `cardId` string - 卡券 ID 350 | > - `amount` int - 修改多少库存 351 | 352 | 示例: 353 | 354 | ```php 355 | $cardId = 'pdkJ9uLRSbnB3UFEjZAgUxAJrjeY'; 356 | 357 | $result = $card->increaseStock($cardId, 100); 358 | ``` 359 | 360 | ## 卡券 Code 361 | 362 | ### 导入code接口 363 | 364 | 在自定义code卡券成功创建并且通过审核后,必须将自定义code按照与发券方的约定数量调用导入code接口导入微信后台。 365 | 366 | ```php 367 | $card->code->deposit($cardId, $codes); 368 | ``` 369 | 370 | > - `cardId` string - 要导入code的卡券ID 371 | > - `codes` array - 要导入微信卡券后台的自定义 code,最多100个 372 | 373 | 示例: 374 | 375 | ```php 376 | $cardId = 'pdkJ9uLCEF_HSKO7JdQOUcZ-PUzo'; 377 | $codes = ['11111', '22222', '33333']; 378 | 379 | $result = $card->code->deposit($cardId, $codes); 380 | ``` 381 | 382 | 383 | 384 | ### 查询导入code数目 385 | 386 | ```php 387 | $card->code->getDepositedCount($cardId); // 要导入 code 的卡券 ID 388 | ``` 389 | 390 | 示例: 391 | 392 | ```php 393 | $cardId = 'pdkJ9uLCEF_HSKO7JdQOUcZ-PUzo'; 394 | 395 | $result = $card->code->getDepositedCount($cardId); 396 | ``` 397 | 398 | 399 | 400 | ### 核查 code 接口 401 | 402 | 为了避免出现导入差错,强烈建议开发者在查询完 code 数目的时候核查 code 接口校验 code 导入微信后台的情况。 403 | 404 | ```php 405 | $card->code->check($cardId, $codes); 406 | ``` 407 | 408 | 示例: 409 | 410 | ```php 411 | $cardId = 'pdkJ9uLCEF_HSKO7JdQOUcZ-PUzo'; 412 | 413 | $codes = ['807732265476', '22222', '33333']; 414 | 415 | $result = $card->code->check($cardId, $codes); 416 | ``` 417 | 418 | 419 | ### 查询 Code 接口 420 | 421 | ```php 422 | $card->code->get($code, $cardId, $checkConsume = true); 423 | ``` 424 | 425 | > - checkConsume 是否校验code核销状态,true和false 426 | 427 | 示例: 428 | 429 | ```php 430 | $code = '736052543512'; 431 | $cardId = 'pdkJ9uDgnm0pKfrTb1yV0dFMO_Gk'; 432 | 433 | $result = $card->code->get($code, $cardId); 434 | $result = $card->code->get($code, $cardId, false); // check_consume = false 435 | ``` 436 | 437 | 438 | 439 | ### 核销Code接口 440 | 441 | ```php 442 | $card->code->consume($code); 443 | // 或者指定 cardId 444 | $card->code->consume($code, $cardId); 445 | ``` 446 | 447 | 示例: 448 | 449 | ```php 450 | $code = '789248558333'; 451 | $cardId = 'pdkJ9uDmhkLj6l5bm3cq9iteQBck'; 452 | 453 | $result = $card->code->consume($code); 454 | // 或 455 | $result = $card->code->consume($code, $cardId); 456 | ``` 457 | 458 | ### Code 解码接口 459 | 460 | ```php 461 | $card->code->decrypt($encryptedCode); 462 | ``` 463 | 464 | 示例: 465 | 466 | ```php 467 | $encryptedCode = 'XXIzTtMqCxwOaawoE91+VJdsFmv7b8g0VZIZkqf4GWA60Fzpc8ksZ/5ZZ0DVkXdE'; 468 | 469 | $result = $card->code->decrypt($encryptedCode); 470 | ``` 471 | 472 | 473 | ### 更改 Code 接口 474 | 475 | ```php 476 | $card->code->update($code, $newCode, $cardId); 477 | ``` 478 | 479 | > - `newCode` string - 变更后的有效 Code 码 480 | 481 | 示例: 482 | 483 | ```php 484 | $code = '148246271394'; 485 | $newCode = '659266965266'; 486 | $cardId = ''; 487 | 488 | $result = $card->code->update($code, $newCode, $cardId); 489 | ``` 490 | 491 | 492 | ### 设置卡券失效 493 | 494 | ```php 495 | $card->code->disable($code, $cardId); 496 | ``` 497 | 498 | 示例: 499 | 500 | ```php 501 | $code = '736052543512'; 502 | $cardId = ''; 503 | 504 | $result = $card->code->disable($code, $cardId); 505 | ``` 506 | 507 | ## 通用卡券 508 | 509 | ## 卡券激活 510 | 511 | ```php 512 | $result = $card->general_card->activate($info); 513 | ``` 514 | 515 | ## 撤销激活 516 | 517 | ```php 518 | $result = $card->general_card->deactivate(string $cardId, string $code); 519 | ``` 520 | 521 | ## 更新用户信息 522 | 523 | ```php 524 | $result = $card->general_card->updateUser(array $info); 525 | ``` 526 | 527 | ## 会员卡 528 | 529 | ### 会员卡激活 530 | 531 | ```php 532 | $result = $card->member_card->activate($info); 533 | ``` 534 | 535 | > - `info` - 需要激活的会员卡信息 536 | 537 | 示例: 538 | 539 | ```php 540 | $info = [ 541 | 'membership_number' => '357898858', //会员卡编号,由开发者填入,作为序列号显示在用户的卡包里。可与Code码保持等值。 542 | 'code' => '916679873278', //创建会员卡时获取的初始code。 543 | 'activate_begin_time' => '1397577600', //激活后的有效起始时间。若不填写默认以创建时的 data_info 为准。Unix时间戳格式 544 | 'activate_end_time' => '1422724261', //激活后的有效截至时间。若不填写默认以创建时的 data_info 为准。Unix时间戳格式。 545 | 'init_bonus' => '持白金会员卡到店消费,可享8折优惠。', //初始积分,不填为0。 546 | 'init_balance' => '持白金会员卡到店消费,可享8折优惠。', //初始余额,不填为0。 547 | 'init_custom_field_value1' => '白银', //创建时字段custom_field1定义类型的初始值,限制为4个汉字,12字节。 548 | 'init_custom_field_value2' => '9折', //创建时字段custom_field2定义类型的初始值,限制为4个汉字,12字节。 549 | 'init_custom_field_value3' => '200', //创建时字段custom_field3定义类型的初始值,限制为4个汉字,12字节。 550 | ]; 551 | 552 | $result = $card->member_card->activate($info); 553 | ``` 554 | 555 | ### 设置开卡字段 556 | 557 | ```php 558 | $card->member_card->setActivationForm($cardId, $settings); 559 | ``` 560 | 561 | > - `settings` array - 会员卡激活时的选项 562 | 563 | 示例: 564 | 565 | ```php 566 | $cardId = 'pdkJ9uJYAyfLXsUCwI2LdH2Pn1AU'; 567 | 568 | $settings = [ 569 | 'required_form' => [ 570 | 'common_field_id_list' => [ 571 | 'USER_FORM_INFO_FLAG_MOBILE', 572 | 'USER_FORM_INFO_FLAG_LOCATION', 573 | 'USER_FORM_INFO_FLAG_BIRTHDAY', 574 | ], 575 | 'custom_field_list' => [ 576 | '喜欢的食物', 577 | ], 578 | ], 579 | 'optional_form' => [ 580 | 'common_field_id_list' => [ 581 | 'USER_FORM_INFO_FLAG_EMAIL', 582 | ], 583 | 'custom_field_list' => [ 584 | '喜欢的食物', 585 | ], 586 | ], 587 | ]; 588 | 589 | $result = $card->member_card->setActivationForm($cardId, $settings); 590 | ``` 591 | 592 | 593 | 594 | ### 拉取会员信息 595 | 596 | ```php 597 | $card->member_card->getUser($cardId, $code); 598 | ``` 599 | 600 | 示例: 601 | 602 | ```php 603 | $cardId = 'pbLatjtZ7v1BG_ZnTjbW85GYc_E8'; 604 | $code = '916679873278'; 605 | 606 | $result = $card->member_card->getUser($cardId, $code); 607 | ``` 608 | 609 | 610 | 611 | ### 更新会员信息 612 | 613 | ```php 614 | $card->member_card->updateUser($info); 615 | ``` 616 | 617 | > - `info` array - 可以更新的会员信息 618 | 619 | 示例: 620 | 621 | ```php 622 | $info = [ 623 | 'code' => '916679873278', //卡券Code码。 624 | 'card_id' => 'pbLatjtZ7v1BG_ZnTjbW85GYc_E8', //卡券ID。 625 | 'record_bonus' => '消费30元,获得3积分', //商家自定义积分消耗记录,不超过14个汉字。 626 | 'bonus' => '100', //需要设置的积分全量值,传入的数值会直接显示,如果同时传入add_bonus和bonus,则前者无效。 627 | 'balance' => '持白金会员卡到店消费,可享8折优惠。', //需要设置的余额全量值,传入的数值会直接显示,如果同时传入add_balance和balance,则前者无效。 628 | 'record_balance' => '持白金会员卡到店消费,可享8折优惠。', //商家自定义金额消耗记录,不超过14个汉字。 629 | 'custom_field_value1' => '100', //创建时字段custom_field1定义类型的最新数值,限制为4个汉字,12字节。 630 | 'custom_field_value2' => '200', //创建时字段custom_field2定义类型的最新数值,限制为4个汉字,12字节。 631 | 'custom_field_value3' => '300', //创建时字段custom_field3定义类型的最新数值,限制为4个汉字,12字节。 632 | ]; 633 | 634 | $result = $card->member_card->updateUser($info); 635 | ``` 636 | 637 | ## 子商户 638 | 639 | ### 添加子商户 640 | 641 | ```php 642 | $card->sub_merchant->create(array $attributes);  643 | ``` 644 | 645 | 示例: 646 | 647 | ```php 648 | $attributes = [ 649 | 'brand_name' => 'overtrue', 650 | 'logo_url' => 'http://mmbiz.qpic.cn/mmbiz/iaL1LJM1mF9aRKPZJkmG8xXhiaHqkKSVMMWeN3hLut7X7hicFNjakmxibMLGWpXrEXB33367o7zHN0CwngnQY7zb7g/0', 651 | 'protocol' => 'qIqwTfzAdJ_1-VJFT0fIV53DSY4sZY2WyhkzZzbV498Qgdp-K5HJtZihbHLS0Ys0', 652 | 'end_time' => '1438990559', 653 | 'primary_category_id' => 1, 654 | 'secondary_category_id' => 101, 655 | 'agreement_media_id' => '', 656 | 'operator_media_id' => '', 657 | 'app_id' => '', 658 | ]; 659 | 660 | $result = $card->sub_merchant->create($attributes); 661 | ``` 662 | 663 | ### 更新子商户 664 | 665 | ```php 666 | $card->sub_merchant->update(int $merchantId, array $info); 667 | ``` 668 | 669 | > - `$merchantId` int - 子商户 ID 670 | > - `$info` array - 参数与创建子商户参数一样 671 | 672 | 示例: 673 | 674 | ```php 675 | $info = [ 676 | //... 677 | ]; 678 | $result = $card->sub_merchant->update('12', $info); 679 | ``` 680 | 681 | ## 特殊票券 682 | 683 | ### 机票值机 684 | 685 | ```php 686 | $card->boarding_pass->checkin(array $params); 687 | ``` 688 | 689 | ### 更新会议门票 - 更新用户 690 | 691 | 692 | ```php 693 | $card->meeting_ticket->updateUser(array $params); 694 | ``` 695 | 696 | ### 更新电影门票 - 更新用户 697 | 698 | 699 | ```php 700 | $card->movie_ticket->updateUser(array $params); 701 | ``` 702 | 703 | 704 | ## JSAPI 705 | 706 | ### 卡券批量下发到用户 707 | 708 | ```php 709 | $cards = [ 710 | ['card_id' => 'pdkJ9uLRSbnB3UFEjZAgUxAJrjeY', 'outer_id' => 2], 711 | ['card_id' => 'pdkJ9uJ37aU-tyRj4_grs8S45k1c', 'outer_id' => 3], 712 | ]; 713 | $json = $card->jssdk->assign($cards); // 返回 json 格式 714 | ``` 715 | 716 | 返回 json,在模板里的用法: 717 | 718 | ```html 719 | wx.addCard({ 720 | cardList: , // 需要打开的卡券列表 721 | success: function (res) { 722 | var cardList = res.cardList; // 添加的卡券列表信息 723 | } 724 | }); 725 | ``` 726 | 727 | ### 获取 Ticket 728 | 729 | ```php 730 | $card->jssdk->getTicket(); 731 | // 强制刷新 732 | $card->jssdk->getTicket(true); 733 | ``` 734 | -------------------------------------------------------------------------------- /official-account/shake-around.md: -------------------------------------------------------------------------------- 1 | # 摇一摇周边 2 | 3 | 4 | 摇一摇周边是微信在线下的全新功能, 为线下商户提供近距离连接用户的能力, 并支持线下商户向周边用户提供个性化营销、互动及信息推荐等服务。 5 | 6 | ## 获取实例 7 | 8 | ```php 9 | $shakearound = $app->shake_around; 10 | 11 | ``` 12 | 13 | ## 说明 14 | 15 | > 特别提醒: 16 | 1、下述所有的接口调用的方法参数都要严格按照方法参数前的类型传入相应类型的实参,否则可能会得到非预期的结果。 17 | 2、涉及需要传入设备id($deviceIdentifier)的参数时,该参数是一个以 `device_id` 或包含 `uuid` `major` `minor` 为key的关联数组。 18 | 3、涉及需要传入设备id列表($deviceIdentifiers)的参数时,该参数是一个二维数组,第一层为索引类型,第二层为关联类型($deviceIdentifier)。 19 | 20 | ```php 21 | // 参数 $deviceIdentifier 的实参形式: 22 | ['device_id' => 10097] 23 | // 或 24 | [ 25 | 'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825', 26 | 'major' => 10001, 27 | 'minor' => 12102, 28 | ] 29 | // 参数$deviceIdentifiers的实参形式: 30 | [ 31 | ['device_id' => 10097], 32 | ['device_id' => 10098], 33 | ] 34 | // 或 35 | [ 36 | [ 37 | 'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825', 38 | 'major' => 10001, 39 | 'minor' => 12102, 40 | ], 41 | [ 42 | 'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825', 43 | 'major' => 10001, 44 | 'minor' => 12103, 45 | ] 46 | ] 47 | ``` 48 | 49 | ## 开通摇一摇周边 50 | 51 | > 提示: 52 | 若不是做 [公众号第三方平台](https://open.weixin.qq.com/cgi-bin/frame?t=home/wx_plugin_tmpl&lang=zh_CN) 开发,建议直接在微信管理后台申请开通摇一摇周边功能。 53 | 54 | ### 申请开通 55 | 56 | 申请开通摇一摇周边功能。成功提交申请请求后,工作人员会在三个工作日内完成审核。若审核不通过,可以重新提交申请请求。若是审核中,请耐心等待工作人员审核,在审核中状态不能再提交申请请求。 57 | 58 | 方法 59 | 60 | ```php 61 | $shakearound->register($data) 62 | ``` 63 | 64 | > {warning} 注意: 65 | 1、相关资质文件的图片是使用本页面下方的素材管理的接口上传的,切勿和另一个 [素材管理](material) 接口混淆。 66 | 2、行业代码请务必传入**字符串**类型的实参,否则以数字0开头的行业代码将会被当成八进制数处理(将转换为十进制数),这可能不是期望的。 67 | 68 | ### 查询审核状态 69 | 70 | 查询已经提交的开通摇一摇周边功能申请的审核状态。在申请提交后,工作人员会在三个工作日内完成审核。 71 | 72 | 方法 73 | 74 | ```php 75 | $shakearound->status() 76 | ``` 77 | 78 | ### 获取摇一摇的设备及用户信息 79 | 80 | 获取设备信息,包括UUID、major、minor,以及距离、openID等信息。 81 | 82 | 方法 83 | 84 | ```php 85 | $shakearound->user($ticket); 86 | // 或者需要返回门店poi_id 87 | $shakearound->user($ticket, true); 88 | ``` 89 | 90 | ## 设备管理 91 | 92 | ### 申请设备 ID 93 | 94 | 申请配置设备所需的UUID、Major、Minor。申请成功后返回批次ID,可用返回的批次ID通过“查询设备ID申请状态”接口查询目前申请的审核状态。 95 | 一个公众账号最多可申请100000个设备ID,如需申请的设备ID数超过最大限额,请邮件至zhoubian@tencent.com,邮件格式如下: 96 | 97 | > 标题:申请提升设备ID额度 98 | 内容: 99 | 1、公众账号名称及appid(wx开头的字符串,在mp平台可查看) 100 | 2、用途 101 | 3、预估需要多少设备ID 102 | 103 | 方法 104 | 105 | ```php 106 | $shakearound->device->apply($data) 107 | ``` 108 | 109 | ### 查询设备 ID 申请审核状态 110 | 111 | 查询设备ID申请的审核状态。若单次申请的设备ID数量小于等于500个,系统会进行快速审核;若单次申请的设备ID数量大于500个,则在三个工作日内完成审核。 112 | 113 | 方法 114 | 115 | ```php 116 | $shakearound->device->status($applyId) // $applyId 批次ID,申请设备ID时所返回的批次ID 117 | ``` 118 | 119 | ### 编辑设备信息 120 | 121 | > 仅能修改设备的备注信息。 122 | 123 | 方法 124 | 125 | ```php 126 | $shakearound->device->update(array $deviceIdentifier, string $comment) 127 | ``` 128 | 129 | 参数 130 | 131 | > $deviceIdentifier 设备id,设备编号device_id或UUID、major、minor的关联数组,若二者都填,则以设备编号为优先 132 | $comment 设备的备注信息,不超过15个汉字或30个英文字母 133 | 134 | 示例 135 | 136 | ```php 137 | $result = $shakearound->device->update(['device_id' => 10011], 'test'); 138 | // 或 139 | $result = $shakearound->device->update(['uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825', 140 | 'major' => 1002, 141 | 'minor' => 1223, 142 | ], 'test'); 143 | 144 | /* 返回结果 145 | { 146 | "data": { 147 | }, 148 | "errcode": 0, 149 | "errmsg": "success." 150 | } 151 | */ 152 | var_dump($result['errcode']) // 0 153 | ``` 154 | 155 | ### 配置设备与门店/其他公众账号门店的关联关系 156 | 157 | 关联本公众账号门店时,支持创建门店后直接关联在设备上,无需为审核通过状态,摇周边后台自动更新门店的最新信息和状态。 158 | 关联其他公众账号门店时,支持设备关联其他公众账号的门店,门店需为审核通过状态。 159 | 160 | > 因为第三方门店不归属本公众账号,所以未保存到设备详情中,查询设备列表接口与获取摇周边的设备及用户信息接口不会返回第三方门店。 161 | 162 | 方法 163 | 164 | ```php 165 | $shakearound->device->bindPoi(array $deviceIdentifier, $poiId) 166 | 167 | //或者 绑定第三方 168 | $shakearound->device->bindThirdPoi(array $deviceIdentifier, $poiId, $poiAppId) 169 | ``` 170 | 171 | 参数 172 | 173 | > $deviceIdentifier 设备 id,设备编号 device_id 或 UUID、major、minor 的关联数组,若二者都填,则以设备编号为优先 174 | $poiId 设备关联的门店 ID,关联门店后,在门店 1KM 的范围内有优先摇出信息的机会。当值为0时,将清除设备已关联的门店 ID 175 | $poiAppId 关联门店所归属的公众账号的 APP ID 176 | 177 | 示例 178 | 179 | ```php 180 | // 关联本公众账号门店 181 | $result = $shakearound->device->bindLocation(['device_id' => 10011], 1231); 182 | // 或 183 | $result = $shakearound->device->bindLocation([ 184 | 'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825', 185 | 'major' => 1002, 186 | 'minor' => 1223, 187 | ], 1231); 188 | 189 | // 关联其他公众账号门店 190 | // wxappid 为关联门店所归属的公众账号的 APP ID 191 | $result = $shakearound->device->bindThirdPoi(['device_id' => 10011], 1231, 'wxappid'); 192 | 193 | // 或 194 | $result = $shakearound->device->bindThirdPoi([ 195 | 'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825', 196 | 'major' => 1002, 197 | 'minor' => 1223, 198 | ], 1231, 'wxappid'); 199 | 200 | /* 返回结果 201 | { 202 | "data": { 203 | }, 204 | "errcode": 0, 205 | "errmsg": "success." 206 | } 207 | */ 208 | ``` 209 | 210 | ## 查询设备列表 211 | 212 | 查询已有的设备 ID、UUID、Major、Minor、激活状态、备注信息、关联门店、关联页面等信息。 213 | 214 | ### 根据设备id批量取回设备数据 215 | 216 | 方法 217 | 218 | > $shakearound->device->listByIds(array $deviceIdentifiers) 219 | 220 | 参数 221 | 222 | > $deviceIdentifiers 设备id列表 223 | 224 | 示例 225 | 226 | ```php 227 | $result = $shakearound->device->listByIds([ 228 | ['device_id' => 10097], 229 | ['device_id' => 10098], 230 | ]); 231 | // 或 232 | $result = $shakearound->device->listByIds([ 233 | [ 234 | 'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825', 235 | 'major' => 10001, 236 | 'minor' => 12102, 237 | ], 238 | [ 239 | 'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825', 240 | 'major' => 10001, 241 | 'minor' => 12103, 242 | ] 243 | ]); 244 | 245 | /* 返回结果 246 | { 247 | "data": { 248 | "devices": [ 249 | { 250 | "comment": "", 251 | "device_id": 10097, 252 | "major": 10001, 253 | "minor": 12102, 254 | "status": 1, 255 | "last_active_time":1437276018, 256 | "poi_id": 0, 257 | "uuid": "FDA50693-A4E2-4FB1-AFCF-C6EB07647825" 258 | }, 259 | { 260 | "comment": "", 261 | "device_id": 10098, 262 | "major": 10001, 263 | "minor": 12103, 264 | "status": 1, 265 | "last_active_time":1437276018, 266 | "poi_appid":"wxe3813f5d8c546fc7" 267 | "poi_id": 123, 268 | "uuid": "FDA50693-A4E2-4FB1-AFCF-C6EB07647825" 269 | } 270 | ], 271 | "total_count": 151 272 | }, 273 | "errcode": 0, 274 | "errmsg": "success." 275 | } 276 | */ 277 | ``` 278 | 279 | ### 分页批量取回设备数据 280 | 281 | 方法 282 | 283 | ```php 284 | $shakearound->device->list(int $lastId, int $count) 285 | ``` 286 | 287 | 参数 288 | 289 | > $lastId 前一次查询列表末尾的设备编号 device_id,第一次查询 lastId 为 0 290 | $count 待查询的设备数量,不能超过50个 291 | 292 | 示例 293 | 294 | ```php 295 | $result = $shakearound->device->list(10097, 3); 296 | 297 | // 返回结果同上 298 | ``` 299 | 300 | ### 根据申请时的批次 ID 分页批量取回设备数据 301 | 302 | 方法 303 | 304 | > $shakearound->device->listByApplyId(int $applyId, int $lastId, int $count) 305 | 306 | 参数 307 | 308 | > $applyId 批次ID,申请设备ID时所返回的批次ID 309 | $lastId 前一次查询列表末尾的设备编号device_id,第一次查询 lastId 为 0 310 | $count 待查询的设备数量,不能超过50个 311 | 312 | 示例 313 | 314 | ```php 315 | $result = $shakearound->device->listByApplyId(1231, 10097, 3); 316 | 317 | // 返回结果同上 318 | ``` 319 | 320 | ## 页面管理 321 | 322 | ### 新增页面 323 | 324 | 新增摇一摇出来的页面信息,包括在摇一摇页面出现的主标题、副标题、图片和点击进去的超链接。其中,图片必须为用素材管理接口上传至微信侧服务器后返回的链接。 325 | 326 | > {warning} 注意: 327 | 图片是使用本页面下方的素材管理的接口上传的,切勿和另一个 [素材管理](material) 接口混淆。 328 | 329 | 方法 330 | 331 | ```php 332 | $shakearound->page->create($data) 333 | ``` 334 | 335 | 参数 336 | 337 | > $title 在摇一摇页面展示的主标题,不超过6个汉字或12个英文字母 338 | $description 在摇一摇页面展示的副标题,不超过7个汉字或14个英文字母 339 | $pageUrl 点击进去的超链接 340 | $iconUrl 在摇一摇页面展示的图片。图片需先上传至微信侧服务器,用“素材管理-上传图片素材”接口上传图片,返回的图片URL再配置在此处 341 | $comment 可选,页面的备注信息,不超过15个汉字或30个英文字母 342 | 343 | 示例 344 | 345 | ```php 346 | $result = $shakearound->page->create($data); 347 | 348 | /* 返回结果 349 | { 350 | "data": { 351 | "page_id": 28840 352 | } 353 | "errcode": 0, 354 | "errmsg": "success." 355 | } 356 | */ 357 | ``` 358 | 359 | ### 编辑页面信息 360 | 361 | 编辑摇一摇出来的页面信息,包括在摇一摇页面出现的主标题、副标题、图片和点击进去的超链接。 362 | 363 | 方法 364 | 365 | ```php 366 | $shakearound->page->update(int $pageId, array $data) 367 | ``` 368 | 369 | 参数 370 | 371 | > $pageId 摇周边页面唯一ID 372 | $data 需要更新的信息 373 | 374 | 示例 375 | 376 | ```php 377 | $result = $shakearound->page->update(28840, [ 378 | 'title' => '主标题', 379 | 'description' => '副标题', 380 | //... 381 | ]); 382 | ``` 383 | 384 | ## 查询页面列表 385 | 386 | 查询已有的页面,包括在摇一摇页面出现的主标题、副标题、图片和点击进去的超链接。 387 | 388 | ### 根据页面id批量取回页面数据 389 | 390 | 方法 391 | 392 | ```php 393 | $shakearound->page->listByIds(array $pageIds) 394 | ``` 395 | 396 | 参数 397 | 398 | > $pageIds 页面的id列表,索引数组 399 | 400 | 示例 401 | 402 | ```php 403 | $result = $shakearound->page->listByIds([28840, 28842]); 404 | 405 | /* 返回结果 406 | { 407 | "data": { 408 | "pages": [ 409 | { 410 | "comment": "just for test", 411 | "description": "test", 412 | "icon_url": "https://www.baidu.com/img/bd_logo1", 413 | "page_id": 28840, 414 | "page_url": "http://xw.qq.com/testapi1", 415 | "title": "测试1" 416 | }, 417 | { 418 | "comment": "just for test", 419 | "description": "test", 420 | "icon_url": "https://www.baidu.com/img/bd_logo1", 421 | "page_id": 28842, 422 | "page_url": "http://xw.qq.com/testapi2", 423 | "title": "测试2" 424 | } 425 | ], 426 | "total_count": 2 427 | }, 428 | "errcode": 0, 429 | "errmsg": "success." 430 | } 431 | */ 432 | ``` 433 | 434 | ### 分页批量取回页面数据 435 | 436 | 方法 437 | 438 | ```php 439 | $shakearound->page->list(int $begin, int $count) 440 | ``` 441 | 442 | 参数 443 | 444 | > $begin 页面列表的起始索引值 445 | $count 待查询的页面数量,不能超过50个 446 | 447 | 示例 448 | 449 | ```php 450 | $result = $shakearound->page->list(0,2); 451 | 452 | // 返回结果同上 453 | ``` 454 | 455 | ### 删除页面 456 | 457 | 删除已有的页面,包括在摇一摇页面出现的主标题、副标题、图片和点击进去的超链接。 458 | 459 | > {warning} 注意: 460 | 只有页面与设备没有关联关系时,才可被删除。 461 | 462 | 方法 463 | 464 | ```php 465 | $shakearound->page->delete(int $pageId) 466 | ``` 467 | 468 | 参数 469 | 470 | > $pageId 页面的id 471 | 472 | 示例 473 | 474 | ```php 475 | $result = $shakearound->page->delete(34567); 476 | 477 | /* 返回结果 478 | { 479 | "data": { 480 | }, 481 | "errcode": 0, 482 | "errmsg": "success." 483 | } 484 | */ 485 | ``` 486 | 487 | ### 素材管理 488 | 489 | 上传在摇一摇功能中需使用到的图片素材,素材保存在微信侧服务器上。图片格式限定为:jpg,jpeg,png,gif。 490 | 若图片为在摇一摇页面展示的图片,则其素材为 `icon` 类型的图片,图片大小建议 `120px*120 px` ,限制不超过 `200 px *200 px` ,图片需为 `正方形` 。 491 | 若图片为申请开通摇一摇周边功能需要上传的资质文件图片,则其素材为 `license` 类型的图片,图片的文件大小不超过 `2MB` ,尺寸不限,形状不限。 492 | 493 | 方法 494 | 495 | > $shakearound->material->uploadImage(string $path [, string $type = 'icon']) 496 | 497 | 参数 498 | 499 | > $path 图片所在路径 500 | $type 可选,值为icon或license 501 | 502 | 示例 503 | 504 | ```php 505 | $result = $shakearound->material->uploadImage(__DIR__ . '/stubs/image.jpg'); 506 | 507 | /* 返回结果 508 | { 509 | "data": { 510 | "pic_url": http://shp.qpic.cn/wechat_shakearound_pic/0/1428377032e9dd2797018cad79186e03e8c5aec8dc/120" 511 | }, 512 | "errcode": 0, 513 | "errmsg": "success." 514 | } 515 | */ 516 | ``` 517 | 518 | ## 管理设备与页面的关系 519 | 520 | 通过接口申请的设备ID,需先配置页面,若未配置页面,则摇不出页面信息。 521 | 522 | ### 配置设备与页面的关联关系 523 | 524 | 配置完成后,在此设备的信号范围内,即可摇出关联的页面信息。 525 | 若设备配置多个页面,则随机出现页面信息。一个设备最多可配置30个关联页面。 526 | 527 | > {warning} 注意: 528 | 1、配置时传入该设备需要关联的页面的id列表,该设备原有的关联关系将被直接清除。 529 | 2、页面的id列表允许为空(**传入空数组**),当页面的id列表为空时则会清除该设备的所有关联关系。 530 | 531 | 方法 532 | 533 | > $shakearound->relation->bindPage(array $deviceIdentifier, array $pageIds) 534 | 535 | 参数 536 | 537 | > $deviceIdentifier 设备id,设备编号device_id或UUID、major、minor的关联数组,若二者都填,则以设备编号为优先 538 | $pageIds 页面的id列表,索引数组 539 | 540 | 示例 541 | 542 | ```php 543 | $result = $shakearound->relation->bindPage(['device_id' => 10011], [12345, 23456, 334567]); 544 | // 或 545 | $result = $shakearound->relation->bindPage(['uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825', 546 | 'major' => 1002, 547 | 'minor' => 1223, 548 | ], [12345, 23456, 334567]); 549 | 550 | /* 返回结果 551 | { 552 | "data": { 553 | }, 554 | "errcode": 0, 555 | "errmsg": "success." 556 | } 557 | */ 558 | var_dump($result->errcode) // 0 559 | ``` 560 | 561 | ### 查询设备与页面的关联关系 562 | 563 | #### 查询指定设备所关联的页面 564 | 565 | 根据设备ID或完整的UUID、Major、Minor查询该设备所关联的所有页面信息 566 | 567 | 方法 568 | 569 | > $shakearound->relation->listByDeviceId(array $deviceIdentifier [, boolean $raw = false]) 570 | 571 | > {warning} 注意: 572 | 该方法默认对返回的数据进行处理后返回一个包含页面id的索引数组。若要返回和 `getDeviceByPageId` 方法类似的数据,请传入 `true` 作为第二个参数。 573 | 574 | 参数 575 | 576 | > $deviceIdentifier 设备id,设备编号device_id或UUID、major、minor的关联数组,若二者都填,则以设备编号为优先 577 | $raw 可选,当为true时,返回值和getDeviceByPageId方法类似,否则返回页面的id列表(索引数组,无关联时为空数组) 578 | 579 | 示例 580 | 581 | ```php 582 | $result = $shakearound->relation->listByDeviceId(['device_id' => 10011]); 583 | // 或 584 | $result = $shakearound->relation->listByDeviceId([ 585 | 'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825', 586 | 'major' => 1002, 587 | 'minor' => 1223, 588 | ]); 589 | 590 | // 返回结果 591 | var_dump($result) // [50054,50055] 592 | ``` 593 | 594 | ##### 查询指定页面所关联的设备 595 | 596 | 指定页面ID分页查询该页面所关联的所有的设备信息 597 | 598 | 方法 599 | 600 | > $shakearound->relation->listByPageId(int $pageId, int $begin, int $count) 601 | 602 | 参数 603 | 604 | > $pageId 指定的页面id 605 | $begin 关联关系列表的起始索引值 606 | $count 待查询的关联关系数量,不能超过50个 607 | 608 | 示例 609 | 610 | ```php 611 | $result = $shakearound->relation->listByPageId(50054, 0, 3); 612 | 613 | /* 返回结果 614 | { 615 | "data": { 616 | "relations": [ 617 | { 618 | "device_id": 797994, 619 | "major": 10001, 620 | "minor": 10023, 621 | "page_id": 50054, 622 | "uuid": "FDA50693-A4E2-4FB1-AFCF-C6EB07647825" 623 | }, 624 | { 625 | "device_id": 797995, 626 | "major": 10001, 627 | "minor": 10024, 628 | "page_id": 50054, 629 | "uuid": "FDA50693-A4E2-4FB1-AFCF-C6EB07647825" 630 | } 631 | ], 632 | "total_count": 2 633 | }, 634 | "errcode": 0, 635 | "errmsg": "success." 636 | } 637 | */ 638 | ``` 639 | 640 | ### 摇一摇数据统计 641 | 642 | > 此接口无法获取当天的数据,最早只能获取前一天的数据。 643 | 由于系统在凌晨处理前一天的数据,太早调用此接口可能获取不到数据,建议在早上8:00之后调用此接口。 644 | 645 | ### 以设备为维度的数据统计 646 | 647 | 查询单个设备进行摇周边操作的人数、次数,点击摇周边消息的人数、次数。 648 | 649 | > {warning} 注意: 650 | 查询的最长时间跨度为 30 天。只能查询最近 90 天的数据。 651 | 652 | 方法 653 | 654 | > $shakearound->stats->deviceSummary(array $deviceIdentifier, int $beginDate, int $endDate) 655 | 656 | 参数 657 | 658 | > $deviceIdentifier 设备id,设备编号device_id或UUID、major、minor的关联数组,若二者都填,则以设备编号为优先 659 | $beginDate 起始日期时间戳,最长时间跨度为30天,单位为秒 660 | $endDate 结束日期时间戳,最长时间跨度为30天,单位为秒 661 | 662 | 示例 663 | 664 | ```php 665 | $result = $shakearound->stats->deviceSummary(['device_id' => 10011], 1425052800, 1425139200); 666 | // 或 667 | $result = $shakearound->stats->deviceSummary(['uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825', 668 | 'major' => 1002, 669 | 'minor' => 1223, 670 | ], 1425052800, 1425139200); 671 | 672 | /* 返回结果 673 | { 674 | "data": [ 675 | { 676 | "click_pv": 0, 677 | "click_uv": 0, 678 | "ftime": 1425052800, 679 | "shake_pv": 0, 680 | "shake_uv": 0 681 | }, 682 | { 683 | "click_pv": 0, 684 | "click_uv": 0, 685 | "ftime": 1425139200, 686 | "shake_pv": 0, 687 | "shake_uv": 0 688 | } 689 | ], 690 | "errcode": 0, 691 | "errmsg": "success." 692 | } 693 | */ 694 | ``` 695 | 696 | ### 批量查询设备统计数据 697 | 698 | 查询指定时间商家帐号下的每个设备进行摇周边操作的人数、次数,点击摇周边消息的人数、次数。 699 | 700 | > 只能查询最近90天内的数据,且一次只能查询一天。 701 | 702 | > {warning} 注意: 703 | 对于摇周边人数、摇周边次数、点击摇周边消息的人数、点击摇周边消息的次数都为0的设备,不在结果列表中返回。 704 | 705 | 方法 706 | 707 | ```php 708 | $shakearound->stats->devicesSummary(int $timestamp, int $pageIndex) 709 | ``` 710 | 711 | 参数 712 | 713 | > $timestamp 指定查询日期时间戳,单位为秒 714 | $pageIndex 指定查询的结果页序号,返回结果按摇周边人数降序排序,每50条记录为一页 715 | 716 | 示例 717 | 718 | ```php 719 | $result = $shakearound->stats->devicesSummary(1435075200, 1); 720 | 721 | /* 返回结果 722 | { 723 | "data": { 724 | "devices": [ 725 | { 726 | "device_id": 10097, 727 | "major": 10001, 728 | "minor": 12102, 729 | "uuid": "FDA50693-A4E2-4FB1-AFCF-C6EB07647825" 730 | "shake_pv": 1 731 | "shake_uv": 2 732 | "click_pv": 3 733 | "click_uv": 4 734 | }, 735 | { 736 | "device_id": 10098, 737 | "major": 10001, 738 | "minor": 12103, 739 | "uuid": "FDA50693-A4E2-4FB1-AFCF-C6EB07647825" 740 | "shake_pv": 1 741 | "shake_uv": 2 742 | "click_pv": 3 743 | "click_uv": 4 744 | } 745 | ], 746 | }, 747 | "date":1435075200 748 | "total_count": 151 749 | "page_index":1 750 | "errcode": 0, 751 | "errmsg": "success." 752 | } 753 | */ 754 | ``` 755 | 756 | ### 以页面为维度的数据统计 757 | 758 | 查询单个页面通过摇周边摇出来的人数、次数,点击摇周边页面的人数、次数 759 | 760 | > 注意: 761 | 查询的最长时间跨度为30天。只能查询最近90天的数据。 762 | 763 | 方法 764 | 765 | ```php 766 | $shakearound->stats->pageSummary(int $pageId, int $beginDate, int $endDate); 767 | ``` 768 | 769 | 参数 770 | 771 | > $pageId 指定页面的页面ID 772 | $beginDate 起始日期时间戳,最长时间跨度为30天,单位为秒 773 | $endDate 结束日期时间戳,最长时间跨度为30天,单位为秒 774 | 775 | 示例 776 | 777 | ```php 778 | $result = $shakearound->stats->pageSummary(12345, 1425052800, 1425139200); 779 | 780 | /* 返回结果 781 | { 782 | "data": [ 783 | { 784 | "click_pv": 0, 785 | "click_uv": 0, 786 | "ftime": 1425052800, 787 | "shake_pv": 0, 788 | "shake_uv": 0 789 | }, 790 | { 791 | "click_pv": 0, 792 | "click_uv": 0, 793 | "ftime": 1425139200, 794 | "shake_pv": 0, 795 | "shake_uv": 0 796 | } 797 | ], 798 | "errcode": 0, 799 | "errmsg": "success." 800 | } 801 | */ 802 | ``` 803 | ### 批量查询页面统计数据 804 | 805 | 查询指定时间商家帐号下的每个页面进行摇周边操作的人数、次数,点击摇周边消息的人数、次数。 806 | 807 | > {warning} 注意: 808 | 对于摇周边人数、摇周边次数、点击摇周边消息的人数、点击摇周边消息的次数都为0的页面,不在结果列表中返回。 809 | 810 | 方法 811 | 812 | ```php 813 | $shakearound->stats->pagesSummary(int $timestamp, int $pageIndex); 814 | ``` 815 | 816 | 参数 817 | 818 | > $timestamp 指定查询日期时间戳,单位为秒 819 | $pageIndex 指定查询的结果页序号,返回结果按摇周边人数降序排序,每50条记录为一页 820 | 821 | 示例 822 | 823 | ```php 824 | $result = $shakearound->stats->pagesSummary(1435075200, 1); 825 | 826 | /* 返回结果 827 | { 828 | "data": { 829 | "pages": [ 830 | { 831 | "page_id":1234 832 | "click_pv": 1, 833 | "click_uv": 3, 834 | "shake_pv": 0, 835 | "shake_uv": 0 836 | }, 837 | { 838 | "page_id":5678 839 | "click_pv": 1, 840 | "click_uv": 2, 841 | "shake_pv": 0, 842 | "shake_uv": 0 843 | }, 844 | ], 845 | }, 846 | "date":1435075200 847 | "total_count": 151 848 | "page_index":1 849 | "errcode": 0, 850 | "errmsg": "success." 851 | } 852 | */ 853 | ``` 854 | 855 | ## 设备分组管理 856 | 857 | 调用H5页面获取设备信息 JS API接口,需要先把设备分组,微信客户端只会返回已在分组中的设备信息。 858 | 859 | ### 新增分组 860 | 861 | 新建设备分组,每个帐号下最多只有1000个分组。 862 | 863 | 方法 864 | 865 | ```php 866 | $shakearound->group->create(string $name) 867 | 868 | 参数 869 | 870 | > $name 分组名称,不超过100汉字或200个英文字母 871 | 872 | 示例 873 | 874 | ```php 875 | $result = $shakearound->group->create('test'); 876 | 877 | /* 返回结果 878 | { 879 | "data": { 880 | "group_id" : 123, 881 | "group_name" : "test" 882 | }, 883 | "errcode": 0, 884 | "errmsg": "success." 885 | } 886 | */ 887 | ``` 888 | 889 | ### 编辑分组信息 890 | 891 | 编辑设备分组信息,目前只能修改分组名。 892 | 893 | 方法 894 | 895 | > $shakearound->group->update(int $groupId, string $name) 896 | 897 | 参数 898 | 899 | > $groupId 分组唯一标识,全局唯一 900 | $name 分组名称,不超过100汉字或200个英文字母 901 | 902 | 示例 903 | 904 | ```php 905 | $result = $shakearound->group->update(123, 'newName'); 906 | 907 | /* 返回结果 908 | { 909 | "data": { 910 | }, 911 | "errcode": 0, 912 | "errmsg": "success." 913 | } 914 | */ 915 | ``` 916 | 917 | ### 删除分组 918 | 919 | 删除设备分组,若分组中还存在设备,则不能删除成功。需把设备移除以后,才能删除。 920 | 921 | > 在执行删除前,最好先使用 `get` 方法查询分组详情,若分组内有设备,先使用 `removeDevices` 方法移除。 922 | 923 | 方法 924 | 925 | ```php 926 | $shakearound->group->delete(int $groupId) 927 | ``` 928 | 929 | 参数 930 | 931 | > $groupId 分组唯一标识,全局唯一 932 | 933 | 示例 934 | 935 | ```php 936 | $result = $shakearound->group->delete(123); 937 | 938 | /* 返回结果 939 | { 940 | "data": { 941 | }, 942 | "errcode": 0, 943 | "errmsg": "success." 944 | } 945 | */ 946 | ``` 947 | 948 | ### 查询分组列表 949 | 950 | 查询账号下所有的分组。 951 | 952 | 方法 953 | 954 | ```php 955 | $shakearound->group->list(int $begin, int $count) 956 | ``` 957 | 958 | 参数 959 | 960 | > $begin 分组列表的起始索引值 961 | $count 待查询的分组数量,不能超过1000个 962 | 963 | 示例 964 | 965 | ```php 966 | $result = $shakearound->group->list(0, 2); 967 | 968 | /* 返回结果 969 | { 970 | "data": { 971 | "groups":[ 972 | { 973 | "group_id" : 123, 974 | "group_name" : "test1" 975 | }, 976 | { 977 | "group_id" : 124, 978 | "group_name" : "test2" 979 | } 980 | ], 981 | "total_count": 100 982 | }, 983 | "errcode": 0, 984 | "errmsg": "success." 985 | } 986 | */ 987 | ``` 988 | 989 | ### 查询分组详情 990 | 991 | 查询分组详情,包括分组名,分组id,分组里的设备列表。 992 | 993 | 方法 994 | 995 | ```php 996 | $shakearound->group->get(int $groupId, int $begin, int $count) 997 | ``` 998 | 999 | 参数 1000 | 1001 | > $groupId 分组唯一标识,全局唯一 1002 | $begin 分组里设备的起始索引值 1003 | $count 待查询的分组里设备的数量,不能超过1000个 1004 | 1005 | 示例 1006 | 1007 | ```php 1008 | $result = $shakearound->group->get(123, 0, 2); 1009 | 1010 | /* 返回结果 1011 | { 1012 | "data": { 1013 | "group_id" : 123, 1014 | "group_name" : "test", 1015 | "total_count": 100, 1016 | "devices" :[ 1017 | { 1018 | "device_id" : 123456, 1019 | "uuid" : "FDA50693-A4E2-4FB1-AFCF-C6EB07647825", 1020 | "major" : 10001, 1021 | "minor" : 10001, 1022 | "comment" : "test device1", 1023 | "poi_id" : 12345, 1024 | }, 1025 | { 1026 | "device_id" : 123457, 1027 | "uuid" : "FDA50693-A4E2-4FB1-AFCF-C6EB07647825", 1028 | "major" : 10001, 1029 | "minor" : 10002, 1030 | "comment" : "test device2", 1031 | "poi_id" : 12345, 1032 | } 1033 | ] 1034 | }, 1035 | "errcode": 0, 1036 | "errmsg": "success." 1037 | } 1038 | */ 1039 | ``` 1040 | 1041 | ### 添加设备到分组 1042 | 1043 | 添加设备到分组,每个分组能够持有的设备上限为10000,并且每次添加操作的添加上限为1000。 1044 | 1045 | > 只有在摇周边申请的设备才能添加到分组。 1046 | 1047 | 方法 1048 | 1049 | > $shakearound->group->addDevices(int $groupId, array $deviceIdentifiers) 1050 | 1051 | 参数 1052 | 1053 | > $groupId 分组唯一标识,全局唯一 1054 | $deviceIdentifiers 设备id列表 1055 | 1056 | 示例 1057 | 1058 | ```php 1059 | $result = $shakearound->group->addDevices(123, [ 1060 | ['device_id' => 10097], 1061 | ['device_id' => 10098], 1062 | ]); 1063 | 1064 | // 或 1065 | $result = $shakearound->group->addDevices(123, [ 1066 | [ 1067 | 'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825', 1068 | 'major' => 10001, 1069 | 'minor' => 12102, 1070 | ], 1071 | [ 1072 | 'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825', 1073 | 'major' => 10001, 1074 | 'minor' => 12103, 1075 | ] 1076 | ]); 1077 | 1078 | /* 返回结果 1079 | { 1080 | "data": { 1081 | }, 1082 | "errcode": 0, 1083 | "errmsg": "success." 1084 | } 1085 | */ 1086 | ``` 1087 | 1088 | ### 从分组中移除设备 1089 | 1090 | 从分组中移除设备,每次删除操作的上限为 1000。 1091 | 1092 | 方法 1093 | 1094 | ```php 1095 | $shakearound->group->removeDevices(int $groupId, array $deviceIdentifiers) 1096 | ``` 1097 | 1098 | 参数 1099 | 1100 | > $groupId 分组唯一标识,全局唯一 1101 | $deviceIdentifiers 设备id列表 1102 | 1103 | 示例 1104 | 1105 | ```php 1106 | $result = $shakearound->group->removeDevices(123, [ 1107 | ['device_id' => 10097], 1108 | ['device_id' => 10098], 1109 | ]); 1110 | // 或 1111 | $result = $shakearound->group->removeDevices(123, [ 1112 | [ 1113 | 'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825', 1114 | 'major' => 10001, 1115 | 'minor' => 12102, 1116 | ], 1117 | [ 1118 | 'uuid' => 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825', 1119 | 'major' => 10001, 1120 | 'minor' => 12103, 1121 | ] 1122 | ]); 1123 | ``` 1124 | 1125 | ## 摇一摇事件通知 1126 | 1127 | 用户进入摇一摇界面,在“周边”页卡下摇一摇时,微信会把这个事件推送到开发者填写的URL(登录公众平台进入开发者中心设置)。推送内容包含摇一摇时“周边”页卡展示出来的页面所对应的设备信息,以及附近最多五个属于该公众账号的设备的信息。当摇出列表时,此事件不推送。 1128 | 1129 | > 摇一摇事件的事件类型:ShakearoundUserShake 1130 | 1131 | 关于事件的处理请移步: [事件](events) 1132 | 1133 | --------------------------------------------------------------------------------