1242 lines
34 KiB
PHP
1242 lines
34 KiB
PHP
<?php
|
||
|
||
// 应用公共文件
|
||
|
||
// 数族分组
|
||
use app\exception\TokenException;
|
||
use EasySwoole\Jwt\Jwt;
|
||
|
||
function getArrayGroupBy($data, $key): array
|
||
{
|
||
$result = [];
|
||
|
||
foreach ($data as $value) {
|
||
if (array_key_exists($key, $value)) {
|
||
$groupValue = $value[$key];
|
||
if (!array_key_exists($groupValue, $result)) {
|
||
$result[$groupValue] = array();
|
||
}
|
||
$result[$groupValue][] = $value;
|
||
}
|
||
}
|
||
|
||
return $result;
|
||
}
|
||
|
||
function strToUtf8($str)
|
||
{
|
||
|
||
$encode = mb_detect_encoding($str, array('CP936', "ASCII", "GB2312", "GBK", 'UTF-8', 'BIG5'));
|
||
|
||
if ($encode == 'UTF-8') {
|
||
|
||
return $str;
|
||
|
||
} else {
|
||
|
||
return mb_convert_encoding($str, 'UTF-8', $encode);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* 对富文本信息中的数据
|
||
* 匹配出所有的 <img> 标签的 src属性
|
||
* @param string $contentStr 富文本字符串
|
||
* @return array
|
||
*
|
||
*/
|
||
function getPatternMatchImages(string $contentStr = ''): array
|
||
{
|
||
$imgSrcArr = [];
|
||
//首先将富文本字符串中的 img 标签进行匹配
|
||
$pattern_imgTag = '/<img\b.*?(?:\>|\/>)/i';
|
||
preg_match_all($pattern_imgTag, $contentStr, $matchIMG);
|
||
if (isset($matchIMG[0])) {
|
||
foreach ($matchIMG[0] as $key => $imgTag) {
|
||
//进一步提取 img标签中的 src属性信息
|
||
$pattern_src = '/\bsrc\b\s*=\s*[\'\"]?([^\'\"]*)[\'\"]?/i';
|
||
preg_match_all($pattern_src, $imgTag, $matchSrc);
|
||
if (isset($matchSrc[1])) {
|
||
foreach ($matchSrc[1] as $src) {
|
||
//将匹配到的src信息压入数组
|
||
$imgSrcArr[] = $src;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
//$pattern= '/<img\b.+\bsrc\b\s*=\s*[\'\"]([^\'\"]*)[\'\"]/iU';
|
||
return $imgSrcArr;
|
||
}
|
||
|
||
|
||
// 获取文件夹下文件数量
|
||
function getFileNumber($path): int
|
||
{
|
||
$handle = opendir($path);
|
||
$i = 0;
|
||
while (false !== $file = (readdir($handle))) {
|
||
if ($file !== '.' && $file != '..') {
|
||
$i++;
|
||
}
|
||
}
|
||
closedir($handle);
|
||
return $i;
|
||
}
|
||
|
||
// 手机版访问
|
||
function isMobile(): bool
|
||
{
|
||
return request()->isMobile();
|
||
}
|
||
|
||
// 按照字符串个数切割字符串
|
||
function hcSubstr($str, $len, $start = 0): string
|
||
{
|
||
if (empty($str)) {
|
||
return '';
|
||
}
|
||
//返回字符串中的前100字符串长度的字符
|
||
return mb_substr($str, $start, $len, 'utf-8');
|
||
}
|
||
|
||
// sql切割
|
||
function hcSplitSql($file, $prefix, $charset = 'utf8mb4', $defaultTablePre = '$prefix$', $defaultCharset = 'utf8mb4')
|
||
{
|
||
if (file_exists($file)) {
|
||
//读取SQL文件
|
||
$sql = file_get_contents($file);
|
||
$sql = str_replace("\r", "\n", $sql);
|
||
$sql = str_replace("BEGIN;\n", '', $sql);//兼容 navicat 导出的 insert 语句
|
||
$sql = str_replace("COMMIT;\n", '', $sql);//兼容 navicat 导出的 insert 语句
|
||
$sql = str_replace($defaultCharset, $charset, $sql);
|
||
$sql = trim($sql);
|
||
//替换表前缀
|
||
$sql = str_replace("{$defaultTablePre}", "{$prefix}", $sql);
|
||
$sqls = explode(";\n", $sql);
|
||
return $sqls;
|
||
}
|
||
|
||
return [];
|
||
}
|
||
|
||
function sp_testwrite($d)
|
||
{
|
||
$tfile = "_test.txt";
|
||
$fp = @fopen($d . "/" . $tfile, "w");
|
||
if (!$fp) {
|
||
return false;
|
||
}
|
||
fclose($fp);
|
||
$rs = @unlink($d . "/" . $tfile);
|
||
if ($rs) {
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
function sp_dir_create($path, $mode = 0777)
|
||
{
|
||
if (is_dir($path))
|
||
return true;
|
||
$ftp_enable = 0;
|
||
$path = sp_dir_path($path);
|
||
$temp = explode('/', $path);
|
||
$cur_dir = '';
|
||
$max = count($temp) - 1;
|
||
for ($i = 0; $i < $max; $i++) {
|
||
$cur_dir .= $temp[$i] . '/';
|
||
if (@is_dir($cur_dir))
|
||
continue;
|
||
@mkdir($cur_dir, 0777, true);
|
||
@chmod($cur_dir, 0777);
|
||
}
|
||
return is_dir($path);
|
||
}
|
||
|
||
function sp_dir_path($path)
|
||
{
|
||
$path = str_replace('\\', '/', $path);
|
||
if (substr($path, -1) != '/')
|
||
$path = $path . '/';
|
||
return $path;
|
||
}
|
||
|
||
function sp_execute_sql($db, $sql)
|
||
{
|
||
$sql = trim($sql);
|
||
if (substr($sql, 0, 12) == 'CREATE TABLE') {
|
||
$table_name = preg_replace("/^CREATE TABLE `(\w+)` .*/s", "\\1", $sql);;
|
||
$msg = "创建数据表 {$table_name} ";
|
||
try {
|
||
$db->execute($sql);
|
||
return [
|
||
'type' => 1, // 创建表
|
||
'error' => 0,
|
||
'message' => $msg . '成功!'
|
||
];
|
||
} catch (\Exception $e) {
|
||
return [
|
||
'type' => 1, // 创建表
|
||
'error' => 1,
|
||
'message' => $msg . '失败!',
|
||
'exception' => $e->getMessage()
|
||
];
|
||
}
|
||
|
||
} else {
|
||
try {
|
||
$db->execute($sql);
|
||
return [
|
||
'type' => 2, // 执行sql语句
|
||
'error' => 0,
|
||
'message' => 'SQL执行成功!'
|
||
];
|
||
} catch (\Exception $e) {
|
||
return [
|
||
'type' => 2, // 执行sql语句
|
||
'error' => 1,
|
||
'message' => 'SQL执行失败!',
|
||
'exception' => $e->getMessage()
|
||
];
|
||
}
|
||
}
|
||
}
|
||
|
||
function hcInstalled(): bool
|
||
{
|
||
return file_exists(CMS_ROOT . '/public/system_file/install.lock');
|
||
}
|
||
|
||
function createInstallFile()
|
||
{
|
||
@file_put_contents(CMS_ROOT . '/public/system_file/install.lock', file_get_contents(CMS_ROOT .'/version'));
|
||
}
|
||
|
||
function updateVersion()
|
||
{
|
||
if (file_get_contents(CMS_ROOT .'/version') != @file_get_contents(CMS_ROOT .'/public/system_file/install.lock')) {
|
||
createInstallFile();
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* @throws \app\exception\ModelException
|
||
* @throws \app\exception\ModelEmptyException
|
||
*/
|
||
function hcUrl($url, $vars, $suffix = true, $domain = false): \think\route\Url
|
||
{
|
||
$url = strtolower($url);
|
||
if (false === strpos($url, '://') && 0 !== strpos($url, '/')) {
|
||
$info = parse_url($url);
|
||
$url = !empty($info['path']) ? $info['path'] : '';
|
||
if (isset($info['fragment'])) {
|
||
// 解析锚点
|
||
$anchor = $info['fragment'];
|
||
if (false !== strpos($anchor, '?')) {
|
||
// 解析参数
|
||
list($anchor, $info['query']) = explode('?', $anchor, 2);
|
||
}
|
||
if (false !== strpos($anchor, '@')) {
|
||
// 解析域名
|
||
list($anchor, $domain) = explode('@', $anchor, 2);
|
||
}
|
||
} elseif (strpos($url, '@') && false === strpos($url, '\\')) {
|
||
// 解析域名
|
||
list($url, $domain) = explode('@', $url, 2);
|
||
}
|
||
}
|
||
if (0 == strpos($url, '/')) {
|
||
$url = ltrim($url, '/');
|
||
}
|
||
// 解析参数
|
||
if (is_string($vars)) {
|
||
// aaa=1&bbb=2 转换成数组
|
||
parse_str($vars, $vars);
|
||
}
|
||
|
||
if (isset($info['query'])) {
|
||
// 解析地址里面参数 合并到vars
|
||
parse_str($info['query'], $params);
|
||
$vars = array_merge($params, $vars);
|
||
}
|
||
|
||
if (!empty($anchor)) {
|
||
$url = $url . '#' . $anchor;
|
||
}
|
||
if ($url == 'list/index' && isset($vars['id'])) {
|
||
$url = $url . '?id=' . $vars['id'];
|
||
unset($vars['id']);
|
||
}
|
||
if ($url == 'detail/index' && isset($vars['cid'])) {
|
||
$url = $url . '?cid=' . $vars['cid'];
|
||
unset($vars['cid']);
|
||
}
|
||
if ($url == 'tag/index') {
|
||
$url = $url . '?id=' . $vars['id'];
|
||
}
|
||
return url($url, $vars, $suffix, $domain);
|
||
}
|
||
|
||
|
||
function optEventLog($id, $title, $operation)
|
||
{
|
||
if (is_array($id)) {
|
||
$id = implode(',', $id);
|
||
}
|
||
$optAdmin = request()->admin;
|
||
event("AdminOptLog", [
|
||
'admin_id' => $optAdmin['uid'],
|
||
'admin_name' => $optAdmin['name'],
|
||
'title' => $title . lang("管理"),
|
||
"content" => $operation . $title . ',' . $title . lang('ID为') . $id,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 判断是否为windows系统
|
||
* @return bool
|
||
*/
|
||
function windows_os(): bool
|
||
{
|
||
return PHP_OS_FAMILY === 'Windows';
|
||
}
|
||
|
||
function is_directory($directory): bool
|
||
{
|
||
return is_dir($directory);
|
||
}
|
||
|
||
// 获取文件后缀
|
||
function getFileExt($str): string
|
||
{
|
||
return strtolower(pathinfo($str, PATHINFO_EXTENSION));
|
||
}
|
||
|
||
/**
|
||
* 返回文件格式
|
||
* @param string $str 文件名
|
||
* @return string 文件格式
|
||
*/
|
||
function fileFormat(string $str): string
|
||
{
|
||
// 取文件后缀名
|
||
$str = getFileExt($str);
|
||
// 图片格式
|
||
$image = array('webp', 'jpg', 'png', 'ico', 'bmp', 'gif', 'tif', 'pcx', 'tga', 'bmp', 'pxc', 'tiff', 'jpeg', 'exif', 'fpx', 'svg', 'psd', 'cdr', 'pcd', 'dxf', 'ufo', 'eps', 'ai', 'hdri');
|
||
// 视频格式
|
||
$video = array('mp4', 'avi', '3gp', 'rmvb', 'wmv', 'mkv', 'mpg', 'vob', 'mov', 'flv', 'swf', 'ape', 'wma', 'aac', 'mmf', 'amr', 'm4a', 'm4r', 'ogg', 'wav', 'wavpack', 'm4v', 'webm');
|
||
// 音频格式
|
||
$audio = array('mp3', 'mpeg', 'wma', 'mid', 'cd', 'wave', 'aiff', 'mpeg-4', 'midi', 'flac', 'acc', 'ape', 'amr');
|
||
// 压缩格式
|
||
$zip = array('rar', 'zip', 'tar', 'cab', 'uue', 'jar', 'iso', 'z', '7-zip', 'ace', 'lzh', 'arj', 'gzip', 'bz2', 'tz');
|
||
// 文档格式
|
||
$text = array('exe', 'doc', 'ppt', 'xls', 'wps', 'txt', 'lrc', 'wfs', 'torrent', 'html', 'htm', 'java', 'js', 'css', 'less', 'php', 'pdf', 'pps', 'host', 'box', 'docx', 'word', 'perfect', 'dot', 'dsf', 'efe', 'ini', 'json', 'lnk', 'log', 'msi', 'ost', 'pcs', 'tmp', 'xlsb','ttf', 'eot','woff','woff2');
|
||
|
||
// 匹配不同的结果
|
||
switch ($str) {
|
||
case in_array($str, $image):
|
||
return 'image';
|
||
case in_array($str, $video):
|
||
return 'video';
|
||
case in_array($str, $zip):
|
||
return 'zip';
|
||
case in_array($str, $audio):
|
||
return 'audio';
|
||
default:
|
||
return 'file';
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取网站跟目录
|
||
* @return string
|
||
*/
|
||
function hcGetRoot(): string
|
||
{
|
||
$root = request()->root();
|
||
$root = str_replace("//", '/', $root);
|
||
$root = str_replace('/index.php', '', $root);
|
||
if (defined('APP_NAMESPACE') && APP_NAMESPACE == 'api') {
|
||
$root = preg_replace('/\/api$/', '', $root);
|
||
}
|
||
return rtrim($root, '/');
|
||
}
|
||
|
||
/**
|
||
* 扫描路径下所有文件包括子目录
|
||
* @param $dir
|
||
* @return array
|
||
*/
|
||
function scanSubDir($dir): array
|
||
{
|
||
// $dir = ltrim($dir, "/");
|
||
$dirs = [];
|
||
$subDirs = hcScanDir("$dir/*", GLOB_ONLYDIR);
|
||
if (!empty($subDirs)) {
|
||
foreach ($subDirs as $subDir) {
|
||
$subDir = "$dir/$subDir";
|
||
array_push($dirs, $subDir);
|
||
$subDirSubDirs = scanSubDir($subDir);
|
||
if (!empty($subDirSubDirs)) {
|
||
$dirs = array_merge($dirs, $subDirSubDirs);
|
||
}
|
||
}
|
||
}
|
||
return $dirs;
|
||
}
|
||
|
||
/**
|
||
* 判断文件是否存在
|
||
* @param $filename
|
||
* @return bool
|
||
*/
|
||
function hcFileExist($filename): bool
|
||
{
|
||
if (is_file($filename)) {
|
||
if (env('app_debug')) {
|
||
if (basename(realpath($filename)) != basename($filename))
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 扫描路径下的文件
|
||
* @param $pattern
|
||
* @param null $flags
|
||
* @return array
|
||
*/
|
||
function hcScanDir($pattern, $flags = null): array
|
||
{
|
||
$files = glob($pattern, $flags);
|
||
if (empty($files)) {
|
||
$files = [];
|
||
} else {
|
||
$files = array_map('basename', $files);
|
||
}
|
||
return $files;
|
||
}
|
||
|
||
/**
|
||
* 小驼峰格式
|
||
*
|
||
* @param string $uncamelized_words
|
||
* @param string $separator
|
||
* @return string
|
||
*/
|
||
function camelize(string $uncamelized_words, string $separator = '_'): string
|
||
{
|
||
$uncamelized_words = $separator . str_replace($separator, " ", strtolower($uncamelized_words));
|
||
return ltrim(str_replace(" ", "", ucwords($uncamelized_words)), $separator);
|
||
}
|
||
|
||
/**
|
||
* 下划线格式
|
||
*
|
||
* @param string $camelCaps
|
||
* @param string $separator
|
||
* @return string
|
||
*/
|
||
function uncamelize(string $camelCaps, string $separator = '_'): string
|
||
{
|
||
return strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . $separator . "$2", $camelCaps));
|
||
}
|
||
|
||
/**
|
||
* 模型内统一数据返回
|
||
* @param $code
|
||
* @param string $msg
|
||
* @param array $data
|
||
* @return array
|
||
*/
|
||
function dataReturn($code, $msg = 'success', $data = [])
|
||
{
|
||
|
||
return ['code' => $code, 'data' => $data, 'msg' => $msg];
|
||
}
|
||
|
||
/**
|
||
* 统一返回json数据
|
||
* @param $code
|
||
* @param string $msg
|
||
* @param $data
|
||
* @return \think\response\Json
|
||
*/
|
||
function jsonReturn($code, string $msg = 'success', $data = []): \think\response\Json
|
||
{
|
||
|
||
return json(['code' => $code, 'data' => $data, 'msg' => $msg]);
|
||
}
|
||
|
||
/**
|
||
* 生成用户密码
|
||
* @param $password
|
||
* @param string $salt
|
||
* @return string
|
||
*/
|
||
function makePassword($password, string $salt = ''): string
|
||
{
|
||
|
||
if (empty($salt)) {
|
||
$salt = config('system.salt');
|
||
}
|
||
|
||
return sha1(md5($password . $salt));
|
||
}
|
||
|
||
/**
|
||
* 校验密码
|
||
* @param $inputPassword
|
||
* @param $dbPassword
|
||
* @param string $salt
|
||
* @return bool
|
||
*/
|
||
function checkPassword($inputPassword, $dbPassword, string $salt = ''): bool
|
||
{
|
||
|
||
if (makePassword($inputPassword, $salt) == $dbPassword) {
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 解析token中简短的用户信息
|
||
* @param $token
|
||
* @return array
|
||
*/
|
||
function getUserSimpleInfo($token): array
|
||
{
|
||
|
||
try {
|
||
|
||
$token = (new \Lcobucci\JWT\Parser())->parse($token);
|
||
} catch (\Exception $e) {
|
||
|
||
return dataReturn(-1, $e->getMessage());
|
||
}
|
||
|
||
$data = new \Lcobucci\JWT\ValidationData();
|
||
|
||
$data->setIssuer($token->getClaim('iss'));
|
||
$data->setAudience($token->getClaim('aud'));
|
||
$data->setId($token->getClaim('jti'));
|
||
|
||
if (!$token->validate($data)) {
|
||
return dataReturn(-2, 'token validate');
|
||
}
|
||
|
||
return dataReturn(0, '', [
|
||
'uid' => $token->getClaim('uid'),
|
||
'name' => $token->getClaim('name'),
|
||
'seller_id' => $token->getClaim('seller_id'),
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 从头部获取token
|
||
* @return bool|string
|
||
*/
|
||
function getHeaderToken()
|
||
{
|
||
|
||
$token = '';
|
||
$authorization = request()->header('authorization');
|
||
if (!empty($authorization)) {
|
||
$token = substr($authorization, 7);
|
||
}
|
||
return $token;
|
||
}
|
||
|
||
/**
|
||
* 统一分页返回
|
||
* @param $list
|
||
* @return array
|
||
*/
|
||
function pageReturn($list): array
|
||
{
|
||
if (0 == $list['code']) {
|
||
return ['code' => 0, 'msg' => 'ok', 'count' => $list['data']->total(), 'data' => $list['data']->all()];
|
||
}
|
||
|
||
return ['code' => 0, 'msg' => 'ok', 'count' => 0, 'data' => []];
|
||
}
|
||
|
||
// 引用实现无限分类
|
||
function generate(array $data, $flag = false): array
|
||
{
|
||
$data = getColumnForKeyArray($data, 'id');
|
||
$tree = [];
|
||
foreach ($data as $k => $v) {
|
||
if (isset($data[$v['parent_id']])) {
|
||
$data[$v['parent_id']]['children'][] = &$data[$k];
|
||
} else {
|
||
$tree[] = &$data[$k];
|
||
}
|
||
}
|
||
return $tree;
|
||
}
|
||
|
||
// 数组值作为键
|
||
function getColumnForKeyArray(array $data, string $key): array
|
||
{
|
||
$item = [];
|
||
foreach ($data as $val) {
|
||
if (!array_key_exists($key, $val)) {
|
||
break;
|
||
}
|
||
$val['children'] = [];
|
||
$item[$val[$key]] = $val;
|
||
}
|
||
return $item;
|
||
}
|
||
|
||
// 自定义树形结构层数
|
||
function makeTreeWithMaxLevel($data, $pid = 0, $maxLevel = 0, $level = 1): array
|
||
{
|
||
$tree = array();
|
||
foreach ($data as $key => $value) {
|
||
if ($value['parent_id'] == $pid) {
|
||
$value['level'] = $level;
|
||
unset($data[$key]);
|
||
if ($maxLevel === 0 || $maxLevel > $level) {
|
||
$value['children'] = makeTreeWithMaxLevel($data, $value['id'], $maxLevel, $level + 1);
|
||
} else {
|
||
$value['children'] = [];
|
||
}
|
||
$tree[] = $value;
|
||
}
|
||
}
|
||
return $tree;
|
||
}
|
||
|
||
/**
|
||
* // 递归实现无限分类
|
||
*
|
||
* @param $data
|
||
* @param int $pid
|
||
* @param int $level
|
||
* @return array
|
||
*/
|
||
function makeTree($data, int $pid = 0, int $level = 0): array
|
||
{
|
||
$tree = array();
|
||
foreach ($data as $key => $value) {
|
||
$value['children'] = [];
|
||
if ($value['parent_id'] == $pid) {
|
||
$value['level'] = $level;
|
||
unset($data[$key]);
|
||
$value['children'] = makeTree($data, $value['id'], $level + 1);
|
||
$tree[] = $value;
|
||
}
|
||
}
|
||
return $tree;
|
||
}
|
||
|
||
/**
|
||
* 获取某月所有时间
|
||
* @param string $time 某天时间戳
|
||
* @param string $format 转换的时间格式
|
||
* @return array
|
||
*/
|
||
function getMonth($time = '', $format = 'Y-m-d')
|
||
{
|
||
$time = $time != '' ? $time : time();
|
||
// 获取当前周几
|
||
$week = date('d', $time);
|
||
$date = [];
|
||
for ($i = 1; $i <= date('t', $time); $i++) {
|
||
$date[date($format, strtotime('+' . ($i - $week) . ' days', $time))] = 0;
|
||
}
|
||
return $date;
|
||
}
|
||
|
||
|
||
/**
|
||
* curl post数据
|
||
* @param $url
|
||
* @param $postData
|
||
* @return array
|
||
*/
|
||
function curlPost($url, $postData)
|
||
{
|
||
|
||
// 初始化
|
||
$curl = curl_init();
|
||
// 设置抓取的url
|
||
curl_setopt($curl, CURLOPT_URL, $url);
|
||
// 设置头文件的信息作为数据流输出
|
||
curl_setopt($curl, CURLOPT_HEADER, 0);
|
||
// 设置获取的信息以文件流的形式返回,而不是直接输出。
|
||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||
// 超时设置
|
||
curl_setopt($curl, CURLOPT_TIMEOUT, 10);
|
||
// 超时设置,以毫秒为单位
|
||
// curl_setopt($curl, CURLOPT_TIMEOUT_MS, 500);
|
||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
|
||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
|
||
// 设置post方式提交
|
||
curl_setopt($curl, CURLOPT_POST, 1);
|
||
curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
|
||
// 执行命令
|
||
$data = curl_exec($curl);
|
||
curl_close($curl);
|
||
|
||
return dataReturn(0, '成功', $data);
|
||
}
|
||
|
||
/**
|
||
* curl get 请求
|
||
* @param $url
|
||
* @return array
|
||
*/
|
||
function curlGet($url)
|
||
{
|
||
$ch = curl_init();
|
||
curl_setopt($ch, CURLOPT_URL, $url);
|
||
curl_setopt($ch, CURLOPT_FAILONERROR, true);
|
||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||
curl_setopt($ch, CURLOPT_AUTOREFERER, true);
|
||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||
// $SSL = substr($url, 0, 8) == "https://" ? true : false;
|
||
// if ($SSL) {
|
||
// curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 信任任何证书
|
||
// curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // 检查证书中是否设置域名
|
||
// }
|
||
$data = curl_exec($ch);
|
||
curl_close($ch);
|
||
return dataReturn(0, '成功', $data);
|
||
}
|
||
|
||
/**
|
||
* 两个日期间全部的数据
|
||
* @param $start
|
||
* @param $end
|
||
* @return array
|
||
*/
|
||
function getBetweenDate($start, $end)
|
||
{
|
||
|
||
$returnDate = [];
|
||
$dtStart = strtotime($start);
|
||
$dtEnd = strtotime($end);
|
||
while ($dtStart <= $dtEnd) {
|
||
$returnDate[] = date('m-d', $dtStart);
|
||
$dtStart = strtotime('+1 day', $dtStart);
|
||
}
|
||
|
||
return $returnDate;
|
||
}
|
||
|
||
|
||
/**
|
||
* 获取树形结构指定值子级
|
||
* @param $tree
|
||
* @param $name
|
||
* @param $value
|
||
* @return array
|
||
*/
|
||
function getTreeDataValue($tree, $name, $value)
|
||
{
|
||
$resTree = array();
|
||
foreach ($tree as $item) {
|
||
if ($item[$name] == $value) {
|
||
$resTree[] = $item[$name];
|
||
if (is_array($item) && isset($item['children'])) {
|
||
$resTree = array_merge($resTree, getTreeData($item['children'], $name));
|
||
}
|
||
} else {
|
||
if (is_array($item) && isset($item['children'])) {
|
||
$resTree = array_merge($resTree, getTreeDataValue($item['children'], $name, $value));
|
||
}
|
||
}
|
||
}
|
||
return $resTree;
|
||
}
|
||
|
||
|
||
/**
|
||
* 获取树形结构指定值
|
||
* @param $tree
|
||
* @param $name
|
||
* @param $value
|
||
* @return array
|
||
*/
|
||
function getTreeData($tree, $name)
|
||
{
|
||
$resTree = array();
|
||
foreach ($tree as $item) {
|
||
$resTree[] = $item[$name];
|
||
if (is_array($item) && isset($item['children'])) {
|
||
$resTree = array_merge($resTree, getTreeData($item['children'], $name));
|
||
}
|
||
}
|
||
return $resTree;
|
||
}
|
||
|
||
|
||
/**
|
||
* 生成下载表格
|
||
* @param $fileName
|
||
* @param $sheetName
|
||
* @param $data
|
||
* @param $matchedData
|
||
* @return array
|
||
*/
|
||
function createDownloadExcel($fileName, $sheetName, $head, $data, $matchedData)
|
||
{
|
||
$config = [
|
||
'path' => config('suwork.excel_url'),
|
||
];
|
||
|
||
$fileName = $fileName . date('Y_m_d_H_i') . '.xlsx';
|
||
$xlsxObject = new \Vtiful\Kernel\Excel($config);
|
||
|
||
$formatData = [];
|
||
foreach ($data as $key => $value) {
|
||
foreach ($matchedData as $k => $val) {
|
||
if (isset($value[$k])) {
|
||
if (is_array($val)) {
|
||
if (isset($val[$value[$k]])) {
|
||
$formatData[$key][] = $val[$value[$k]];
|
||
} else {
|
||
$formatData[$key][] = '';
|
||
}
|
||
} else {
|
||
$formatData[$key][] = $value[$k];
|
||
}
|
||
} else {
|
||
$formatData[$key][] = '';
|
||
}
|
||
}
|
||
}
|
||
$formatData = array_values($formatData);
|
||
|
||
$filePath = $xlsxObject->fileName($fileName, $sheetName)
|
||
->header($head)
|
||
->data($formatData)
|
||
->output();
|
||
// Set Header
|
||
header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||
header('Content-Disposition: attachment;filename="' . $fileName . '"');
|
||
header('Content-Length: ' . filesize($filePath));
|
||
header('Content-Transfer-Encoding: binary');
|
||
header('Cache-Control: must-revalidate');
|
||
header('Cache-Control: max-age=0');
|
||
header('Pragma: public');
|
||
|
||
ob_clean();
|
||
flush();
|
||
|
||
if (copy($filePath, 'php://output') === false) {
|
||
return jsonReturn(-1, '');
|
||
}
|
||
// Delete temporary file
|
||
@unlink($filePath);
|
||
die();
|
||
}
|
||
|
||
/**
|
||
* 参数过滤
|
||
* @param $class
|
||
* @return array
|
||
* @throws array
|
||
*/
|
||
function requestFilter($class)
|
||
{
|
||
|
||
try {
|
||
|
||
$class = new \ReflectionClass($class);
|
||
|
||
$properties = $class->getProperties();
|
||
$propertiesMap = [];
|
||
foreach ($properties as $vo) {
|
||
$propertiesMap[] = strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $vo->name));
|
||
}
|
||
|
||
return \think\facade\Request::only($propertiesMap);
|
||
} catch (\ReflectionException $e) {
|
||
|
||
return [];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取设备信息
|
||
* @param $ua
|
||
* @return array
|
||
*/
|
||
function getDeviceInfo($ua)
|
||
{
|
||
$deviceOs = '未知设备';
|
||
$deviceVersion = '未知版本';
|
||
// $ua = $_SERVER['HTTP_USER_AGENT'];
|
||
if (strpos($ua, 'Android') !== false) {
|
||
|
||
preg_match("/(?<=Android )[\d\.]{1,}/", $ua, $version);
|
||
$deviceOs = 'Android';
|
||
$deviceVersion = $version[0];
|
||
} elseif (strpos($ua, 'iPhone') !== false) {
|
||
|
||
preg_match("/(?<=CPU iPhone OS )[\d\_]{1,}/", $ua, $version);
|
||
$deviceOs = 'iPhone';
|
||
$deviceVersion = str_replace('_', '.', $version[0]);
|
||
} elseif (strpos($ua, 'iPad') !== false) {
|
||
|
||
preg_match("/(?<=CPU OS )[\d\_]{1,}/", $ua, $version);
|
||
$deviceOs = 'iPad';
|
||
$deviceVersion = str_replace('_', '.', $version[0]);
|
||
|
||
} elseif (preg_match('/OmniWeb\/(v*)([^\s|;]+)/i', $ua, $regs)) {
|
||
|
||
$deviceOs = 'OmniWeb';
|
||
$deviceVersion = $regs[2];
|
||
} elseif (preg_match('/Netscape([\d]*)\/([^\s]+)/i', $ua, $regs)) {
|
||
|
||
$deviceOs = 'Netscape';
|
||
$deviceVersion = $regs[2];
|
||
} elseif (preg_match('/safari\/([^\s]+)/i', $ua, $regs) && !preg_match('/Chrome\/([^\s]+)/i', $ua, $regs2)) {
|
||
|
||
$deviceOs = 'Safari';
|
||
$deviceVersion = $regs[1];
|
||
} elseif (preg_match('/MSIE\s([^\s|;]+)/i', $ua, $regs)) {
|
||
|
||
$deviceOs = 'Internet Explorer';
|
||
$deviceVersion = $regs[1];
|
||
} elseif (preg_match('/Opera[\s|\/]([^\s]+)/i', $ua, $regs)) {
|
||
|
||
$deviceOs = 'Opera';
|
||
$deviceVersion = $regs[1];
|
||
} elseif (preg_match('/NetCaptor\s([^\s|;]+)/i', $ua, $regs)) {
|
||
|
||
$deviceOs = '(Internet Explorer) NetCaptor';
|
||
$deviceVersion = $regs[1];
|
||
} elseif (preg_match('/Maxthon/i', $ua, $regs)) {
|
||
|
||
$deviceOs = '(Internet Explorer) Maxthon';
|
||
$deviceVersion = '';
|
||
} elseif (preg_match('/360SE/i', $ua, $regs)) {
|
||
|
||
$deviceOs = '(Internet Explorer) 360SE';
|
||
$deviceVersion = '';
|
||
} elseif (preg_match('/SE 2.x/i', $ua, $regs)) {
|
||
|
||
$deviceOs = '(Internet Explorer) 搜狗';
|
||
$deviceVersion = '';
|
||
} elseif (preg_match('/FireFox\/([^\s]+)/i', $ua, $regs)) {
|
||
|
||
$deviceOs = 'FireFox';
|
||
$deviceVersion = $regs[1];
|
||
} elseif (preg_match('/Lynx\/([^\s]+)/i', $ua, $regs)) {
|
||
|
||
$deviceOs = 'Lynx';
|
||
$deviceVersion = $regs[1];
|
||
} elseif (preg_match('/Chrome\/([^\s]+)/i', $ua, $regs)) {
|
||
|
||
$deviceOs = 'Chrome';
|
||
$deviceVersion = $regs[1];
|
||
} elseif (strpos($ua, 'Postman') !== false) {
|
||
$deviceOs = 'Postman';
|
||
$deviceVersion = '';
|
||
}
|
||
|
||
return [
|
||
'deviceOs' => $deviceOs,
|
||
'deviceVersion' => $deviceVersion
|
||
];
|
||
}
|
||
|
||
|
||
/**
|
||
* 根据ip定位
|
||
* @param $ip
|
||
* @param $type
|
||
* @return string | array
|
||
* @throws Exception
|
||
*/
|
||
function getLocationByIp($ip, $type = 1)
|
||
{
|
||
$ip2region = new \Ip2Region();
|
||
$info = $ip2region->btreeSearch($ip);
|
||
if (empty($info) || empty($info['region'])) {
|
||
return ['province' => '未知', 'city' => '未知'];
|
||
}
|
||
$info = explode('|', $info['region']);
|
||
|
||
$address = '';
|
||
foreach ($info as $vo) {
|
||
if ('0' !== $vo) {
|
||
$address .= $vo . '-';
|
||
}
|
||
}
|
||
|
||
if (2 == $type) {
|
||
if (empty(array_filter($info))) {
|
||
return ['province' => '未知', 'city' => '未知'];
|
||
}
|
||
return ['province' => $info['2'], 'city' => $info['3']];
|
||
}
|
||
|
||
return rtrim($address, '-');
|
||
}
|
||
|
||
/**
|
||
* 快速排序
|
||
* @param $arr
|
||
*/
|
||
function quickSort(&$arr)
|
||
{
|
||
$length = count($arr);
|
||
|
||
if ($length <= 1) {
|
||
return;
|
||
}
|
||
|
||
$middle = $arr[0];
|
||
|
||
$left = [];
|
||
$right = [];
|
||
|
||
for ($i = 1; $i < $length; $i++) {
|
||
if ($middle['pivot']['sort'] < $arr[$i]['pivot']['sort']) {
|
||
$right[] = $arr[$i];
|
||
} else {
|
||
$left[] = $arr[$i];
|
||
}
|
||
}
|
||
|
||
quickSort($left);
|
||
quickSort($right);
|
||
|
||
$arr = array_merge($left, [$middle], $right);
|
||
|
||
// return $arr;
|
||
}
|
||
|
||
function makeFormTable($table)
|
||
{
|
||
return config('database.connections.mysql.prefix') . 'diyform_' . $table;
|
||
}
|
||
|
||
/**
|
||
* 获取当前请求所对应的语言
|
||
* @return string
|
||
*/
|
||
function setLang(): string
|
||
{
|
||
$baseUrl = trim(\request()->baseUrl(), '/');
|
||
$firstPath = explode('/', $baseUrl)[0];
|
||
$langArr = config('system.lang');
|
||
if (empty($firstPath) || !in_array($firstPath, $langArr)) {
|
||
$firstPath = config('lang.default_lang');
|
||
}
|
||
return $firstPath;
|
||
}
|
||
|
||
/**
|
||
* 字符串命名风格转换
|
||
* type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
|
||
* @param string $name 字符串
|
||
* @param integer $type 转换类型
|
||
* @param bool $ucfirst 首字母是否大写(驼峰规则)
|
||
* @return string
|
||
*/
|
||
function parse_name($name, $type = 0, $ucfirst = true)
|
||
{
|
||
if ($type) {
|
||
$name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
|
||
return strtoupper($match[1]);
|
||
}, $name);
|
||
return $ucfirst ? ucfirst($name) : lcfirst($name);
|
||
}
|
||
|
||
return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
|
||
}
|
||
|
||
/**
|
||
* 获取插件类名
|
||
* @param string $name 插件名
|
||
* @return string
|
||
*/
|
||
function get_plugin_class($name)
|
||
{
|
||
$name = ucwords($name);
|
||
$pluginDir = parse_name($name);
|
||
$class = "plugins\\{$pluginDir}\\{$name}Plugin";
|
||
return $class;
|
||
}
|
||
|
||
function url_root($url = "")
|
||
{
|
||
$dual_host = array('aaa.pro', 'ac.cn', 'ac.kr', 'ac.mu', 'aca.pro', 'acct.pro', 'ae.org', 'ah.cn', 'ar.com', 'avocat.pro', 'bar.pro', 'biz.ki', 'biz.pl', 'bj.cn', 'br.com', 'busan.kr', 'chungbuk.kr', 'chungnam.kr', 'club.tw', 'cn.com', 'co.ag', 'co.am', 'co.at', 'co.bz', 'co.cm', 'co.com', 'co.gg', 'co.gl', 'co.gy', 'co.il', 'co.im', 'co.in', 'co.je', 'co.kr', 'co.lc', 'co.mg', 'co.ms', 'co.mu', 'co.nl', 'co.nz', 'co.uk', 'co.ve', 'co.za', 'com.af', 'com.ag', 'com.am', 'com.ar', 'com.au', 'com.br', 'com.bz', 'com.cm', 'com.cn', 'com.co', 'com.de', 'com.ec', 'com.es', 'com.gl', 'com.gr', 'com.gy', 'com.hn', 'com.ht', 'com.im', 'com.ki', 'com.lc', 'com.lv', 'com.mg', 'com.ms', 'com.mu', 'com.mx', 'com.nf', 'com.pe', 'com.ph', 'com.pk', 'com.pl', 'com.ps', 'com.pt', 'com.ro', 'com.ru', 'com.sb', 'com.sc', 'com.se', 'com.sg', 'com.so', 'com.tw', 'com.vc', 'com.ve', 'cpa.pro', 'cq.cn', 'daegu.kr', 'daejeon.kr', 'de.com', 'ebiz.tw', 'edu.cn', 'edu.gl', 'eng.pro', 'es.kr', 'eu.com', 'fin.ec', 'firm.in', 'fj.cn', 'game.tw', 'gangwon.kr', 'gb.com', 'gb.net', 'gd.cn', 'gen.in', 'go.kr', 'gov.cn', 'gr.com', 'gs.cn', 'gwangju.kr', 'gx.cn', 'gyeongbuk.kr', 'gyeonggi.kr', 'gyeongnam.kr', 'gz.cn', 'ha.cn', 'hb.cn', 'he.cn', 'hi.cn', 'hk.cn', 'hl.cn', 'hn.cn', 'hs.kr', 'hu.com', 'hu.net', 'idv.tw', 'in.net', 'incheon.kr', 'ind.in', 'info.ec', 'info.ht', 'info.ki', 'info.nf', 'info.pl', 'info.ve', 'jeju.kr', 'jeonbuk.kr', 'jeonnam.kr', 'jl.cn', 'jp.net', 'jpn.com', 'js.cn', 'jur.pro', 'jx.cn', 'kg.kr', 'kiwi.nz', 'kr.com', 'law.pro', 'ln.cn', 'me.uk', 'med.ec', 'med.pro', 'mex.com', 'mo.cn', 'ms.kr', 'ne.kr', 'net.af', 'net.ag', 'net.am', 'net.br', 'net.bz', 'net.cm', 'net.cn', 'net.co', 'net.ec', 'net.gg', 'net.gl', 'net.gr', 'net.gy', 'net.hn', 'net.ht', 'net.im', 'net.in', 'net.je', 'net.ki', 'net.lc', 'net.lv', 'net.mg', 'net.mu', 'net.my', 'net.nf', 'net.nz', 'net.ph', 'net.pk', 'net.pl', 'net.ps', 'net.ru', 'net.sb', 'net.sc', 'net.so', 'net.vc', 'net.ve', 'nm.cn', 'no.com', 'nom.ag', 'nom.co', 'nom.es', 'nom.ro', 'nx.cn', 'or.at', 'or.jp', 'or.kr', 'or.mu', 'org.af', 'org.ag', 'org.am', 'org.bz', 'org.cn', 'org.es', 'org.gg', 'org.gl', 'org.gr', 'org.hn', 'org.ht', 'org.il', 'org.im', 'org.in', 'org.je', 'org.ki', 'org.lc', 'org.lv', 'org.mg', 'org.ms', 'org.mu', 'org.my', 'org.nz', 'org.pk', 'org.pl', 'org.ps', 'org.ro', 'org.ru', 'org.sb', 'org.sc', 'org.so', 'org.uk', 'org.vc', 'org.ve', 'pe.kr', 'pro.ec', 'qc.com', 'qh.cn', 'radio.am', 'radio.fm', 're.kr', 'recht.pro', 'ru.com', 'sa.com', 'sc.cn', 'sc.kr', 'sd.cn', 'se.com', 'senet', 'seoul.kr', 'sh.cn', 'sn.cn', 'sx.cn', 'tj.cn', 'tw.cn', 'uk.com', 'uk.net', 'ulsan.kr', 'us.com', 'us.org', 'uy.com', 'web.ve', 'xj.cn', 'xz.cn', 'yn.cn', 'za.com', 'zj.cn');
|
||
$url_arr = explode(".", $url);
|
||
if (count($url_arr) <= 2) {
|
||
$host = $url;
|
||
} else {
|
||
$last = array_pop($url_arr);
|
||
$last_1 = array_pop($url_arr);
|
||
$last_2 = array_pop($url_arr);
|
||
$host = $last_1 . '.' . $last;
|
||
if (in_array($host, $dual_host)) {
|
||
$host = $last_2 . '.' . $last_1 . '.' . $last;
|
||
}
|
||
}
|
||
return $host;
|
||
}
|
||
|
||
function random_code_type($length = 8, $type = 'alpha-number')
|
||
{
|
||
$code_arr = array(
|
||
'alpha' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 'number' => '0123456789', 'sign' => '#$%@*-_',);
|
||
$type_arr = explode('-', $type);
|
||
foreach ($type_arr as $t) {
|
||
if (!array_key_exists($t, $code_arr)) {
|
||
trigger_error("Can not generate type ($t) code");
|
||
}
|
||
}
|
||
$chars = '';
|
||
foreach ($type_arr as $t) {
|
||
$chars .= $code_arr[$t];
|
||
}
|
||
$chars = str_shuffle($chars);
|
||
$number = $length > strlen($chars) - 1 ? strlen($chars) - 1 : $length;
|
||
return substr($chars, 0, $number);
|
||
}
|
||
|
||
function get_sub_data($pid, &$subData, &$data)
|
||
{
|
||
$param = [];
|
||
if (is_array($pid)) {
|
||
$param['in'] = $pid; //上级pid IN 查询
|
||
} else {
|
||
$param['eq'] = $pid; //上级 pid = 查询
|
||
}
|
||
|
||
//根据父节点,查找下级的子节点
|
||
$subList = search_all($param, $data);
|
||
if (empty($subList)) {
|
||
return $subData;
|
||
}
|
||
|
||
$tempSubIds = array_column($subList, 'id'); //获取这个节点的所有下级id
|
||
$subData = array_merge($subData, $subList); //用户下级数据合并
|
||
|
||
get_sub_data($tempSubIds, $subData, $data);
|
||
}
|
||
|
||
function get_sub_ids($pid, &$subIds, &$data)
|
||
{
|
||
$param = [];
|
||
if (is_array($pid)) {
|
||
$param['in'] = $pid; //上级pid IN 查询
|
||
} else {
|
||
$param['eq'] = $pid; //上级 pid = 查询
|
||
}
|
||
|
||
//根据父节点,查找下级的子节点
|
||
$subList = search_all($param, $data);
|
||
if (empty($subList)) {
|
||
return $subIds;
|
||
}
|
||
|
||
$tempSubIds = array_column($subList, 'id'); //获取这个节点的所有下级id
|
||
$subIds = array_merge($subIds, $tempSubIds); //用户下级ID合并
|
||
|
||
get_sub_ids($tempSubIds, $subIds, $data);
|
||
}
|
||
|
||
//模拟数据表查询所有操作
|
||
function search_all($param, &$data)
|
||
{
|
||
$result = [];
|
||
|
||
if (array_key_exists('eq', $param)) { //等于操作
|
||
$searchValue = $param['eq'];
|
||
foreach ($data as $value) {
|
||
if ($searchValue == $value['parent_id']) {
|
||
$result[] = $value;
|
||
}
|
||
}
|
||
}
|
||
if (array_key_exists('in', $param)) { //in查询
|
||
$searchArray = $param['in'];
|
||
foreach ($data as $value) {
|
||
if (in_array($value['parent_id'], $searchArray)) {
|
||
$result[] = $value;
|
||
}
|
||
}
|
||
}
|
||
|
||
return $result;
|
||
}
|
||
|
||
function createFile($file)
|
||
{
|
||
//循环遍历文件夹,循环条件文件夹不存在
|
||
if (is_dir($file)) {
|
||
return;
|
||
}
|
||
|
||
//强制将'\'转换成 '/'
|
||
$file = str_replace('\\', '/', $file);
|
||
$file = substr($file, 0, strrpos($file, '/'));
|
||
|
||
//创建文件夹,若创建失败错误提示被抑制
|
||
@mkdir($file);
|
||
//获取上级文件夹路径地址
|
||
$file = substr($file, 0, strrpos($file, '/'));
|
||
// echo 'sss';
|
||
//打印路径
|
||
//echo $file . '';
|
||
//调用自身方法,将上级目录路径传入
|
||
createFile($file);
|
||
|
||
}
|
||
|
||
function mkdirs($dir, $mode = 0777) {
|
||
if (! is_dir ( $dir )) {
|
||
if (! mkdirs ( dirname ( $dir ) )) {
|
||
return false;
|
||
}
|
||
if (! mkdir ( $dir, $mode )) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
|
||
|
||
if(!function_exists("createUserToken")){
|
||
/**
|
||
* @throws TokenException
|
||
*/
|
||
function createUserToken($data, $jtiType='admin')
|
||
{
|
||
try{
|
||
$jwtConfig = config("jwt")['stores']['token'];
|
||
$jti = $jtiType.'_'.mt_rand(1000,9999).$data['uid'];
|
||
$jwtObject = Jwt::getInstance()->setSecretKey($jwtConfig['signer_key'])->publish();
|
||
$jwtObject->setAlg('HMACSHA256');
|
||
$jwtObject->setExp(time()+$jwtConfig['refresh_ttL']); //过期时间
|
||
$jwtObject->setIat(time()); // 发布时间
|
||
$jwtObject->setIss('huocms'); // 发行人
|
||
$jwtObject->setJti(md5($jti)); // jwt id 用于标识该jwt
|
||
$jwtObject->setNbf(time()); // 在此之前不可用
|
||
$jwtObject->setSub($jtiType); // 主题
|
||
$jwtObject->setData($data);
|
||
return $jwtObject->__toString();
|
||
}catch (Exception $e){
|
||
throw new TokenException("登录失败",-402);
|
||
}
|
||
}
|
||
}
|