352 lines
10 KiB
PHP
352 lines
10 KiB
PHP
<?php
|
|
// +----------------------------------------------------------------------
|
|
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
|
|
// +----------------------------------------------------------------------
|
|
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
|
|
// +----------------------------------------------------------------------
|
|
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
|
|
// +----------------------------------------------------------------------
|
|
// | Author: 萤火科技 <admin@yiovo.com>
|
|
// +----------------------------------------------------------------------
|
|
declare (strict_types=1);
|
|
|
|
namespace app\store\controller;
|
|
|
|
use app\common\crypto\Crypto;
|
|
use app\store\model\store\User;
|
|
use cores\BaseController;
|
|
use app\store\service\Auth as AuthService;
|
|
use app\common\service\store\User as StoreUserService;
|
|
use app\common\exception\BaseException;
|
|
use think\response\Json;
|
|
use think\Session;
|
|
|
|
use app\common\service\SybOil;
|
|
|
|
/**
|
|
* 商户后台控制器基类
|
|
* Class Controller
|
|
* @package app\store\controller
|
|
*/
|
|
class Controller extends BaseController
|
|
{
|
|
// 商家登录信息
|
|
protected $store;
|
|
|
|
// 当前商城ID
|
|
protected $storeId;
|
|
|
|
// 当前控制器名称
|
|
protected $controller = '';
|
|
|
|
// 当前方法名称
|
|
protected $action = '';
|
|
|
|
// 当前路由uri
|
|
protected $routeUri = '';
|
|
|
|
// 当前路由:分组名称
|
|
protected $group = '';
|
|
|
|
// 登录验证白名单
|
|
protected $allowAllAction = [
|
|
'passport/login',
|
|
'passport/logout',
|
|
'passport/detail',
|
|
'merchant/all',
|
|
];
|
|
|
|
/**
|
|
* 强制验证当前访问的控制器方法method
|
|
* 例: [ 'login' => 'POST' ]
|
|
* @var array
|
|
*/
|
|
protected $methodRules = [];
|
|
|
|
/**
|
|
* 后台初始化
|
|
* @throws BaseException
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
public function initialize()
|
|
{
|
|
// 当前商城id
|
|
$this->storeId = $this->getStoreId();
|
|
// 设置管理员登录信息
|
|
$this->setStoreInfo();
|
|
// 当前路由信息
|
|
$this->getRouteInfo();
|
|
// 验证登录状态
|
|
$this->checkLogin();
|
|
// 验证当前API权限
|
|
$this->checkPrivilege();
|
|
// 强制验证当前访问的控制器方法method
|
|
$this->checkMethodRules();
|
|
}
|
|
|
|
/**
|
|
* 设置管理员登录信息
|
|
*/
|
|
private function setStoreInfo()
|
|
{
|
|
$this->store = StoreUserService::getLoginInfo();
|
|
}
|
|
|
|
/**
|
|
* 验证当前路由权限
|
|
* @return bool
|
|
* @throws BaseException
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
private function checkPrivilege(): bool
|
|
{
|
|
// 在开发模式下, 建议把此处代码暂时屏蔽, 开发完成后在超管后台新增菜单和api
|
|
if (!AuthService::getInstance()->checkPrivilege('/' . $this->routeUri)) {
|
|
throwError('很抱歉,没有当前api的访问权限 ' . $this->routeUri);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 解析当前路由参数 (分组名称、控制器名称、方法名)
|
|
*/
|
|
protected function getRouteInfo()
|
|
{
|
|
// 控制器名称
|
|
$this->controller = uncamelize($this->request->controller());
|
|
// 方法名称
|
|
$this->action = $this->request->action();
|
|
// 控制器分组 (用于定义所属模块)
|
|
$group = strstr($this->controller, '.', true);
|
|
$this->group = $group !== false ? $group : $this->controller;
|
|
// 当前uri
|
|
$this->routeUri = "{$this->controller}/$this->action";
|
|
}
|
|
|
|
/**
|
|
* 验证登录状态
|
|
* @return bool
|
|
* @throws BaseException
|
|
*/
|
|
private function checkLogin(): bool
|
|
{
|
|
// 验证当前请求是否在白名单
|
|
if (in_array($this->routeUri, $this->allowAllAction)) {
|
|
return true;
|
|
}
|
|
// 验证登录状态
|
|
if (empty($this->store) || (int)$this->store['is_login'] !== 1) {
|
|
throwError('请先登录后再访问', config('status.not_logged'));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 获取当前store_id
|
|
* @return int|null
|
|
*/
|
|
protected function getStoreId(): ?int
|
|
{
|
|
// app/store/common.php
|
|
return getStoreId();
|
|
}
|
|
|
|
/**
|
|
* 返回封装后的 API 数据到客户端
|
|
* @param int|null $status 状态码
|
|
* @param string $message
|
|
* @param array $data
|
|
* @return Json
|
|
*/
|
|
protected function renderData(int $status = null, string $message = '', array $data = []): Json
|
|
{
|
|
is_null($status) && $status = config('status.success');
|
|
return json(compact('status', 'message', 'data'));
|
|
}
|
|
|
|
/**
|
|
* 返回操作成功json
|
|
* @param array|string $data
|
|
* @param string $message
|
|
* @return Json
|
|
*/
|
|
protected function renderSuccess($data = [], string $message = 'success'): Json
|
|
{
|
|
if (is_string($data)) {
|
|
$message = $data;
|
|
$data = [];
|
|
}
|
|
return $this->renderData(config('status.success'), $message, $data);
|
|
}
|
|
|
|
/**
|
|
* 返回操作失败json
|
|
* @param string $message
|
|
* @param array $data
|
|
* @return Json
|
|
*/
|
|
protected function renderError(string $message = 'error', array $data = []): Json
|
|
{
|
|
return $this->renderData(config('status.error'), $message, $data);
|
|
}
|
|
|
|
/**
|
|
* 获取post数据 (数组)
|
|
* @param $key
|
|
* @return mixed
|
|
*/
|
|
protected function postData($key = null)
|
|
{
|
|
return $this->request->post(empty($key) ? '' : "{$key}/a");
|
|
}
|
|
|
|
/**
|
|
* 获取post数据 (数组)
|
|
* @param string $key
|
|
* @return mixed
|
|
*/
|
|
protected function postForm(string $key = 'form')
|
|
{
|
|
return $this->postData($key);
|
|
}
|
|
|
|
/**
|
|
* 获取post数据 (数组)
|
|
* @param $key
|
|
* @return mixed
|
|
*/
|
|
protected function getData($key = null)
|
|
{
|
|
return $this->request->get(is_null($key) ? '' : $key);
|
|
}
|
|
|
|
/**
|
|
* 强制验证当前访问的控制器方法method
|
|
* @return bool
|
|
* @throws BaseException
|
|
*/
|
|
private function checkMethodRules(): bool
|
|
{
|
|
if (!isset($this->methodRules[$this->action])) {
|
|
return true;
|
|
}
|
|
$methodRule = $this->methodRules[$this->action];
|
|
$currentMethod = $this->request->method();
|
|
if (empty($methodRule)) {
|
|
return true;
|
|
}
|
|
if (is_array($methodRule) && in_array($currentMethod, $methodRule)) {
|
|
return true;
|
|
}
|
|
if (is_string($methodRule) && $methodRule == $currentMethod) {
|
|
return true;
|
|
}
|
|
throwError('illegal request method');
|
|
return false;
|
|
}
|
|
|
|
public function mk_dir_store($dir, $mode = 0777)
|
|
{
|
|
if (is_dir($dir) || @mkdir($dir,$mode)) return true;
|
|
if (!$this->mk_dir_store(dirname($dir),$mode)) return false;
|
|
return @mkdir($dir,$mode);
|
|
}
|
|
|
|
/** 记录日志
|
|
* @param $data
|
|
*/
|
|
public function saveLogStore($data){
|
|
$SybOil = new SybOil();
|
|
$SybOil->saveLogStore($data);
|
|
}
|
|
|
|
public function sendRequest($company, $url, $businessParams = [], $appendHeaders = [], $file = null)
|
|
{
|
|
$crypto = new Crypto($company);
|
|
// 签名并组合header,并加密数据
|
|
$this->saveLogStore(json_encode($businessParams,320));
|
|
$requestData = $crypto->prepareRequest($appendHeaders, $businessParams);
|
|
$businessParams = $requestData['encryptData'];
|
|
// 构建默认的公共参数头
|
|
$headers = [];
|
|
foreach ($requestData['header'] as $k=>$val){
|
|
$headers[] = $k.': '.$val;
|
|
}
|
|
$this->saveLogStore(json_encode($requestData['header'],320));
|
|
$this->saveLogStore(json_encode($businessParams,320));
|
|
// 使用 cURL 发送请求
|
|
$ch = curl_init();
|
|
|
|
// 设置请求 URL
|
|
curl_setopt($ch, CURLOPT_URL, $url);
|
|
|
|
// 设置请求方式为 POST
|
|
curl_setopt($ch, CURLOPT_POST, true);
|
|
|
|
// 返回结果而不是输出
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
|
|
// 包含响应头在输出中
|
|
curl_setopt($ch, CURLOPT_HEADER, true);
|
|
|
|
$headers[] = 'Charset: UTF-8';
|
|
if ($file) {
|
|
// 如果有文件上传,设置 multipart/form-data 表单
|
|
$filePath = $file->getPathname();
|
|
$fileName = $file->getOriginalName();
|
|
$fileMime = $file->getMimeType();
|
|
$postFields = [
|
|
'file' => new \CURLFile($filePath, $fileMime, $fileName),
|
|
'businessParams' => json_encode($businessParams, JSON_UNESCAPED_UNICODE),
|
|
];
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
|
|
} else {
|
|
// 如果没有文件上传,直接发送业务参数的 JSON 数据
|
|
$postFields = json_encode($businessParams, JSON_UNESCAPED_UNICODE);
|
|
$headers[] = 'Content-Type: application/json';
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
|
|
}
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
|
|
|
// 执行请求
|
|
$response = curl_exec($ch);
|
|
$this->saveLogStore('接口返回值:'.$response);
|
|
// 检查是否有错误
|
|
if (curl_errno($ch)) {
|
|
$error_msg = curl_error($ch);
|
|
curl_close($ch);
|
|
return ['code' => '01', 'message' => $error_msg];
|
|
}
|
|
|
|
// 获取响应头大小
|
|
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
|
|
|
// 分离响应头和响应体
|
|
$headerString = substr($response, 0, $header_size);
|
|
$bodyString = substr($response, $header_size);
|
|
|
|
// 关闭 cURL 句柄
|
|
curl_close($ch);
|
|
|
|
// 解析响应头为数组
|
|
$headerArray = [];
|
|
foreach (explode("\r\n", $headerString) as $header) {
|
|
if (trim($header) !== '' && strpos($header, ':') !== false) {
|
|
list($key, $value) = explode(': ', $header, 2);
|
|
$headerArray[strtolower(trim($key))] = trim($value);
|
|
}
|
|
}
|
|
$res = $crypto->processResponse(['header'=>$headerArray,'encryptData'=>json_decode($bodyString, true)]);
|
|
if(!$res){
|
|
return ['code' => '01', 'message' => $bodyString];
|
|
}
|
|
// 返回结果
|
|
return $res;
|
|
}
|
|
|
|
}
|