微信小程序联盟是微信官方的小程序推广后台,
小程序联盟是微信官方提供给小程序商家和推客(推广者)的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 );附件是这次的文件,主要是目录结构:
