You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
yanzong/app/common.php

674 lines
19 KiB

<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
/**
* 应用公共函数库文件
*/
use think\Response;
use think\facade\Env;
use think\facade\Log;
use think\facade\Config;
use think\facade\Request;
use cores\exception\BaseException;
use cores\exception\DebugException;
use think\exception\HttpResponseException;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use think\facade\Db;
/**
* 打印调试函数 html
* @param $content
* @param bool $export
*/
function pre($content, bool $export = false)
{
$output = $export ? var_export($content, true) : print_r($content, true);
echo "<pre>{$output}</pre>";
app_end();
}
/**
* 打印调试函数 json
* @param $content
* @param bool $export
* @throws DebugException
*/
function pree($content, bool $export = false)
{
$output = $export ? var_export($content, true) : $content;
throw new DebugException([], $output);
}
/**
* 打印调试函数 输出在终端
* 只有debug模式下输出
* @param $content
* @return void
*/
function tre($content)
{
// if (is_debug()) {
$output = print_r($content, true);
echo "$output\n";
// }
}
/**
* 输出错误信息
* @param string $message 报错信息
* @param int|null $status 状态码,默认为配置文件status.error
* @param array $data 附加数据
* @throws BaseException
*/
function throwError(string $message, ?int $status = null, array $data = [])
{
is_null($status) && $status = config('status.error');
throw new BaseException(['status' => $status, 'message' => $message, 'data' => $data]);
}
/**
* 下划线转驼峰
* @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));
}
/**
* 生成密码hash值
* @param string $password
* @return string
*/
function encryption_hash(string $password): string
{
return password_hash($password, PASSWORD_DEFAULT);
}
/**
* 获取当前域名及根路径
* @return string
*/
function base_url(): string
{
static $baseUrl = '';
if (empty($baseUrl)) {
$request = Request::instance();
// url协议,设置强制https或自动获取
$scheme = Config::get('route')['url_force_https'] ? 'https' : $request->scheme();
// url子目录
$rootUrl = root_url();
// 拼接完整url
$baseUrl = "{$scheme}://" . $request->host() . $rootUrl;
}
return $baseUrl;
}
/**
* 获取当前url的子目录路径
* @return string
*/
function root_url(): string
{
static $rootUrl = '';
if (empty($rootUrl)) {
$request = Request::instance();
$subUrl = str_replace('\\', '/', dirname($request->baseFile()));
$rootUrl = $subUrl . ($subUrl === '/' ? '' : '/');
}
return $rootUrl;
}
/**
* 获取当前uploads目录访问地址
* @return string
*/
function uploads_url(): string
{
return base_url() . 'uploads/';
}
/**
* 获取当前temp目录访问地址
* @return string
*/
function temp_url(): string
{
return base_url() . 'temp/';
}
/**
* 获取当前的应用名称
* @return mixed
*/
function app_name()
{
return app('http')->getName();
}
/**
* 获取web根目录
* @return string
*/
function web_path(): string
{
static $webPath = '';
if (empty($webPath)) {
$request = Request::instance();
$webPath = dirname($request->server('SCRIPT_FILENAME')) . DIRECTORY_SEPARATOR;
}
return $webPath;
}
/**
* 获取data目录路径
* @return string
*/
function data_path(): string
{
return config('filesystem.disks.data.root') . DIRECTORY_SEPARATOR;
}
/**
* 获取runtime根目录路径
* @return string
*/
function runtime_root_path(): string
{
// return dirname(runtime_path()) . DIRECTORY_SEPARATOR;
return root_path() . 'runtime' . DIRECTORY_SEPARATOR;
}
/**
* 写入日志 (使用tp自带驱动记录到runtime目录中)
* @param mixed $value
* @param string $type
*/
function log_record($value, string $type = 'info')
{
$content = is_string($value) ? $value : print_r($value, true);
Log::record($content, $type);
}
/**
* 多维数组合并
* @param $array1
* @param $array2
* @return array
*/
function array_merge_multiple($array1, $array2): array
{
$merge = $array1 + $array2;
$data = [];
foreach ($merge as $key => $val) {
if (
isset($array1[$key])
&& is_array($array1[$key])
&& isset($array2[$key])
&& is_array($array2[$key])
) {
$data[$key] = is_assoc($array1[$key]) ? array_merge_multiple($array1[$key], $array2[$key]) : $array2[$key];
} else {
$data[$key] = $array2[$key] ?? $array1[$key];
}
}
return $data;
}
/**
* 判断是否为自定义索引数组
* @param array $array
* @return bool
*/
function is_assoc(array $array): bool
{
if (empty($array)) return false;
return array_keys($array) !== range(0, count($array) - 1);
}
/**
* 二维数组排序
* @param $arr
* @param $keys
* @param bool $desc
* @return array
*/
function array_sort($arr, $keys, bool $desc): array
{
$key_value = $new_array = array();
foreach ($arr as $k => $v) {
$key_value[$k] = $v[$keys];
}
if ($desc) {
arsort($key_value);
} else {
asort($key_value);
}
reset($key_value);
foreach ($key_value as $k => $v) {
$new_array[$k] = $arr[$k];
}
return $new_array;
}
/**
* 隐藏敏感字符
* @param $value
* @return string
*/
function substr_cut($value): string
{
$strlen = mb_strlen($value, 'utf-8');
if ($strlen <= 1) return $value;
$firstStr = mb_substr($value, 0, 1, 'utf-8');
$lastStr = mb_substr($value, -1, 1, 'utf-8');
return $strlen == 2 ? $firstStr . str_repeat('*', $strlen - 1) : $firstStr . str_repeat("*", $strlen - 2) . $lastStr;
}
/**
* 获取当前系统版本号
* @return string
* @throws BaseException
*/
function get_version(): string
{
return \cores\library\Version::getVersion();
}
/**
* 获取全局唯一标识符
* @param bool $trim
* @return string
*/
function get_guid_v4(bool $trim = true): string
{
// Windows
if (function_exists('com_create_guid') === true) {
$charid = com_create_guid();
return $trim ? trim($charid, '{}') : $charid;
}
// OSX/Linux
if (function_exists('openssl_random_pseudo_bytes') === true) {
$data = openssl_random_pseudo_bytes(16);
$data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0100
$data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}
// Fallback (PHP 4.2+)
mt_srand(intval((double)microtime() * 10000));
$charid = strtolower(md5(uniqid((string)rand(), true)));
$hyphen = chr(45); // "-"
$lbrace = $trim ? "" : chr(123); // "{"
$rbrace = $trim ? "" : chr(125); // "}"
return $lbrace .
substr($charid, 0, 8) . $hyphen .
substr($charid, 8, 4) . $hyphen .
substr($charid, 12, 4) . $hyphen .
substr($charid, 16, 4) . $hyphen .
substr($charid, 20, 12) .
$rbrace;
}
/**
* 时间戳转换日期
* @param int|string $timeStamp 时间戳
* @param bool $withTime 是否关联时间
* @return false|string
*/
function format_time($timeStamp, bool $withTime = true)
{
$format = 'Y-m-d';
$withTime && $format .= ' H:i:s';
return $timeStamp ? date($format, $timeStamp) : '';
}
/**
* 左侧填充0
* @param string $value
* @param int $padLength
* @return string
*/
function pad_left(string $value, int $padLength = 2): string
{
return str_pad($value, $padLength, '0', STR_PAD_LEFT);
}
/**
* 重写trim方法 (解决int类型过滤后后变为string类型)
* @param $str
* @return string|void
*/
function my_trim($str)
{
return is_string($str) ? trim($str) : $str;
}
/**
* 重写htmlspecialchars方法 (解决int类型过滤后后变为string类型)
* @param $string
* @return string|void
*/
function my_htmlspecialchars($string)
{
return is_string($string) ? htmlspecialchars($string, ENT_COMPAT) : $string;
}
/**
* 过滤emoji表情
* @param $text
* @return null|string|string[]
*/
function filter_emoji($text)
{
if (!is_string($text)) {
return $text;
}
// 此处的preg_replace用于过滤emoji表情
// 如需支持emoji表情, 需将mysql的编码改为utf8mb4
return preg_replace('/[\xf0-\xf7].{3}/', '', $text);
}
/**
* 根据指定长度截取字符串
* @param $str
* @param int $length
* @return bool|string
*/
function str_substr($str, int $length = 30)
{
if (strlen($str) > $length) {
$str = mb_substr($str, 0, $length);
}
return $str;
}
/**
* 结束执行
*/
function app_end()
{
if (\request()->isCli()) {
exit(PHP_EOL);
}
throw new HttpResponseException(Response::create());
}
/**
* 当前是否为调试模式
* @return bool
*/
function is_debug(): bool
{
return (bool)Env::instance()->get('APP_DEBUG');
}
/**
* 文本左斜杠转换为右斜杠
* @param string $string
* @return string
*/
function convert_left_slash(string $string): string
{
return str_replace('\\', '/', $string);
}
/**
* 隐藏手机号中间四位 13012345678 -> 130****5678
* @param string $mobile 手机号
* @return string
*/
function hide_mobile(string $mobile): string
{
return substr_replace($mobile, '****', 3, 4);
}
function getHost(){
return (isset($_SERVER['REQUEST_SCHEME'])&&!empty($_SERVER['REQUEST_SCHEME']) ? $_SERVER['REQUEST_SCHEME'] : "https")."://".$_SERVER['HTTP_HOST'];
}
function getUrl($value, $host = ''){
if (strpos($value, "http") !== false) {
return $value;
}
$host = $host ? $host : getHost();
return $value ? $host."/".$value : "";
}
function getUrlValue($value, $host = '', $storage = ""){
if (strpos($value, "http") !== false) {
return $value;
}
$host = $host ? $host : getHost();
if ($storage == 'local') {
return uploads_url() .$value;
} else {
return $value ? $host."/".$value : "";
}
}
function calc_time($startTime, $endTime) {
$diffTime = ($endTime - $startTime);
if ($diffTime > 3600) {
return "";
}
return date('i分钟s秒', (3600 - $diffTime));
}
if (!function_exists('downLoadExcel')){
/**
* 导出excel
* @param $name excel名称
* @param $titles 标题 [['name'=>'姓名'],['gender'=>'性别']]
* @param array $data
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
*/
function downLoadExcel($name, $titles, $data=[])
{
$count = count($titles); //计算表头数量
$spreadsheet = new Spreadsheet();
$styleArray = [
'alignment' => [
'horizontal' => Alignment::HORIZONTAL_CENTER_CONTINUOUS,
'vertical' => Alignment::VERTICAL_CENTER,
'wrapText' => true,
],
];
$sheet = $spreadsheet->getActiveSheet();
for ($i = 65; $i < $count + 65; $i++) { //数字转字母从65开始,循环设置表头
$sheet->getStyle(strtoupper(chr($i)))->applyFromArray($styleArray);
$sheet->getCell(strtoupper(chr($i)).'1')->getStyle()->getFont()->setBold(true);
$index = $i - 65;
$sheet->setCellValue(strtoupper(chr($i)) . '1', $titles[$index][key($titles[$index])] );
}
/*--------------开始从数据库提取信息插入Excel表中------------------*/
foreach ($data as $key => $item) { //循环设置单元格:
//$key+2,因为第一行是表头,所以写到表格时 从第二行开始写
for ($i = 65; $i < $count + 65; $i++) { //数字转字母从65开始:
$sheet->setCellValue(strtoupper(chr($i)) . ($key + 2),$item[key($titles[$i - 65])]);
$spreadsheet->getActiveSheet()->getColumnDimension(strtoupper(chr($i)))->setAutoSize(true);
}
}
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="' . $name . '.xlsx"');
header('Cache-Control: max-age=0');
$writer = IOFactory::createWriter($spreadsheet,'Xlsx');
$writer->save('php://output');
//删除清空
$spreadsheet->disconnectWorksheets();
unset($spreadsheet);
exit;
}
}
/**
* CURL请求
* @param $url 请求url地址
* @param $method 请求方法 get post
* @param null $postfields post数据数组
* @param array $headers 请求header信息
* @param bool|false $debug 调试开启 默认false
* @return mixed
*/
//Modified by Shayne Song to solve problem that OFPAY video vip card buying interface need 15 seconds to return result on 2018/03/19.
function httpRequest($url, $method="GET", $postfields = null, $headers = array(), $debug = false, $timeout = 10) {
$method = strtoupper($method);
$ci = curl_init();
/* Curl settings */
curl_setopt($ci, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_setopt($ci, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0");
curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, 60); /* 在发起连接前等待的时间,如果设置为0,则无限等待 */
curl_setopt($ci, CURLOPT_TIMEOUT, $timeout); /* 设置cURL允许执行的最长秒数 */
curl_setopt($ci, CURLOPT_RETURNTRANSFER, true);
switch ($method) {
case "POST":
curl_setopt($ci, CURLOPT_POST, true);
if (!empty($postfields)) {
$tmpdatastr = is_array($postfields) ? http_build_query($postfields) : $postfields;
curl_setopt($ci, CURLOPT_POSTFIELDS, $tmpdatastr);
}
break;
default:
curl_setopt($ci, CURLOPT_CUSTOMREQUEST, $method); /* //设置请求方式 */
break;
}
$ssl = preg_match('/^https:\/\//i',$url) ? TRUE : FALSE;
curl_setopt($ci, CURLOPT_URL, $url);
if($ssl){
curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, FALSE); // https请求 不验证证书和hosts
curl_setopt($ci, CURLOPT_SSL_VERIFYHOST, FALSE); // 不从证书中检查SSL加密算法是否存在
}
//curl_setopt($ci, CURLOPT_HEADER, true); /*启用时会将头文件的信息作为数据流输出*/
curl_setopt($ci, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ci, CURLOPT_MAXREDIRS, 2);/*指定最多的HTTP重定向的数量,这个选项是和CURLOPT_FOLLOWLOCATION一起使用的*/
curl_setopt($ci, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ci, CURLINFO_HEADER_OUT, true);
/*curl_setopt($ci, CURLOPT_COOKIE, $Cookiestr); * *COOKIE带过去** */
$response = curl_exec($ci);
$requestinfo = curl_getinfo($ci);
$http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
$curl_error = curl_errno($ci);
if($curl_error){
Log::error("ERROR_CODE:{$curl_error} | URL:".$url.' | postfields:'.json_encode($postfields),'curl_error');
//sys_log("ERROR_CODE:{$curl_error} | URL:".$url.' | postfields:'.json_encode($postfields),'curl_error');
//\app\common\util\ErrorAlert::curlWarning($url,$curl_error);
}
if ($debug) {
echo "=====post data======\r\n";
var_dump($postfields);
echo "=====info===== \r\n";
print_r($requestinfo);
echo "=====response=====\r\n";
print_r($response);
}
curl_close($ci);
return json_decode($response, true);
//return array($http_code, $response,$requestinfo);
}
/**
* 获取加价之后的成本价
* [getGoodsCostPrice description]
* @param [type] $cost_price [description]
* @param [type] $rate [description]
* @return [type] [description]
*/
function getGoodsCostAndProfitAndProfitRate($net_price, $cost_price, $rate){
if ($rate > 0) {
$cost_price = round($cost_price / (1 - ($rate / 100)), 0);
}
$profit = (float)$net_price - (float)$cost_price;
$profit_rate = (float)$net_price > 0 ? bcmul(bcdiv((string)$profit, (string)$net_price, 4), (string)100, 2) : 0.00;
return [$cost_price, $profit, $profit_rate];
}
/**
* 抓取京东商品信息
* [getJdGoodsBySku description]
* @param [type] $skus [description]
* @return [type] [description]
*/
function getJdGoodsBySku($skus){
$sku = implode(",", $skus);
//$url = "http://47.98.251.206:8811/api/skus/info?skus=".$sku;
$url = "http://8.130.98.31:8811/api/skus/info?skus=".$sku;
$data = httpRequest($url, "GET", null, [], false, 30);
if ($data['code'] != 0 || !$data['data']) {
return [];
}
$data = $data['data'];
foreach ($data as &$item) {
$content = "";
if (isset($item['infoImages']) && $item['infoImages']) {
foreach ($item['infoImages'] as $value) {
if (strpos($value, "http") !== false) {
$content .= '<p><img src="' . $value . '"/></p>';
} else {
if (strpos($value, "//") !== false) {
$content .= '<p><img src="' . "https:".$value . '"/></p>';
} else {
$content .= '<p><img src="' . "https://".$value . '"/></p>';
}
}
}
$item['content'] = $content;
}
$goods_images = [];
//写入主图到数据库
if ($item['mainImages']) {
foreach ($item['mainImages'] as $image) {
$goods_images[] = [
'preview_url' => $image,
'file_id' => 0,
];
}
}
$item['goods_images'] = $goods_images;
}
$data = array_column($data, null, "skuId");
return $data;
}