admin/addon/weapp/model/Weapp.php

522 lines
19 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* ThinkShop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 成都云之牛科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.cdcloudshop.com
* =========================================================
*/
namespace addon\weapp\model;
use app\model\BaseModel;
use app\model\system\Api;
use EasyWeChat\Factory;
use think\facade\Cache;
use addon\weapp\model\Config as WeappConfigModel;
use addon\wxoplatform\model\Config as WxOplatformConfigModel;
use app\model\web\Config as WebConfig;
/**
* 微信小程序配置
*/
class Weapp extends BaseModel
{
private $app;//微信模型
//小程序类型
public $service_type = array(
0 => "小程序",
);
//小程序认证类型
public $verify_type = array(
-1 => "未认证",
0 => "微信认证",
);
//business_info 说明
public $business_type = array(
'open_store' => "是否开通微信门店功能",
'open_scan' => "是否开通微信扫商品功能",
'open_pay' => "是否开通微信支付功能",
'open_card' => "是否开通微信卡券功能",
'open_shake' => "是否开通微信摇一摇功能",
);
// 站点ID
private $site_id;
public function __construct($site_id = 1)
{
$this->site_id = $site_id;
//微信小程序配置
$weapp_config_model = new WeappConfigModel();
$weapp_config = $weapp_config_model->getWeappConfig($site_id);
$weapp_config = $weapp_config["data"]["value"];
if (isset($weapp_config['is_authopen']) && addon_is_exit('wxoplatform')) {
$plateform_config_model = new WxOplatformConfigModel();
$plateform_config = $plateform_config_model->getOplatformConfig();
$plateform_config = $plateform_config["data"]["value"];
$config = [
'app_id' => $plateform_config["appid"] ?? '',
'secret' => $plateform_config["secret"] ?? '',
'token' => $plateform_config["token"] ?? '',
'aes_key' => $plateform_config["aes_key"] ?? '',
'log' => [
'level' => 'debug',
'permission' => 0777,
'file' => 'runtime/log/wechat/oplatform.logs',
],
];
$open_platform = Factory::openPlatform($config);
$this->app = $open_platform->miniProgram($weapp_config['authorizer_appid'], $weapp_config['authorizer_refresh_token']);
} else {
$config = [
'app_id' => $weapp_config["appid"] ?? '',
'secret' => $weapp_config["appsecret"] ?? '',
'response_type' => 'array',
'log' => [
'level' => 'debug',
'permission' => 0777,
'file' => 'runtime/log/wechat/easywechat.logs',
],
];
$this->app = Factory::miniProgram($config);
}
}
/**
* TODO
* 根据 jsCode 获取用户 session 信息
* @param $param
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
*/
public function authCodeToOpenid($param)
{
try {
$result = $this->app->auth->session($param['code']);
if (isset($result['errcode']) && $result['errcode'] != 0) {
return $this->handleError($result['errcode'], $result['errmsg']);
} else {
Cache::set('weapp_' . $result['openid'], $result);
unset($result['session_key']);
return $this->success($result);
}
} catch (\Exception $e) {
if (property_exists($e, 'formattedResponse')) {
return $this->handleError($e->formattedResponse['errcode'], $e->formattedResponse['errmsg']);
}
return $this->error('', $e->getMessage());
}
}
/**
* 生成二维码
* @param unknown $param
*/
public function createQrcode($param)
{
try {
$checkpath_result = $this->checkPath($param['qrcode_path']);
if ($checkpath_result["code"] != 0) return $checkpath_result;
// scene:场景值最大32个可见字符只支持数字大小写英文以及部分特殊字符!#$&'()*+,/:;=?@-._~
$scene = '';
if (!empty($param['data'])) {
foreach ($param['data'] as $key => $value) {
//防止参数过长source_member用m代替
if($key == 'source_member'){
$key = 'm';
}
if ($scene == '') $scene .= $key . '-' . $value;
else $scene .= '&' . $key . '-' . $value;
}
}
$response = $this->app->app_code->getUnlimit($scene, [
'page' => substr($param['page'], 1),
'width' => isset($param['width']) ? $param['width'] : 120
]);
if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
$filename = $param['qrcode_path'] . '/';
$filename .= $response->saveAs($param['qrcode_path'], $param['qrcode_name'] . '_' . $param['app_type'] . '.png');
return $this->success(['path' => $filename]);
} else {
return $this->handleError($response['errcode'], $response['errmsg']);
}
} catch (\Exception $e) {
if (property_exists($e, 'formattedResponse')) {
return $this->handleError($e->formattedResponse['errcode'], $e->formattedResponse['errmsg']);
}
return $this->error('', $e->getMessage());
}
}
/**
* 校验目录是否可写
* @param unknown $path
* @return multitype:number unknown |multitype:unknown
*/
private function checkPath($path)
{
if (is_dir($path) || mkdir($path, intval('0755', 8), true)) {
return $this->success();
}
return $this->error('', "directory {$path} creation failed");
}
/************************************************************* 数据统计与分析 start **************************************************************/
/**
* 访问日趋势
* @param $from 格式 20170313
* @param $to 格式 20170313
*/
public function dailyVisitTrend($from, $to)
{
try {
$result = $this->app->data_cube->dailyVisitTrend($from, $to);
if (isset($result['errcode']) && $result['errcode'] != 0) {
return $this->error([], $result["errmsg"]);
}
return $this->success($result["list"]);
} catch (\Exception $e) {
return $this->error([], $e->getMessage());
}
}
/**
* 访问周趋势
* @param $from
* @param $to
* @return array|\multitype
*/
public function weeklyVisitTrend($from, $to)
{
try {
$result = $this->app->data_cube->weeklyVisitTrend($from, $to);
if (isset($result['errcode']) && $result['errcode'] != 0) {
return $this->error([], $result["errmsg"]);
}
return $this->success($result["list"]);
} catch (\Exception $e) {
return $this->error([], $e->getMessage());
}
}
/**
* 访问月趋势
* @param $from
* @param $to
* @return array|\multitype
*/
public function monthlyVisitTrend($from, $to)
{
try {
$result = $this->app->data_cube->monthlyVisitTrend($from, $to);
if (isset($result['errcode']) && $result['errcode'] != 0) {
return $this->error([], $result["errmsg"]);
}
return $this->success($result["list"]);
} catch (\Exception $e) {
return $this->error([], $e->getMessage());
}
}
/**
* 访问分布
* @param $from
* @param $to
*/
public function visitDistribution($from, $to)
{
try {
$result = $this->app->data_cube->visitDistribution($from, $to);
if (isset($result['errcode']) && $result['errcode'] != 0) {
return $this->error($result, $result["errmsg"]);
}
return $this->success($result["list"]);
} catch (\Exception $e) {
return $this->error([], $e->getMessage());
}
}
/**
* 访问页面
* @param $from
* @param $to
*/
public function visitPage($from, $to)
{
try {
$result = $this->app->data_cube->visitPage($from, $to);
if (isset($result['errcode']) && $result['errcode'] != 0) {
return $this->error([], $result["errmsg"]);
}
return $this->success($result["list"]);
} catch (\Exception $e) {
return $this->error([], $e->getMessage());
}
}
/************************************************************* 数据统计与分析 end **************************************************************/
/**
* 下载小程序代码包
* @param $site_id
*/
public function download($site_id)
{
$source_file_path = $this->createTempPackage($site_id, 'public/weapp');
$file_arr = getFileMap($source_file_path);
if (!empty($file_arr)) {
$zipname = 'upload/weapp_' . $site_id . '_' . date('Ymd') . '.zip';
$zip = new \ZipArchive();
$res = $zip->open($zipname, \ZipArchive::CREATE);
if ($res === TRUE) {
foreach ($file_arr as $file_path => $file_name) {
if (is_dir($file_path)) {
$file_path = str_replace($source_file_path . '/', '', $file_path);
$zip->addEmptyDir($file_path);
} else {
$zip_path = str_replace($source_file_path . '/', '', $file_path);
$zip->addFile($file_path, $zip_path);
}
}
$zip->close();
header("Content-Type: application/zip");
header("Content-Transfer-Encoding: Binary");
header("Content-Length: " . filesize($zipname));
header("Content-Disposition: attachment; filename=\"" . basename($zipname) . "\"");
readfile($zipname);
@unlink($zipname);
deleteDir($source_file_path);
}
}
}
/**
* 创建临时包
* @param $site_id
* @param $package_path
* @param string $to_path
* @return array
*/
private function createTempPackage($site_id, $package_path, $to_path = '')
{
if (is_dir($package_path)) {
$package = scandir($package_path);
if (empty($to_path)) {
$to_path = 'upload/temp/' . $site_id . '/';
dir_mkdir($to_path);
}
foreach ($package as $path) {
$temp_path = $package_path . '/' . $path;
if (is_dir($temp_path)) {
if ($path == '.' || $path == '..') {//判断是否为系统隐藏的文件.和.. 如果是则跳过否则就继续往下走,防止无限循环再这里。
continue;
}
dir_mkdir($to_path . $path);
$this->createTempPackage($site_id, $temp_path, $to_path . $path . '/');
} else {
if (file_exists($temp_path)) {
copy($temp_path, $to_path . $path);
if (stristr($temp_path, 'common/vendor.js')) {
$content = file_get_contents($to_path . $path);
$content = $this->paramReplace($site_id, $content);
file_put_contents($to_path . $path, $content);
}
}
}
}
return $to_path;
}
}
/**
* 参数替换
* @param $site_id
* @param $string
* @return null|string|string[]
*/
private function paramReplace($site_id, $string)
{
$api_model = new Api();
$api_config = $api_model->getApiConfig();
$api_config = $api_config['data'];
$web_config_model = new WebConfig();
$web_config = $web_config_model ->getMapConfig();
$web_config = $web_config['data']['value'];
$socket_url = (strstr(ROOT_URL, 'https://') === false ? str_replace('http', 'ws', ROOT_URL) : str_replace('https', 'wss', ROOT_URL)) . '/wss';
$patterns = [
'/\{\{\$baseUrl\}\}/',
'/\{\{\$imgDomain\}\}/',
'/\{\{\$h5Domain\}\}/',
'/\{\{\$mpKey\}\}/',
'/\{\{\$apiSecurity\}\}/',
'/\{\{\$publicKey\}\}/',
'/\{\{\$webSocket\}\}/'
];
$replacements = [
ROOT_URL,
ROOT_URL,
ROOT_URL . '/h5',
$web_config['tencent_map_key'] ?? '',
$api_config['is_use'] ?? 0,
$api_config['value']['public_key'] ?? '',
$socket_url
];
$string = preg_replace($patterns, $replacements, $string);
return $string;
}
/**
* 消息解密
* @param array $param
*/
public function decryptData($param = [])
{
try {
$cache = Cache::get('weapp_' . $param['weapp_openid']);
$session_key = $cache['session_key'] ?? '';
$result = $this->app->encryptor->decryptData($session_key, $param['iv'], $param['encryptedData']);
if (isset($result['errcode']) && $result['errcode'] != 0) {
return $this->handleError($result['errcode'], $result['errmsg']);
}
return $this->success($result);
} catch (\Exception $e) {
if (property_exists($e, 'formattedResponse')) {
return $this->handleError($e->formattedResponse['errcode'], $e->formattedResponse['errmsg']);
}
return $this->error([], $e->getMessage());
}
}
/**
* 获取订阅消息template_id
* @param array $param
*/
public function getTemplateId(array $param){
try {
$result = $this->app->subscribe_message->addTemplate($param['tid'], $param['kidList'], $param['sceneDesc']);
return $result;
} catch (\Exception $e) {
return ['errcode' => -1, 'errmsg' => $e->getMessage()];
}
}
/**
* 发送订阅消息
* @param array $param
* @return array
*/
public function sendTemplateMessage(array $param){
$result = $this->app->subscribe_message->send([
'template_id' => $param['template_id'],// 模板id
'touser' => $param['openid'], // openid
'page' => $param['page'], // 点击模板卡片后的跳转页面 支持带参数
'data' => $param['data'] // 模板变量
]);
if (isset($result['errcode']) && $result['errcode'] != 0) {
return $this->error($result, $result["errmsg"]);
}
return $this->success($result);
}
/**
* 消息推送
*/
public function relateWeixin(){
$server = $this->app->server;
$message = $server->getMessage();
if (isset($message['MsgType'])) {
switch ($message['MsgType']) {
case 'event':
$this->app->server->push(function ($res) {
// 商品审核结果通知
if ($res['Event'] == 'open_product_spu_audit' && addon_is_exit('shopcomponent', $this->site_id)) {
model('shopcompoent_goods')->update([
'edit_status' => $res['OpenProductSpuAudit']['status'],
'reject_reason' => !empty($res['OpenProductSpuAudit']['reject_reason']) ?: '',
'audit_time' => time()
], [
['out_product_id', '=', $res['OpenProductSpuAudit']['out_product_id'] ]
]);
}
// 类目审核结果通知
if ($res['Event'] == 'open_product_category_audit' && addon_is_exit('shopcomponent', $this->site_id)) {
model('shopcompoent_category_audit')->update([
'status' => $res['QualificationAuditResult']['status'],
'reject_reason' => !empty($res['QualificationAuditResult']['reject_reason']) ?: '',
'audit_time' => time()
], [
['audit_id', '=', $res['QualificationAuditResult']['audit_id'] ]
]);
}
// 视频号支付订单回调
if ($res['Event'] == 'open_product_order_pay' && addon_is_exit('shopcomponent', $this->site_id)) {
event("shopcomponentNotify", $res);
}
});
break;
}
}
$response = $this->app->server->serve();
return $response->send();
}
/**
* 检查场景值是否在支付校验范围内
* @param $scene
* @return array
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function sceneCheck($scene){
try {
$result = $this->app->mini_store->checkScene($scene);
if (isset($result['errcode']) && $result['errcode'] == 0) {
return $this->success($result['is_matched']);
} else {
return $this->error('', $result['errmsg']);
}
} catch (\Exception $e) {
return $this->error([], $e->getMessage());
}
}
public function createOrder($order_info){
try {
$result = $this->app->mini_store->addOrder($order_info);
if (isset($result['errcode']) && $result['errcode'] == 0) {
return $this->success($result['is_matched']);
} else {
return $this->error('', $result['errmsg']);
}
} catch (\Exception $e) {
return $this->error([], $e->getMessage());
}
}
/**
* 处理错误信息
* @param $errcode
* @param string $message
* @return array
*/
public function handleError($errcode, $message = ''){
$error = require 'addon/weapp/config/weapp_error.php';
return $this->error([], $error[ $errcode ] ?? $message);
}
}