Files
2026-09-01 22:15:50 +08:00

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;
}
}