SchoolPhysicalExamination/application/NewReedaw/controller/app/Base.php

1033 lines
41 KiB
PHP
Raw Normal View History

2025-10-11 18:11:41 +08:00
<?php
namespace app\NewReedaw\controller\app;
use think\Controller;
use think\Db;
use think\Cache;
use think\Log;
use PHPMailer\PHPMailer\PHPMailer;
class Base extends Controller{
protected $base_use_db_name = [
'1'=>'app_data_log',
'2'=>'app_card_data',
'3'=>'app_user_data',
'4'=>'pc_vitalcapacity_standard',
'5'=>'admin_estimate',
2026-03-06 18:02:49 +08:00
'6'=>'app_account_number',
'search_history'=>'app_user_search_history',
'foodlist4'=>'app_z_national_standard_food_type_4',
'user'=>'app_user_data'
2025-10-11 18:11:41 +08:00
];
public $test_token = ['57bd45e3a963b372ea2d873e4bd8d1f8','e0966788d02cc93290d9d674921d9715'];
protected $base_call_method = ['内部'];
protected $token_time = 30;//30天的秒数
protected $return_data_all = [
// '0' => ['success',[]],
'10001'=>'关键参数缺失',
'10002'=>'操作失败',
'10003'=>'信息核实错误',
'10004'=>'未找到有效数据',
'10005'=>'参数格式错误',
'10006'=>'参数不能为空',
'10007'=>'参数错误',
'10008'=>'',
'10009'=>'',
'10010'=>'自定义信息',
'20001'=>'登录失效',
'99999'=>'网络异常,请稍后重试',
];
// 加 bcadd(,,20)
// 减 bcsub(,,20)
// 乘 bcmul(,,20)
// 除 bcdiv(,,20)
################################################################接口################################################################
################################################################接口################################################################
################################################################接口################################################################
// 接口记录
public function record_api_log($params, $error = null, $response = null){
$logContent = "接口请求参数:" . json_encode($params, JSON_UNESCAPED_UNICODE) . PHP_EOL;
if ($error) {
$logContent .= "错误信息:" . $error['all_content'] . PHP_EOL;
if(!cache($error['flie']."_".$error['line'])){
cache($error['flie']."_".$error['line'],"API错误",3600);
$this->send_email_api_error(["tsf3920322@126.com"],['title'=>'新Reedaw接口报错','from_user_name'=>'Reedaw-API','content'=>$logContent]);
}
}
if ($response) {
$logContent .= "返回信息:" . json_encode($response, JSON_UNESCAPED_UNICODE) . PHP_EOL;
}
// 使用ThinkPHP的日志记录方法
Log::record($logContent, 'api_log');
}
// 检查变量是否是一个只有数字的一维数组
public function is_num_array($array = [1,2,3]) {
if (!is_array($array)) {
return false; // 变量不是数组
}
foreach ($array as $value) {
if (!is_numeric($value)) {
return false; // 数组中包含非数字元素
}
}
$result = Db::table($this->base_use_db_name['2'])->where(['is_del'=>0])->cache(true,600)->select();//查询结果缓存3600秒
if(empty(array_diff($array, array_column($result, 'id')))){
return true;// 数组是一维的且只包含数字,且已经跟数据库比对过,每个数值都是有效
}else{
return false;//跟数据库比对过,存在无效数值
}
}
public function validate_user_identity($data) {
$validate_user = Db::table($this->base_use_db_name['3'])->where(['id'=>$data])->count();
if($validate_user<=0){
return false;
}else{
return true;
}
}
2026-03-06 18:02:49 +08:00
// 判断字符串是手机还是邮箱(有用)
2025-10-11 18:11:41 +08:00
public function is_tel_email($str) {
// 手机号码的正则表达式(中国大陆格式)(下面正则实际判断的是是否为11位数字)
$mobilePattern = '/^\d{11}$/';
// 电子邮件地址的正则表达式
$emailPattern = '/^[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/';
// 判断是否为手机号码
if (preg_match($mobilePattern, $str)) {
return 'tel';
}
// 判断是否为电子邮件地址
if (preg_match($emailPattern, $str)) {
return 'email';
}
// 如果都不是,返回其他
return false;
}
2026-03-06 18:02:49 +08:00
// 计算年龄(有用)
2025-10-11 18:11:41 +08:00
public function calculate_age($data = '1991-04-20'){
$today = time(); // 获取当前时间的 Unix 时间戳
$birthDate = strtotime($data); // 将出生日期字符串转换为 Unix 时间戳
if ($birthDate !== false) {
$age = date('Y', $today) - date('Y', $birthDate);
// 如果当前年份的月份和日期小于出生年份的月份和日期,那么年龄减一
if (date('m-d', $today) < date('m-d', $birthDate)) {
$age--;
}
return $age;
} else {
return false;
}
}
// 秒转化格式00:00:00
public function handle_hour_branch_second($data = '2000'){
$data = abs($data);
$hours = intval($data / 3600);
$minutes = intval(($data % 3600) / 60);
$remainingSeconds = $data % 60;
return [
'h' => str_pad($hours, 2, '0', STR_PAD_LEFT),
'm' => str_pad($minutes, 2, '0', STR_PAD_LEFT),
's' => str_pad($remainingSeconds, 2, '0', STR_PAD_LEFT)
];
}
// 判断token是否过期
public function token_time_validate($token){
// 591b70e0d80b5fa6d77e6e1384453ab9
if(is_string($token)){
$length = strlen($token);
if ($length < 10 ) {
Log::record('用户尝试更新token时间token' . $token.',但是更新token失败字符串长度小于10', 'token_log');
return ['state'=>false,'language'=>null];
}
}else{
Log::record('用户尝试更新token时间token' . $token.',但是更新token失败不是字符串', 'token_log');
return ['state'=>false,'language'=>null];
}
$user_login = Db::table($this->base_use_db_name['6'])->where(['token'=>$token])->field('id,login_time,language')->find();
if(!$user_login){
Log::record('用户尝试更新token时间token' . $token.',但是更新token失败未找到用户token', 'token_log');
return ['state'=>false,'language'=>null];
}
// 创建 DateTime 对象来表示指定的日期和时间
$specifiedDateTime = new \DateTime($user_login['login_time']);
// 获取当前时间的 DateTime 对象
$currentDateTime = new \DateTime();
// 计算两个日期之间的差异(以秒为单位)
$interval = $currentDateTime->diff($specifiedDateTime);
// 将差异转换为天数(注意:这里的天数可能不是整数,因为差异可能包括小时、分钟等)
$daysDifference = $interval->days;
// 如果需要更精确的计算(包括小时、分钟等转换成的天数),可以使用以下方式:
// $totalSecondsDifference = $interval->format('%a') * 86400 + $interval->format('%h') * 3600 + $interval->format('%i') * 60 + $interval->format('%s');
// $daysDifference = floor($totalSecondsDifference / 86400); // 将总秒数转换为天数并取整
// 判断差异是否超过指定的天数
if ($daysDifference > $this->token_time) {
// echo "超过 {$specifiedDays} 天";
Log::record('用户尝试更新token时间token' . $token.',但是更新token失败原因没有找到该token,或该token已经超过30天', 'token_log');
return ['state'=>false,'language'=>$user_login['language']];
} else {
// echo "未超过 {$specifiedDays} 天";
$user_login = Db::table($this->base_use_db_name['6'])->where(['token'=>$token])->update(['login_time'=>date('Y-m-d H:i:s')]);
if($user_login){
Log::record('用户尝试更新token时间token' . $token.',记录成功,最新的时间为'.date('Y-m-d H:i:s'), 'token_log');
return ['state'=>true,'language'=>$user_login['language']];
}else{
Log::record('用户尝试更新token时间token' . $token.',但是更新token失败数据库更新时间未成功', 'token_log');
return ['state'=>true,'language'=>$user_login['language']];
}
}
}
// 计算天数
public function daysSince($pastDate,$now = false)
{
// 创建一个表示过去日期的 DateTime 对象
$past = new \DateTime($pastDate);
if($now === false){
// 创建一个表示当前日期的 DateTime 对象
$now = new \DateTime();
}else{
$now = new \DateTime($now);
}
// 使用 DateTime::diff() 方法计算两个日期之间的差值
$interval = $past->diff($now);
// 返回相差的天数
return $interval->format('%a');
}
2026-03-06 18:02:49 +08:00
// 计算月龄(有用)
2025-10-11 18:11:41 +08:00
public function calculateAgeInMonthsWithPrecision($birthDateStr) {
// 获取当前日期
$now = new \DateTime();
// 将出生日期字符串转换为 DateTime 对象
$birthDate = \DateTime::createFromFormat('Y-m-d', $birthDateStr);
// 计算两者之间的差距(以月为单位,包含部分月份的小数)
$interval = $now->diff($birthDate);
$ageInMonths = $interval->y * 12 + $interval->m; // 年份乘以12加上月份
$remainingDays = $interval->d; // 当前月内的剩余天数
// 将剩余天数转换为小数月份假设一个月为30天进行近似计算
$partialMonth = $remainingDays / 30;
// 结果精确到小数点后两位
// $ageInMonthsPrecise = round($ageInMonths + $partialMonth, 2);
// 整月+剩余月取整
$ageInMonthsPrecise = intval($ageInMonths + $partialMonth);
return $ageInMonthsPrecise;
}
2026-03-06 18:02:49 +08:00
// // 曲线页面-底部统计动作
// public function base_target_initial_cumulative_weight($data = []){
// // 第一种:用户详情(所有数据都有)
// // 第二种:手动记录(只有最新体重)
// // 第三种:修改原始体重(只有原始体重)
// // $result_data['target_weight'] 目标体重
// // $result_data['initial_weight'] 最初体重
// // $result_data['weight'] 最近一次测量重量
// // $result_data['initial_date'] 初始体重日期
// if(count($data) > 0){
// $result_data['target_weight'] = $data['target_weight'];
// $result_data['initial_weight'] = $data['initial_weight'];
// $result_data['cumulative_weight'] = bcsub($data['weight'],$data['initial_weight'],2);
// $result_data['cumulative_day'] = $data['initial_date'] == 0?0:$this->daysSince($data['initial_date']);
// }else{
// $result_data['target_weight'] = 0;
// $result_data['initial_weight'] = 0;
// $result_data['cumulative_weight'] = 0;
// $result_data['cumulative_day'] = 0;
// }
// return $result_data;
// }
2025-10-11 18:11:41 +08:00
// 判断一个参数是否为数字且大于等于0
public function isPositiveNumber($value) {
return is_numeric($value) && $value >= 0;
}
// 判断是否为整型,或者字符串类型的整型数字
public function isValidInteger($var) {
// 直接检查是否为整型
if (is_int($var)) {
return true;
}
// 检查是否为字符串且是有效的整数表示
if (is_string($var) && filter_var($var, FILTER_VALIDATE_INT) !== false) {
return true;
}
// 其他情况
return false;
}
// 判断一个字符串是否为两位以内小数
public function isTwoDecimalOrLess($str) {
return preg_match('/^\d*(\.\d{1,2})?$/', $str) === 1;
}
// 获取用户肺活量的标准值
public function get_vitalcapacity_data($id){
$standard_data = [
['min_val'=>'90','max_val'=>'100','text'=>'优秀','color'=>'#6492F6'],
['min_val'=>'80','max_val'=>'89','text'=>'良好','color'=>'#5AD06D'],
['min_val'=>'60','max_val'=>'79','text'=>'及格','color'=>'#FFAB00'],
['min_val'=>'10','max_val'=>'59','text'=>'不及格','color'=>'#FF5656'],
['min_val'=>'0','max_val'=>'9','text'=>'无效','color'=>'#FF5656'],
];
$grade = Db::table($this->base_use_db_name['3'])->where(['id'=>$id])->field('id,grade,gender,birthday')->find();
if(!$grade){
return [];
}
if($grade['grade'] == 'nothing'){
// 计算年龄判断是属于哪个年级
$user_age = $this->calculate_age($grade['birthday']);
if($user_age <= 7){
$grade['grade'] = 'grade_s_1';
}else if($user_age == 8){
$grade['grade'] = 'grade_s_2';
}else if($user_age == 9){
$grade['grade'] = 'grade_s_3';
}else if($user_age == 10){
$grade['grade'] = 'grade_s_4';
}else if($user_age == 11){
$grade['grade'] = 'grade_s_5';
}else if($user_age == 12){
$grade['grade'] = 'grade_s_6';
}else if($user_age == 13){
$grade['grade'] = 'grade_m_1';
}else if($user_age == 14){
$grade['grade'] = 'grade_m_2';
}else if($user_age == 15){
$grade['grade'] = 'grade_m_3';
}else if($user_age == 16){
$grade['grade'] = 'grade_h_1';
}else if($user_age == 17){
$grade['grade'] = 'grade_h_2';
}else if($user_age == 18){
$grade['grade'] = 'grade_h_3';
}else if($user_age == 19 || $user_age == 20){
$grade['grade'] = 'grade_u_12';
}else if($user_age >= 21){
$grade['grade'] = 'grade_u_34';
}
}
$sql_min = "WITH RankedGrades AS (
SELECT
id,
level,
".$grade['grade'].",
ROW_NUMBER() OVER(PARTITION BY level ORDER BY ".$grade['grade']." ASC, id ASC) AS rn
FROM
".$this->base_use_db_name['4']."
WHERE
sex = ".$grade['gender']."
)
SELECT
id,
level,
".$grade['grade']."
FROM
RankedGrades
WHERE
rn = 1";
$result_min = Db::query($sql_min);
foreach ($result_min as $key => $value) {
foreach ($standard_data as $sdk => $sdv) {
if($value['level'] == $sdv['text']){
$standard_data[$sdk]['min_val'] = $value[$grade['grade']];
}
}
}
for ($i=count($standard_data)-1; $i >= 1; $i--) {
$standard_data[$i]['max_val'] = $standard_data[$i-1]['min_val'];
}
$standard_data[0]['max_val'] = '5140';
return $standard_data;
}
// 时间日期转换
public function addCurrentTimeToDateString($dateStr) {
// 将日期字符串转换为DateTime对象
$dateTime = new \DateTime($dateStr);
// 获取当前的时分秒
$currentTime = new \DateTime('now');
$hours = $currentTime->format('H');
$minutes = $currentTime->format('i');
$seconds = $currentTime->format('s');
// 设置DateTime对象的时间部分为当前时间
$dateTime->setTime($hours, $minutes, $seconds);
// 返回格式化为"Y-m-d H:i:s"的字符串
return $dateTime->format('Y-m-d H:i:s');
}
// 处理分秒变秒
public function convertMinutesSecondsToStringSeconds($timeString) {
// 分割字符串获取分钟和秒
list($minutes, $seconds) = explode(':', $timeString);
// 将分钟和秒转换为秒
$totalSeconds = ($minutes * 60) + intval($seconds); // 确保秒是整数
return $totalSeconds;
}
// 转换数字"90.00", "88.11", "66.50", ".00"为正常数字
public function convertStringToNumber($str) {
// 去除字符串两端的空格(如果有的话)
$str = trim($str);
// 检查字符串是否为空或只包含小数点
if ($str === '' || $str === '.') {
return 0;
}
// 尝试将字符串转换为浮点数
$number = (float)$str;
// 格式化浮点数,去掉末尾多余的零
$formattedNumber = rtrim(rtrim(sprintf('%.2f', $number), '0'), '.');
// 如果结果为空字符串(比如,原字符串是“.00”则返回0
if ($formattedNumber === '') {
return '0';
}
// 返回结果,转换为整数如果小数点后没有数字
if (strpos($formattedNumber, '.') === false) {
$formattedNumber = (int)$formattedNumber;
return "$formattedNumber";
}
return $formattedNumber;
}
// 时间加一或者减一
public function adjustDateTime($datetimeStr, $type) {
// 将时间字符串转换为时间戳
$timestamp = strtotime($datetimeStr);
// 检查时间戳是否有效
if ($timestamp === false) {
return "无效的日期时间格式";
}
// 根据$type参数调整时间戳
switch ($type) {
case 'add':
$newTimestamp = strtotime('+1 day', $timestamp);
break;
case 'subtract':
$newTimestamp = strtotime('-1 day', $timestamp);
break;
default:
return false;
}
// 将新的时间戳转换回日期时间字符串
$newDateTimeStr = date('Y-m-d', $newTimestamp);
return $newDateTimeStr;
}
// 对于任意浮点字符串的指定位四舍五入
public function roundToString($numberStr, $numDecimals) {
// 将字符串转换为浮点数
$number = floatval($numberStr);
// 四舍五入到指定的小数位数
$roundedNumber = round($number, $numDecimals);
// 将结果转换回字符串
return strval($roundedNumber);
}
// 发送一个PSOT请求
public function postRequest($url, $data = [], $headers = []) {
$ch = curl_init(); // 初始化cURL会话
if (!$ch) {
return [
'error' => true,
'message' => 'cURL init failed'
];
}
// 设置cURL选项
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 禁用证书验证
curl_setopt($ch, CURLOPT_URL, $url); // 要请求的URL
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 将curl_exec()获取的信息以文件流的形式返回,而不是直接输出
curl_setopt($ch, CURLOPT_POST, true); // 发送一个常规的POST请求
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); // POST数据
// 设置请求头
if (!empty($headers)) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}else{
// 如果需要发送JSON数据可以使用以下设置
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
}
// 执行cURL会话
$response = curl_exec($ch);
if ($response === false) {
$error = curl_error($ch);
curl_close($ch);
return [
'error' => true,
'message' => "cURL Error: $error"
];
}
$decodedResponse = json_decode($response, true);
$jsonError = json_last_error();
curl_close($ch);
if ($jsonError !== JSON_ERROR_NONE) {
return [
'error' => true,
'message' => 'Invalid JSON Response',
'raw_response' => $response
];
}
return $decodedResponse;
}
public function msg($data,$str='',$result = []){
if(is_array($data)){
if($str != ''){
return json(['code'=>0,'msg'=>$str,'data'=>$data]);
}else{
return json(['code'=>0,'msg'=>'操作成功','data'=>$data]);
}
}else{
if($str != ''){
return json(['code'=>$data,'msg'=>$str,'data'=>$result]);
}
return json(['code'=>$data,'msg'=>$this->return_data_all[$data],'data'=>$result]);
}
}
/* 接口说明(发邮件)
* $address收件人的邮箱地址 数组 格式: ['460834639@qq.com','460834639@qq.com'.......]
* $content邮件的主题数据信息 数组 格式:['title'=>'123','from_user_name'=>'123','content'=>'123']
* $annex附件路径信息 字符串
*/
public function send_email_api_error($address,$content,$annex=''){
// $ad = '460834639@qq.com';
$ad1 = '295155911@qq.com';
$mail = new PHPMailer(); //实例化
$mail->IsSMTP(); // 启用SMTP
$mail->Host = "smtp.126.com"; //SMTP服务器 163邮箱例子
$mail->Port = 465; //邮件发送端口
$mail->SMTPAuth = true; //启用SMTP认证
$mail->SMTPSecure = 'ssl';
$mail->CharSet = "UTF-8"; //字符集
$mail->Encoding = "base64"; //编码方式
$mail->Username = "tsf3920322@126.com"; //你的邮箱
$mail->Password = "HLWXNRPUCTHJFIIX"; //你的密码(邮箱后台的授权密码)
$mail->From = "tsf3920322@126.com"; //发件人地址(也就是你的邮箱)
// $mail->Subject = "微盟测试邮件"; //邮件标题
$mail->Subject = $content['title']; //邮件标题
// $mail->FromName = "微盟体测中心"; //发件人姓名
$mail->FromName = $content['from_user_name']; //发件人姓名
for ($i=0; $i < count($address); $i++) {
$mail->AddAddress($address[$i], ""); //添加收件人(地址,昵称)
}
if($annex != ''){
// $url = ROOT_PATH. 'public' . DS . 'tsf' . DS .'demoooo.jpg';
$mail->AddAttachment($annex,''); // 添加附件,并指定名称
}
$mail->IsHTML(true); //支持html格式内容
$neirong = $content['content'];
$mail->Body = $neirong; //邮件主体内容
//发送
if (!$mail->Send()) {
return ['code' => 10003,'msg'=>$mail->ErrorInfo];
// return $mail->ErrorInfo;
} else {
return ['code' => 0];
// return 'success';
}
}
/**
* 验证数据是否符合指定类型要求
*
* @param mixed $data 要验证的数据
* @param string $type 验证类型 (str, num, intnum, datetime)
* @return bool 验证结果
* @throws InvalidArgumentException 当传入未知类型时抛出异常
*/
public function verify_data_is_ok($data, string $type): bool
{
switch ($type) {
case 'str':
// 字符串验证 - 只要数据类型是字符串即可
return is_string($data);
case 'num':
// 数字验证 - 接受数字、数字字符串、小数和小数字符串
// 注意:布尔值、科学计数法等也会被 is_numeric 认为是数字
return is_numeric($data);
case 'intnum':
// 整数验证 - 必须是整型或纯整数字符串
// 使用 filter_var 同时验证整型和整数字符串
2025-11-21 19:13:01 +08:00
// 必须是 >0 的整数或字符串整数
$filtered = filter_var($data, FILTER_VALIDATE_INT);
return $filtered !== false && $filtered > 0;
2026-03-06 18:02:49 +08:00
case 'arr_intnum':
// 一维整数数组验证 - 必须是非空数组,且所有元素都是整数
// 1. 先检查是否是数组
if (!is_array($data)) {
return false;
}
// 2. 检查数组是否为空
if (empty($data)) {
return false;
}
// 3. 检查是否是一维数组
foreach ($data as $item) {
if (is_array($item)) {
return false; // 包含多维数组,不是一维数组
}
}
// 4. 验证所有元素都是整数
foreach ($data as $item) {
$filtered = filter_var($item, FILTER_VALIDATE_INT);
if ($filtered === false) {
return false; // 不是整数
}
}
return true;
2025-10-11 18:11:41 +08:00
case 'datetime':
// 日期时间验证 - 保持原有逻辑不变
$formats = ['Y-m-d', 'Y-m-d H:i:s'];
foreach ($formats as $format) {
$dateTime = \DateTime::createFromFormat($format, $data);
if ($dateTime && $dateTime->format($format) === $data) {
return true;
}
}
return false;
default:
throw new \InvalidArgumentException("未知的验证类型: {$type}");
}
}
2026-03-06 18:02:49 +08:00
// 处理身高体重的单位转换它们为cm和kg。(有用)
2025-10-11 18:11:41 +08:00
public function convertHeightAndWeight($height, $weight) {
// 加 bcadd(,,20)
// 减 bcsub(,,20)
// 乘 bcmul(,,20)
// 除 bcdiv(,,20)
// 定义单位转换比例
$heightConversion = [
'cm' => 1,
'inch' => 2.54,
'ft-in' => function($value) {
list($ft, $in) = explode('-', $value);
return $ft * 30.48 + $in * 2.54; // 1 foot = 30.48 cm, 1 inch = 2.54 cm
}
];
$weightConversion = [
'kg' => 1,
'斤' => 0.5, // 1斤 = 0.5kg
'st:lb' => function($value) {
list($st, $lb) = explode(':', $value);
return $st * 6.35029318 + $lb * 0.45359237; // 1 stone = 6.35029318 kg, 1 lb = 0.45359237 kg
},
'lb' => 0.45359237 // 1 lb = 0.45359237 kg
];
// 处理 height
if (preg_match('/([\d.]+)(cm|inch|ft-in)/', $height, $matches)) {
// $heightValue = floatval($matches[1]);
$heightValue = $matches[1];
$heightUnit = $matches[2];
if($heightUnit == 'ft-in'){
// 如果单位为st:lb但是数据格式不对
$heightValue = str_replace($heightUnit, "", $height);
if(count(explode('-', $heightValue)) < 2){
$heightValue = str_replace("-", "", $heightValue);
$heightValue = $heightValue."-0";
}
}
if (isset($heightConversion[$heightUnit])) {
if (is_callable($heightConversion[$heightUnit])) {
$heightInCm = $heightConversion[$heightUnit]($heightValue);
} else {
$heightInCm = $heightValue * $heightConversion[$heightUnit];
}
} else {
// 未知单位,返回错误
$heightInCm = false;
}
} else {
// 未找到指定单位判断是否是数字
if (preg_match('/^-?\d+(\.\d+)?$/', $height)) {
$heightInCm = $height;
} else {
$heightInCm = false;
}
}
// 处理 weight
if (preg_match('/([\d.:]+)(kg|斤|st:lb|lb)/', $weight, $matches)) {
$weightValue = $matches[1];
$weightUnit = $matches[2];
if($weightUnit == 'st:lb'){
// 如果单位为st:lb但是数据格式不对
$weightValue = str_replace($weightUnit, "", $weight);
if(count(explode(':', $weightValue)) < 2){
$weightValue = str_replace(":", "", $weightValue);
$weightValue = $weightValue.":0";
}
}
if (isset($weightConversion[$weightUnit])) {
if (is_callable($weightConversion[$weightUnit])) {
$weightInKg = $weightConversion[$weightUnit]($weightValue);
} else {
$weightInKg = $weightValue * $weightConversion[$weightUnit];
}
} else {
// 未知单位,返回错误
$weightInKg = false;
}
} else {
// 未找到指定单位判断是否是数字
if (preg_match('/^-?\d+(\.\d+)?$/', $weight)) {
$weightInKg = $weight;
} else {
$weightInKg = false;
}
}
return [
'height_in_cm' => bcmul($heightInCm,1,2),
'weight_in_kg' => bcmul($weightInKg,1,2)
];
}
2026-03-06 18:02:49 +08:00
##########################################################以下是厨房秤的内容##########################################################
##########################################################以下是厨房秤的内容##########################################################
##########################################################以下是厨房秤的内容##########################################################
2025-10-11 18:11:41 +08:00
2026-03-06 18:02:49 +08:00
// 计算常规卡路里
public function count_user_nutrition_all($data){
// 计算基础代谢率BMR
if($data['gender'] == 1){
// 男性BMR = 10 × 体重kg + 6.25 × 身高cm - 5 × 年龄(岁) + 5
$bmr = bcmul(10,$data['weight'],20);
$bmr = bcadd($bmr,bcmul(6.25,$data['height'],20),20);
$bmr = bcsub($bmr,bcmul(5,$data['age_num'],20),20);
$bmr = bcadd($bmr,5,2);
}else if($data['gender'] == 2){
// 女性BMR = 10 × 体重kg + 6.25 × 身高cm - 5 × 年龄(岁) - 161
$bmr = bcmul(10,$data['weight'],20);
$bmr = bcadd($bmr,bcmul(6.25,$data['height'],20),20);
$bmr = bcsub($bmr,bcmul(5,$data['age_num'],20),20);
$bmr = bcsub($bmr,161,2);
}else{
return $this->msg(10003,'性别未知');
}
// 每日总能量消耗TDEE
// 久坐很少或没有运动BMR × 1.2
// 轻度活动每周1-3天轻度运动BMR × 1.375
// 中度活动每周3-5天中度运动BMR × 1.55
// 高度活动每周6-7天高强度运动BMR × 1.725
// 极高活动体力劳动或每天高强度训练BMR × 1.9
if(array_key_exists('activity_level',$data)){
if($data['activity_level'] != null){
$tdee = bcmul($bmr,$data['activity_level'],2);
}else{
$tdee = bcmul($bmr,1.55,2);
}
}else{
$tdee = bcmul($bmr,1.55,2);
}
// 碳水化合物通常占总热量的45-65%
// 蛋白质通常占总热量的10-35%
// 脂肪通常占总热量的20-35%
// 孩子&成年人碳水化合物50%蛋白质20%脂肪30%。
// 老人碳水化合物50%蛋白质25%脂肪25%。
// 建议每日摄入量计算:
// 1.碳水化合物(克): (TDEE × 碳水化合物比例) / 4
// 2.蛋白质(克):(TDEE × 蛋白质比例) / 4
// 3.脂肪(克): (TDEE × 脂肪比例) / 9
2025-10-11 18:11:41 +08:00
2026-03-06 18:02:49 +08:00
$carbohydrate_p = 0.5;
$carbohydrate = bcdiv(bcmul($tdee,0.5,20),4,2);
if($data['age_num'] < 65){
$protein_p = 0.2;
$fat_p = 0.3;
$protein = bcdiv(bcmul($tdee,0.2,20),4,2);
$fat = bcdiv(bcmul($tdee,0.3,20),9,2);
}else{
$protein_p = 0.25;
$fat_p = 0.25;
$protein = bcdiv(bcmul($tdee,0.25,20),4,2);
$fat =bcdiv(bcmul($tdee,0.25,20),9,2);
}
return ['kcal'=>$tdee,'carbohydrate'=>$carbohydrate,'protein'=>$protein,'fat'=>$fat,'bmr'=>$bmr,'carbohydrate_p'=>$carbohydrate_p,'protein_p'=>$protein_p,'fat_p'=>$fat_p];
}
2025-10-11 18:11:41 +08:00
2026-03-06 18:02:49 +08:00
// 计算营养物质
public function calculate_nutrients($data){
// dump($data);
$food_id_arr = [];
2025-10-11 18:11:41 +08:00
for ($i=0; $i < count($data); $i++) {
2026-03-06 18:02:49 +08:00
$food_id_arr[] = $data[$i]['food_id'];
}
$cfc = Db::connect('cfc_db');
// dump($data);
// dump(implode(",",$food_id_arr));
$nutrients_list = $cfc->table($this->base_use_db_name['foodlist4'])
->where("father_id in (".implode(",",$food_id_arr).")")
// ->field()
->select();
2025-10-11 18:11:41 +08:00
2026-03-06 18:02:49 +08:00
$nutrients_arr = ['VitaminA','VitaminB1','VitaminB2','VitaminB6','VitaminB12','VitaminD','VitaminK','Niacin','VitaminC','VitaminE','FolicAcid','Biotin','PantothenicAcid','TotalCholine','Ca','Phosphorus','Kalium','Mg','Na','Fe','Zn','Se','Cu','Mn','Iodine'];
// dump($nutrients_list);
// die;
// 加 bcadd(,,20)
// 减 bcsub(,,20)
// 乘 bcmul(,,20)
// 除 bcdiv(,,20)
for ($i=0; $i < count($data); $i++) {
$zong_all = bcadd($data[$i]['protein_val'],bcadd($data[$i]['fat_val'],$data[$i]['carbohydrate_val'],20),20);
$data[$i]['nutrients_four'][] = [
'name' => '卡路里',
'unit' => 'kcal',
'color' => '',
'value' => $data[$i]['kcal_val'],
'proportion' => 0,
];
$data[$i]['nutrients_four'][] = [
'name' => '蛋白质',
'unit' => 'g',
'color' => '#5180D8',
'value' => $data[$i]['protein_val'],
'proportion' => $zong_all == 0?0:bcmul(bcdiv($data[$i]['protein_val'],$zong_all,2),100,0),
];
$data[$i]['nutrients_four'][] = [
'name' => '脂肪',
'unit' => 'g',
'color' => '#ED7886',
'value' => $data[$i]['fat_val'],
'proportion' => $zong_all == 0?0:bcmul(bcdiv($data[$i]['fat_val'],$zong_all,2),100,0),
];
$data[$i]['nutrients_four'][] = [
'name' => '碳水化合物',
'unit' => 'g',
'color' => '#FFB169',
'value' => $data[$i]['carbohydrate_val'],
'proportion' => $zong_all == 0?0:bcmul(bcdiv($data[$i]['carbohydrate_val'],$zong_all,2),100,0),
];
$data[$i]['nutrients_list'][] = [
'name' => 'Calorie',
'name_ch' => '卡路里',
'unit' => 'kcal',
'value' => $data[$i]['kcal_val'],
'type' => 1,
'type_name' => '能量及宏量营养素',
'color' => '#C4FFE0',
];
$data[$i]['nutrients_list'][] = [
'name' => 'Protein',
'name_ch' => '蛋白质',
'unit' => 'g',
'value' => $data[$i]['protein_val'],
'type' => 1,
'type_name' => '能量及宏量营养素',
'color' => '#C4FFE0',
];
$data[$i]['nutrients_list'][] = [
'name' => 'Fat',
'name_ch' => '脂肪',
'unit' => 'g',
'value' => $data[$i]['fat_val'],
'type' => 1,
'type_name' => '能量及宏量营养素',
'color' => '#C4FFE0',
];
$data[$i]['nutrients_list'][] = [
'name' => 'Carbohydrate',
'name_ch' => '碳水化合物',
'unit' => 'g',
'value' => $data[$i]['carbohydrate_val'],
'type' => 1,
'type_name' => '能量及宏量营养素',
'color' => '#C4FFE0',
];
foreach ($nutrients_list as $key => $value) {
if($value['father_id'] == $data[$i]['food_id']){
if(in_array($value['name'],$nutrients_arr)){
$data[$i]['nutrients_list'][] = [
'name' => $value['name'],
'name_ch' => $value['name_ch'],
'unit' => $value['unit'],
'value' => bcmul($value['value'],bcdiv($data[$i]['weight'],100,20),2),
'type' => $value['type'],
'type_name' => $value['type'] == 1?'能量及宏量营养素':($value['type'] == 2?'维生素':($value['type'] == 3?'矿物质':'')),
'color' => $value['type'] == 1?'#C4FFE0':($value['type'] == 2?'#FFEFB7':($value['type'] == 3?'#7DA8E0':'')),
];
}
}
2025-10-11 18:11:41 +08:00
}
2026-03-06 18:02:49 +08:00
}
return $data;
}
public function add_search_history_action($data){
// 添加一条搜索记录start
// $data['id']是账号id
// $cfc = Db::connect('cfc_db');
$insert_search_log = Db::table($this->base_use_db_name['search_history'])->where(['user_id'=>$data['id'],'keyword'=>$data['search_data'],'type'=>$data['type']])->field('id,search_count')->find();
if($insert_search_log){
Db::table($this->base_use_db_name['search_history'])->where(['id'=>$insert_search_log['id']])->update([
'search_count'=>$insert_search_log['search_count']+1,
'last_searched_at'=>date('Y-m-d H:i:s'),
]);
}else{
Db::table($this->base_use_db_name['search_history'])->insert([
'user_id'=>$data['id'],
'keyword'=>$data['search_data'],
'type'=>$data['type'],
2025-10-11 18:11:41 +08:00
]);
}
2026-03-06 18:02:49 +08:00
// 添加一条搜索记录end
}
/**
* 将重量转换为克(g)
* @param string $weight 重量值
* @param string $unit 单位 (g, oz, lb, lb:oz)
* @return float 转换后的克重
*/
public function convertWeightToGrams($weight = 100, $unit = 'oz') {
// 定义精确的转换常量
$G_PER_OZ = '28.349523125';
$G_PER_LB = '453.59237';
$unit = strtolower($unit);
$result = 0;
switch ($unit) {
case 'g':
case '克':
// 已经是克,直接返回
$result = $weight;
break;
case 'oz':
case '盎司':
// 盎司转克
$result = bcmul($weight,$G_PER_OZ,2);
break;
case 'lb':
case '磅':
// 磅转克
$result = bcmul($weight,$G_PER_LB,2);
break;
case 'lb:oz':
case '磅:盎司':
// 磅:盎司复合单位处理
if (strpos($weight, ':') !== false) {
$temporary_data = explode(':', $weight);
$result = bcadd(bcmul($temporary_data[0],$G_PER_LB,20),bcmul($temporary_data[1],$G_PER_OZ,20),20);
} else {
// 如果格式不正确可以抛出异常或返回0
$result = '0';
}
break;
default:
$result = '0';
}
// 保留两位小数并返回(目前不做截取,全额返回)
return $result;
2025-10-11 18:11:41 +08:00
}
2026-03-06 18:02:49 +08:00
// public function ceshiyong($aa = 4,$gd = 0.2){
// phpinfo();
// die;
// $token = 'cd3f27cf4c4002170ea7bceeb723ac91';
// $data = Db::table('pc_bmistand2')->select();
// for ($i=0; $i < count($data); $i++) {
// foreach ($data[$i] as $key => $value) {
// $data[$i][$key] = str_replace(' ', '',$data[$i][$key]);
// }
// Db::table('pc_bmistand2')->where(['id'=>$data[$i]['id']])->update([
// 'month'=>$data[$i]['month'],
// 'sex'=>$data[$i]['sex'],
// // 'f3sd'=>$data[$i]['f3sd'],
// // 'f2sd'=>$data[$i]['f2sd'],
// 'f1sd'=>$data[$i]['f1sd'],
// 'median'=>$data[$i]['median'],
// 'z1sd'=>$data[$i]['z1sd'],
// 'z2sd'=>$data[$i]['z2sd'],
// // 'z3sd'=>$data[$i]['z3sd'],
// ]);
// }
// die;
// // $this->send_email_api_error(["tsf3920322@126.com"],['title'=>'接口报错','from_user_name'=>'青测API','content'=>'123']);
// }
2025-10-11 18:11:41 +08:00
}