微信小程序联盟是微信官方的小程序推广后台,
小程序联盟是微信官方提供给小程序商家和推客(推广者)的CPS推广工具。其具有“先成交后付费”的特点,商家在管理后台发布商品推广需求和佣金,佣金在推广者成功完成推广后才会结算。
<?php namespace wbs\xcx\union; /** * 微信小程序联盟 * @author blog.alipay168.cn * Class UnionXcx * @package wbs\xcx\union * * @notice 注意事项,runtime需要写权限,作为日志和临时数据存放,也可以自定义修改 */ class UnionXcx { /** * @var string 推广位 */ private $pid = ''; /** * 接口基础 * @var string */ private $uri_base = 'https://api.weixin.qq.com'; /** * 登录联盟推客管理后台,点击左侧导航栏里【账号设置】, * 获取推客账号appID及appsecret(appsecret需要账号超级管理员微信扫码获取); * appid * @var string */ private $appid = ''; /** * 登录联盟推客管理后台,点击左侧导航栏里【账号设置】, * 获取推客账号appID及appsecret(appsecret需要账号超级管理员微信扫码获取); * 小appSecret * @var string */ private $secret = ''; /** * 临时存储数据和日志的目录 * @var string */ public $dir_runtime = ''; public function __construct($config) { $this->appid = $config['appid']; $this->secret = $config['secret']; $this->pid = $config['pid']; $this->dir_runtime = !empty($config['runtime']) ? $config['runtime'] : __DIR__ . '/../runtime/'; if (!is_dir($this->dir_runtime)) { @mkdir($this->dir_runtime, 0644, true); } } /** * 发起post请求 * @param $url * @param $data array|string * @param array $headers * @return array|bool|float|int|mixed|\stdClass|string|null */ protected function curl_post($url, $data, $headers = []) { if (!empty($headers)) { $headers = array_merge($headers, ['content-type: application/json']); } else { $headers = ['content-type: application/json']; } $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_POSTFIELDS, $data); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);//测试时禁用 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);//测试时禁用 //curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); //curl_setopt($curl, CURLOPT_REFERER, $url); if (!empty($headers)) { curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); } $response = curl_exec($curl); $error = curl_error($curl); return $error ? $error : $response; } /** * 发起post请求 * @param $url * @param array $data array * @param array $headers * @return array|bool|float|int|mixed|\stdClass|string|null */ protected function curl_get($url, $data = [], $headers = []) { if (!empty($data)) { if (stripos($url, '?') === false) { $url = $url . '?' . http_build_query($data); } else { $url = $url . '&' . http_build_query($data); } } if (!empty($headers)) { $headers = array_merge($headers, ['content-type: application/json']); } else { $headers = ['content-type: application/json']; } $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_POST, 0); curl_setopt($curl, CURLOPT_HEADER, 0); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE); if (!empty($headers)) { curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); } $response = curl_exec($curl); $error = curl_error($curl); return $error ? $error : $response; } /** * 获取access_token * @return string|array */ public function get_access_token() { $tokenFile = $this->dir_runtime . 'data/access_token'; if (file_exists($tokenFile)) { $info = @json_decode(file_get_contents($tokenFile), true); //有效直接返回 if (!empty($info['expire']) && $info['expire'] > time()) { return $info['token']; } } $url = $this->uri_base . '/cgi-bin/token?grant_type=client_credential&appid=' . $this->appid . '&secret=' . $this->secret; $res = $this->curl_get($url, ''); $ret = json_decode($res, true); if ((!is_dir($this->dir_runtime) && @mkdir($this->dir_runtime, 0644, true)) || !is_writable($this->dir_runtime)) { exit($this->dir_runtime . '目录需要写入权限'); } if (!empty($ret['errcode'])) { //日志记录 if (!is_dir($this->dir_runtime . 'log/')) { @mkdir($this->dir_runtime . 'log/', 0644, true); } @file_put_contents($this->dir_runtime . 'log/' . date('Ymd') . '_err.log', $res . PHP_EOL, FILE_APPEND); exit('获取accessToken失败:' . $ret['errmsg']); //return ['code' => -1, 'msg' => $ret['errmsg']]; } if (!is_dir($this->dir_runtime . 'data/')) { @mkdir($this->dir_runtime . 'data/', 0644, true); } @file_put_contents($this->dir_runtime . 'data/access_token', json_encode([ 'expire' => time() + 7000,//提前200秒 'token' => $ret['access_token'] ])); return $ret['access_token']; } /** * 添加推广位 * @param $name string 推广位名称,如宅家推广 * @return array */ public function promotion_add($name) { $data = json_encode([ 'promotionSourceName' => $name ], JSON_UNESCAPED_UNICODE); $access_token = $this->get_access_token(); $res = $this->curl_post($this->uri_base . '/union/promoter/promotion/add?access_token=' . $access_token, $data); $ret = json_decode($res, true); if (!empty($ret['errcode'])) { return ['code' => -1, 'msg' => $ret['errmsg']]; } return ['code' => 0, 'msg' => 'success', 'pid' => $ret['pid']]; } /** * 删除某个推广位 * @param $pid string 推广位字符串 * @param $name string 推广位名称 * @return array */ public function promotion_del($pid, $name) { $data = json_encode([ 'promotionSourcePid' => $pid, 'promotionSourceName' => $name, ], JSON_UNESCAPED_UNICODE); $access_token = $this->get_access_token(); $res = $this->curl_post($this->uri_base . '/union/promoter/promotion/del?access_token=' . $access_token, $data); $ret = json_decode($res, true); if (!empty($ret['errcode'])) { return ['code' => -1, 'msg' => $ret['errmsg']]; } return ['code' => 0, 'msg' => 'success']; } /** * 更新推广位 * @param $pid string 推广位字符串 * @param $oldName string 推广位名称(修改前名称) * @param $newName string 新推广位名称 * @return array */ public function promotion_udp($pid, $oldName, $newName) { $data = json_encode([ 'previousPromotionInfo' => [ 'promotionSourcePid' => $pid, 'promotionSourceName' => $oldName, ], 'promotionInfo' => [ 'promotionSourceName' => $newName ] ], JSON_UNESCAPED_UNICODE); $access_token = $this->get_access_token(); $res = $this->curl_post($this->uri_base . '/union/promoter/promotion/upd?access_token=' . $access_token, $data); $ret = json_decode($res, true); if (!empty($ret['errcode'])) { return ['code' => -1, 'msg' => $ret['errmsg']]; } return ['code' => 0, 'msg' => 'success']; } /** * 获取推广位列表 * @param int $start * @param int $limit * @return array */ public function promotion_list($start = 0, $limit = 20) { $data = [ 'start' => $start, 'limit' => $limit ]; $access_token = $this->get_access_token(); $res = $this->curl_get($this->uri_base . '/union/promoter/promotion/list?access_token=' . $access_token, $data); $ret = json_decode($res, true); if (!empty($ret['errcode'])) { return ['code' => -1, 'msg' => $ret['errmsg']]; } return [ 'code' => 0, 'msg' => 'success', 'list' => $ret['promotionSourceList'],//推广位数据 'total' => $ret['total'],//推广位总数 'limitMaxCount' => $ret['promotionMaxCnt'],//允许创建的推广位最大数量 ]; } /** * 获取联盟商品类目列表及类目ID * @return array */ public function product_category() { $access_token = $this->get_access_token(); $res = $this->curl_get($this->uri_base . '/union/promoter/product/category?access_token=' . $access_token, ''); $ret = json_decode($res, true); if (!empty($ret['errcode'])) { return ['code' => -1, 'msg' => $ret['errmsg']]; } return [ 'code' => 0, 'msg' => 'success', 'list' => $ret['productCats'],//类目数据 ]; } /** * 查询商品详情信息 * 支持根据多种筛选条件获取可供推广的商品列表及详情,筛选条件包括商品关键词(名称、店铺、spuID)、商品价格、商品佣金、佣金比例、是否含有联盟券 * @param array $args 请求参数 * @return array */ public function product_list($args = []) { $param = [ 'from' => !empty($args['page']) ? intval($args['page']) : 1, 'limit' => !empty($args['limit']) ? intval($args['limit']) : 20, //0-搜索商品名称,1-搜索小商店名称;2-搜索商品SPU ID 'queryType' => isset($args['queryType']) ? intval($args['queryType']) : 0, ]; //商品最高价格,单位分 if (!empty($args['maxPrice'])) { $param['maxPrice'] = intval($args['maxPrice']); } //商品最低价格,单位分 if (!empty($args['minPrice'])) { $param['minPrice'] = intval($args['minPrice']); } //佣金金额下限,单位分 if (!empty($args['minCommissionValue'])) { $param['minCommissionValue'] = intval($args['minCommissionValue']); } //佣金比例下限,单位万分之一 if (!empty($args['minCommissionRatio'])) { $param['minCommissionRatio'] = intval($args['minCommissionRatio']); } /**排序 * 0 -默认排序 * 1 -商品价格升序 * 2 -商品价格降序 * 3 -佣金比例升序 * 4 -佣金比例降序 * 5 -佣金数值升序 * 6 -佣金数值降序 */ if (isset($args['sortType'])) { $param['sortType'] = intval($args['sortType']); } //类目ID,值来自获取类目列表接口 if (!empty($args['categoryId'])) { $param['categoryId'] = intval($args['categoryId']); } //是否有联盟券:0-无,1-有 if (!empty($args['hasCoupon'])) { $param['hasCoupon'] = intval($args['hasCoupon']); } //商品SPUID,多个用英文逗号分隔 if (!empty($args['productId'])) { $param['productId'] = trim($args['productId']); } //商品类目ID,多个用英文逗号分隔 if (!empty($args['category'])) { $param['category'] = trim($args['category']); } //黑名单类目ID,不拉出黑名单类目商品,多个用英文逗号分隔 if (!empty($args['noCategory'])) { $param['noCategory'] = trim($args['noCategory']); } //小商店AppID列表--array if (!empty($args['shopAppIds'])) { $param['shopAppIds'] = json_encode($args['shopAppIds']); } $access_token = $this->get_access_token(); $res = $this->curl_get($this->uri_base . '/union/promoter/product/list?access_token=' . $access_token, $param); $ret = json_decode($res, true); if (!empty($ret['errcode'])) { return ['code' => -1, 'msg' => $ret['errmsg']]; } return [ 'code' => 0, 'msg' => 'success', 'list' => $ret['productList'],//商品列表数据 'total' => $ret['total'],//商品总数 ]; } /** * 根据订单ID查询订单详情 * @param $orderIdList array 订单数组 * @return array */ public function order_info($orderIdList) { $data = [ 'orderIdList' => json_encode($orderIdList) ]; $access_token = $this->get_access_token(); $res = $this->curl_get($this->uri_base . '/union/promoter/order/info?access_token=' . $access_token, $data); $ret = json_decode($res, true); if (!empty($ret['errcode'])) { return ['code' => -1, 'msg' => $ret['errmsg']]; } return [ 'code' => 0, 'msg' => 'success', 'list' => $ret['orderList'], ]; } /** * 根据订单支付时间、订单分佣状态拉取订单详情 * @param array $args * @return array */ public function order_search($args = []) { $param = [ 'page' => !empty($args['page']) ? intval($args['page']) : 1, ]; //起始时间戳,单位为秒 if (!empty($args['startTimestamp'])) { $param['startTimestamp'] = $args['startTimestamp']; } //结束时间戳,单位为秒 if (!empty($args['endTimestamp'])) { $param['endTimestamp'] = $args['endTimestamp']; } //分佣状态:SETTLEMENT_PENDING-待结算;SETTLEMENT_SUCCESS-已结算;SETTLEMENT_CANCELED -取消结算 if (!empty($args['commissionStatus'])) { $param['commissionStatus'] = trim($args['commissionStatus']); } $access_token = $this->get_access_token(); $res = $this->curl_get($this->uri_base . '/union/promoter/order/search?access_token=' . $access_token, $param); $ret = json_decode($res, true); if (!empty($ret['errcode'])) { return ['code' => -1, 'msg' => $ret['errmsg']]; } return [ 'code' => 0, 'msg' => 'success', 'list' => $ret['orderList'], 'pageSize' => $ret['pageSize'], 'totalNum' => $ret['totalNum'], ]; } }
实例操作:
<?php require ("../union/UnionXcx.php"); $config = [ 'appid'=>'', 'secret'=>'', 'pid'=>'', 'runtime'=> RUNTIME_PATH.'union_xcx/', ]; $union = new \wbs\xcx\union\UnionXcx($config); $data = $union->promotion_list(); print_r($data );
附件是这次的文件,主要是目录结构: