1900 lines
70 KiB
PHP
Executable File
1900 lines
70 KiB
PHP
Executable File
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace App\Services;
|
||
|
||
use App\Models\Ann;
|
||
use App\Models\Config;
|
||
use App\Models\DetectLog;
|
||
use App\Models\EmailQueue;
|
||
use App\Models\HourlyUsage;
|
||
use App\Models\Invoice;
|
||
use App\Models\Node;
|
||
use App\Models\OnlineLog;
|
||
use App\Models\Order;
|
||
use App\Models\Paylist;
|
||
use App\Models\SubscribeLog;
|
||
use App\Models\User;
|
||
use App\Models\TgStep;
|
||
use App\Models\Zhuanfas;
|
||
use App\Models\Ducks;
|
||
use App\Models\Visitor;
|
||
use App\Models\CountVisitor;
|
||
use App\Models\CountUser;
|
||
use App\Models\Product;
|
||
use App\Models\UserMoneyLog;
|
||
use App\Models\OrderLog;
|
||
//use App\Models\UserRenew;
|
||
//use App\Models\ExpireConfrm;
|
||
use App\Models\PlanActivated;
|
||
use App\Models\PlanExpired;
|
||
use App\Models\PlanPending;
|
||
use App\Models\PlanQueue;
|
||
use App\Services\TomTool\TgSendFormat;
|
||
use App\Services\IM\Telegram;
|
||
use App\Services\IM\TelegramV2;
|
||
use App\Services\Tg\ReportUser;
|
||
use App\Utils\Tools;
|
||
use DateTime;
|
||
use Exception;
|
||
use GuzzleHttp\Exception\GuzzleException;
|
||
use Psr\Http\Client\ClientExceptionInterface;
|
||
use Telegram\Bot\Exceptions\TelegramSDKException;
|
||
use function array_map;
|
||
use function date;
|
||
use function in_array;
|
||
use function json_decode;
|
||
use function str_replace;
|
||
use function strtotime;
|
||
use function time;
|
||
use const PHP_EOL;
|
||
use App\Models\Smtp as ModelSmtp;
|
||
//use Illuminate\Support\Facades\DB; // 线上可能要开
|
||
|
||
|
||
final class Cron
|
||
{
|
||
|
||
//// 商品自动化
|
||
public static function productAuto(): void
|
||
{
|
||
$i = 0;
|
||
$time = time();
|
||
|
||
//// 售空下架,前提不限时或过期
|
||
$oProduct = Product::where("status", 1)
|
||
->where("stock", "!=", -1)
|
||
->whereRaw("sale_count >= stock")
|
||
->get();
|
||
|
||
if (!$oProduct->isEmpty()) {
|
||
foreach ($oProduct as $oProductRow) {
|
||
|
||
// 不限时 或 过期 >> 下架
|
||
// 不限时是0,自然也小于当前时间
|
||
if ($oProductRow->end_time < $time) {
|
||
$oProductRow->status = 0;
|
||
$oProductRow->save();
|
||
$i++;
|
||
}
|
||
|
||
}
|
||
}
|
||
//// 售空下架 end
|
||
|
||
//// 过期无条件下架,没售空也下架
|
||
$oProduct = Product::where("status", 1)->where("end_time", "!=", 0)->where("end_time", "<", $time)->get();
|
||
if (!$oProduct->isEmpty()) {
|
||
foreach ($oProduct as $oProductRow) {
|
||
$oProductRow->status = 0;
|
||
$oProductRow->save();
|
||
$i++;
|
||
}
|
||
}
|
||
|
||
echo Tools::toDateTime(time()) . ' 下架'.$i.'个商品' . PHP_EOL;
|
||
//// 过期下架 end
|
||
|
||
//// 假销售
|
||
$iRand = rand(1, 288); // 一天288个五分钟(cron),也就是说一天最多假销售288个,没毛病够用
|
||
|
||
$oProduct = Product::where("status", 1)
|
||
->where("stock", "!=", -1)
|
||
->whereRaw("sale_count < stock")
|
||
->where("sale_shadow_oneday", ">=", $iRand)
|
||
->get();
|
||
|
||
if (!$oProduct->isEmpty()) {
|
||
$i = 0;
|
||
foreach ($oProduct as $oProductRow) {
|
||
$oProductRow->sale_count += 1;
|
||
$oProductRow->sale_count_shadow += 1;
|
||
$oProductRow->save();
|
||
$i++;
|
||
}
|
||
echo Tools::toDateTime(time()) . ' 假销售'.$i.'个商品' . PHP_EOL;
|
||
}
|
||
//// 假销售 end
|
||
|
||
}
|
||
|
||
// 数据库清理
|
||
public static function cleanDb(): void
|
||
{
|
||
(new SubscribeLog())->where(
|
||
'request_time',
|
||
'<',
|
||
time() - 86400 * Config::obtain('subscribe_log_retention_days')
|
||
)->delete();
|
||
(new HourlyUsage())->where(
|
||
'date',
|
||
'<',
|
||
date('Y-m-d', time() - 86400 * Config::obtain('traffic_log_retention_days'))
|
||
)->delete();
|
||
(new DetectLog())->where('datetime', '<', time() - 86400 * 3)->delete();
|
||
(new EmailQueue())->where('time', '<', time() - 86400)->delete();
|
||
(new OnlineLog())->where('last_time', '<', time() - 86400)->delete();
|
||
|
||
echo Tools::toDateTime(time()) . ' 数据库清理完成' . PHP_EOL;
|
||
}
|
||
|
||
|
||
// 清理tg step,暂时没用
|
||
public static function clearTgStep(): void
|
||
{
|
||
TgStep::where("date", "<=", date('Y-m-d', strtotime('-1 day')))->delete();
|
||
}
|
||
|
||
// 统计用户数据,入库,发送tg
|
||
public static function userCount(): void
|
||
{
|
||
$sPrevDate = date("Y-m-d", strtotime("-1 day"));
|
||
$sPrevDateStart = date("Y-m-d 00:00:00", strtotime("-1 day"));
|
||
$sPrevDateEnd = date("Y-m-d 23:59:59", strtotime("-1 day"));
|
||
$sPrevTimeStart = strtotime($sPrevDateStart);
|
||
$sPrevTimeEnd = strtotime($sPrevDateEnd);
|
||
$sPrevDate30 = date("Y-m-d", strtotime("-30 day"));
|
||
|
||
//// 访客统计 start
|
||
$aVisitorCount = Visitor::select('from', DB::raw('count(*) as count'))
|
||
->groupBy('from')
|
||
->get()
|
||
->toArray();
|
||
|
||
$aVisitorMix = [];
|
||
foreach ($aVisitorCount as $row) {
|
||
$aVisitorMix[$row['from']]['count'] = $row['count'];
|
||
}
|
||
//// 访客统计 end
|
||
|
||
// 注册数量
|
||
$aRegCount = User::select('from', DB::raw('count(*) as count'))
|
||
->whereDate('reg_date', $sPrevDate)
|
||
->groupBy('from')
|
||
->get()
|
||
->toArray();
|
||
|
||
$aRegMix = [];
|
||
foreach ($aRegCount as $row) {
|
||
|
||
if (isset($row['from'])) {
|
||
$sFrom = $row['from'];
|
||
} else {
|
||
$sFrom = '无';
|
||
}
|
||
|
||
$aRegMix[$sFrom]['count'] = $row['count'];
|
||
}
|
||
|
||
$aOrder = Order::whereBetween("update_time", [$sPrevTimeStart, $sPrevTimeEnd])
|
||
->where("status", "activated")
|
||
->get()
|
||
->toArray();
|
||
|
||
// 标记是否是新用户
|
||
$oUserModel = new User();
|
||
$aUserMix = [];
|
||
|
||
foreach ($aOrder as $row) {
|
||
$oUser = $oUserModel->where("id", $row["user_id"])->first();
|
||
|
||
if (isset($oUser->from)) {
|
||
$sFrom = $oUser->from;
|
||
} else {
|
||
$sFrom = "无";
|
||
}
|
||
|
||
// 初始化用户数据
|
||
if (!isset($aUserMix[$sFrom])) {
|
||
$aUserMix[$sFrom] = [
|
||
'pay_count_new' => 0,
|
||
'money_count_new' => 0,
|
||
'pay_count_old' => 0,
|
||
'money_count_old' => 0,
|
||
'pay_count' => 0,
|
||
'money_count' => 0,
|
||
];
|
||
}
|
||
|
||
// 确保时间比较的正确性
|
||
if (isset($oUser->reg_date) && ($row['update_time'] - strtotime($oUser->reg_date)) < (86400 * 30)) {
|
||
$aUserMix[$sFrom]['pay_count_new']++;
|
||
$aUserMix[$sFrom]['money_count_new'] += $row["price"];
|
||
} else {
|
||
$aUserMix[$sFrom]['pay_count_old']++;
|
||
$aUserMix[$sFrom]['money_count_old'] += $row["price"];
|
||
}
|
||
|
||
$aUserMix[$sFrom]['pay_count']++;
|
||
$aUserMix[$sFrom]['money_count'] += $row["price"];
|
||
}
|
||
|
||
$aAllMix = array_merge($aVisitorMix, $aRegMix, $aUserMix);
|
||
|
||
foreach ($aAllMix as $k => $v) {
|
||
|
||
$oCountUserModel = new CountUser();
|
||
$oCountUserModel->from = $k;
|
||
$oCountUserModel->count_from = $aVisitorMix[$k]['count'] ?? 0;
|
||
$oCountUserModel->count_reg = $aRegMix[$k]['count'] ?? 0;
|
||
$oCountUserModel->count_pay = $aUserMix[$k]['pay_count'] ?? 0;
|
||
$oCountUserModel->count_pay_new = $aUserMix[$k]['pay_count_new'] ?? 0;
|
||
$oCountUserModel->count_pay_old = $aUserMix[$k]['pay_count_old'] ?? 0;
|
||
$oCountUserModel->count_money = $aUserMix[$k]['money_count'] ?? 0;
|
||
$oCountUserModel->count_money_new = $aUserMix[$k]['money_count_new'] ?? 0;
|
||
$oCountUserModel->count_money_old = $aUserMix[$k]['money_count_old'] ?? 0;
|
||
$oCountUserModel->date = $sPrevDate;
|
||
$r = $oCountUserModel->save();
|
||
|
||
}
|
||
|
||
Visitor::truncate();
|
||
|
||
$sMsg = (new ReportUser())->ByDay(1);
|
||
|
||
(new Telegram())->send(0, $sMsg);
|
||
}
|
||
|
||
// public static function visitorCount(): void
|
||
// {
|
||
// $oVisitor = Visitor::select('from', DB::raw('count(*) as count'))
|
||
// ->groupBy('from')
|
||
// ->get();
|
||
//
|
||
// foreach ($oVisitor as $row) {
|
||
//
|
||
// $oCountVisitor = new CountVisitor();
|
||
// $oCountVisitor->from = $row->from;
|
||
// $oCountVisitor->count = $row->count;
|
||
// $oCountVisitor->date = date('Y-m-d', strtotime('-1 day'));
|
||
// $oCountVisitor->save();
|
||
//
|
||
// }
|
||
//
|
||
// Visitor::truncate();
|
||
//
|
||
// // tg报表
|
||
// $aCountVisitor = CountVisitor::where('date', date('Y-m-d', strtotime('-1 day')))->get()->toArray();
|
||
//
|
||
// $sTgReport = '';
|
||
// foreach ($aCountVisitor as $row) {
|
||
//
|
||
// $sTgReport .= $row["from"].":".$row["count"]."\n";
|
||
//
|
||
// }
|
||
//
|
||
// (new Telegram())->send(0, $sTgReport);
|
||
//
|
||
// }
|
||
|
||
// 限制帐户检测
|
||
public static function detectInactiveUser(): void
|
||
{
|
||
$checkin_days = Config::obtain('detect_inactive_user_checkin_days');
|
||
$login_days = Config::obtain('detect_inactive_user_login_days');
|
||
$use_days = Config::obtain('detect_inactive_user_use_days');
|
||
|
||
(new User())->where('is_admin', 0)
|
||
->where('is_inactive', 0)
|
||
->where('last_check_in_time', '<', time() - 86400 * $checkin_days)
|
||
->where('last_login_time', '<', time() - 86400 * $login_days)
|
||
->where('last_use_time', '<', time() - 86400 * $use_days)
|
||
->update(['is_inactive' => 1]);
|
||
|
||
(new User())->where('is_admin', 0)
|
||
->where('is_inactive', 1)
|
||
->where('last_check_in_time', '>', time() - 86400 * $checkin_days)
|
||
->where('last_login_time', '>', time() - 86400 * $login_days)
|
||
->where('last_use_time', '>', time() - 86400 * $use_days)
|
||
->update(['is_inactive' => 0]);
|
||
|
||
echo Tools::toDateTime(time()) .
|
||
' 检测到 ' . (new User())->where('is_inactive', 1)->count() . ' 个账户处于闲置状态' . PHP_EOL;
|
||
}
|
||
|
||
// 节点掉线检测
|
||
public static function detectNodeOffline(): void
|
||
{
|
||
$nodes = (new Node())->where('type', 1)->get();
|
||
|
||
foreach ($nodes as $node) {
|
||
if ($node->getNodeOnlineStatus() >= 0 && $node->online === 1) {
|
||
continue;
|
||
}
|
||
|
||
if ($node->getNodeOnlineStatus() === -1 && $node->online === 1) {
|
||
echo 'Send Node Offline Email to admin users' . PHP_EOL;
|
||
|
||
try {
|
||
Notification::notifyAdmin(
|
||
$_ENV['appName'] . '-系统警告',
|
||
'管理员你好,系统发现节点 ' . $node->name . ' 掉线了,请你及时处理。'
|
||
);
|
||
} catch (GuzzleException|ClientExceptionInterface|TelegramSDKException $e) {
|
||
echo $e->getMessage() . PHP_EOL;
|
||
}
|
||
|
||
if (Config::obtain('telegram_node_offline')) {
|
||
$notice_text = str_replace(
|
||
'%node_name%',
|
||
$node->name,
|
||
Config::obtain('telegram_node_offline_text')
|
||
);
|
||
|
||
try {
|
||
(new Telegram())->send(0, $notice_text);
|
||
} catch (TelegramSDKException $e) {
|
||
echo $e->getMessage();
|
||
}
|
||
}
|
||
|
||
$node->online = 0;
|
||
$node->save();
|
||
|
||
continue;
|
||
}
|
||
|
||
if ($node->getNodeOnlineStatus() === 1 && $node->online === 0) {
|
||
echo 'Send Node Online Email to admin user' . PHP_EOL;
|
||
|
||
try {
|
||
Notification::notifyAdmin(
|
||
$_ENV['appName'] . '-系统提示',
|
||
'管理员你好,系统发现节点 ' . $node->name . ' 恢复上线了。'
|
||
);
|
||
} catch (GuzzleException|ClientExceptionInterface|TelegramSDKException $e) {
|
||
echo $e->getMessage() . PHP_EOL;
|
||
}
|
||
|
||
if (Config::obtain('telegram_node_online')) {
|
||
$notice_text = str_replace(
|
||
'%node_name%',
|
||
$node->name,
|
||
Config::obtain('telegram_node_online_text')
|
||
);
|
||
|
||
try {
|
||
(new Telegram())->send(0, $notice_text);
|
||
} catch (TelegramSDKException $e) {
|
||
echo $e->getMessage();
|
||
}
|
||
}
|
||
|
||
$node->online = 1;
|
||
$node->save();
|
||
}
|
||
}
|
||
|
||
echo Tools::toDateTime(time()) . ' 节点离线检测完成' . PHP_EOL;
|
||
}
|
||
|
||
// 新增,专门检测处理体验用户
|
||
// class=1为免费体验用户,免费体验到期转为0彻底不能用
|
||
public static function expireFreeUserAccount(): void
|
||
{
|
||
$paidUsers = (new User())->where('class', 1)->get();
|
||
|
||
foreach ($paidUsers as $user) {
|
||
if (strtotime($user->class_expire) < time()) {
|
||
$user->u = 0;
|
||
$user->d = 0;
|
||
$user->transfer_today = 0;
|
||
$user->transfer_enable = 0;
|
||
$user->class = 0;
|
||
$user->save();
|
||
}
|
||
}
|
||
|
||
echo Tools::toDateTime(time()) . ' 体验用户过期检测完成' . PHP_EOL;
|
||
}
|
||
|
||
// 付费用户过期检测
|
||
// 现在,付费用户是2+,体验用户是1。付费到期转为体验。
|
||
// 快要到期应该也提醒,目前好像没有,就是没有
|
||
// 作废了
|
||
public static function expirePaidUserAccount(): void
|
||
{
|
||
return; // 作废
|
||
|
||
|
||
$paidUsers = (new User())->where('class', '>=', 2)->get();
|
||
|
||
foreach ($paidUsers as $user) {
|
||
if (strtotime($user->class_expire) < time()) {
|
||
$text = '您好,系统发现您的套餐已经过期了。';
|
||
$reset_traffic = $_ENV['class_expire_reset_traffic'];
|
||
$reset_day = $_ENV['class_expire_reset_day'];
|
||
|
||
// !!!!! 这里目前有问题,$reset_traffic不大于零就乱套了
|
||
if ($reset_traffic >= 0) {
|
||
$user->transfer_enable = Tools::toGB($reset_traffic);
|
||
$user->class_expire = date('Y-m-d H:i:s', strtotime("+$reset_day days"));
|
||
$text .= '已转为免费体验帐户,赠送' . $reset_traffic . 'GB体验流量,'.$reset_day.'天体验时长。';
|
||
}
|
||
|
||
// todo 反水
|
||
// 这里返水的话,等于是直接覆盖的用户不返水,自然过期的用户返水,这到合理,自然过期的才是好用户
|
||
|
||
try {
|
||
Notification::notifyUser($user, $_ENV['appName'] . '-您的套餐已经过期', $text);
|
||
} catch (GuzzleException|ClientExceptionInterface|TelegramSDKException $e) {
|
||
echo $e->getMessage() . PHP_EOL;
|
||
}
|
||
|
||
$user->u = 0;
|
||
$user->d = 0;
|
||
$user->transfer_today = 0;
|
||
$user->class = 1;
|
||
$user->save();
|
||
}
|
||
|
||
//// 流量到期处理 | 不重置了,默认暂停就行
|
||
// 这里,只重置付费用户,不重置免费用户。那么假如免费用户领了60g流量,他就真的能用到没。付费用户则会连带套餐一起重置掉。
|
||
// 应该问题不大,赠送流量有关时,区分免费付费用户,对付费大方(陷阱),对免费抠门。
|
||
// 其实压根就不叠加,套餐流量直接覆盖免费流量。
|
||
// 再者,免费流量
|
||
// 总之,免费流量就是零头,无所谓重置的。
|
||
|
||
// 用户流量用光,或者用户等级到期,就重置。
|
||
// 流量用光时顺便标记订单。在这里标记不容易埋坑。
|
||
// $ud = $user->u + $user->d;
|
||
// if ($ud >= $user->transfer_enable) {
|
||
//
|
||
// // 订单标记为过期
|
||
// // 既然class大于0,就说明肯定有激活的套餐,对吧
|
||
// $activated_order = (new Order())->where('user_id', $user->id)
|
||
// ->where('status', 'activated')
|
||
// ->where('product_type', 'tabp')
|
||
// ->orderBy('id')
|
||
// ->first();
|
||
//
|
||
// // 以防万一,判断一下
|
||
// if (!$activated_order) {
|
||
// $activated_order->status = 'expired';
|
||
// $activated_order->update_time = time();
|
||
// $activated_order->save();
|
||
// }
|
||
//
|
||
//// tomd($activated_order, 1);
|
||
// // 用户流量重置
|
||
// $user->u = 0;
|
||
// $user->d = 0;
|
||
// $user->class = 0;
|
||
// $user->transfer_today = 0;
|
||
// $user->transfer_enable = 0;
|
||
// $user->class_expire = date("Y-m-d H:i:s"); // 用户等级时间到当前,注意订单没变,应该合理
|
||
// $user->save();
|
||
//
|
||
// $sText = "你好,系统发现您的流量已用完,已转为免费体验帐户,可用每日签到获取免费流量。";
|
||
//
|
||
// try {
|
||
// Notification::notifyUser($user, $_ENV['appName'] . '-您的流量已用完', $sText);
|
||
// } catch (GuzzleException|ClientExceptionInterface|TelegramSDKException $e) {
|
||
// echo $e->getMessage() . PHP_EOL;
|
||
// }
|
||
//
|
||
// }
|
||
|
||
//// end
|
||
}
|
||
|
||
echo Tools::toDateTime(time()) . ' 付费用户过期检测完成' . PHP_EOL;
|
||
}
|
||
|
||
// 邮件队列处理
|
||
public static function processEmailQueue(): void
|
||
{
|
||
if ((new EmailQueue())->count() === 0) {
|
||
echo Tools::toDateTime(time()) . ' 邮件队列为空' . PHP_EOL;
|
||
} else {
|
||
//记录当前时间戳
|
||
$timestamp = time();
|
||
//邮件队列处理
|
||
while (true) {
|
||
if (time() - $timestamp > 299) {
|
||
echo Tools::toDateTime(time()) . '邮件队列处理超时,已跳过' . PHP_EOL;
|
||
break;
|
||
}
|
||
|
||
DB::beginTransaction();
|
||
|
||
try {
|
||
|
||
$email_queues_raw = DB::select('SELECT * FROM email_queue where `type` is NULL LIMIT 1 FOR UPDATE SKIP LOCKED');
|
||
|
||
if (count($email_queues_raw) === 0) {
|
||
DB::commit();
|
||
break;
|
||
}
|
||
|
||
$email_queues = array_map(static function ($value) {
|
||
return (array) $value;
|
||
}, $email_queues_raw);
|
||
$email_queue = $email_queues[0];
|
||
echo '发送邮件至 ' . $email_queue['to_email'] . PHP_EOL;
|
||
DB::delete('DELETE FROM email_queue WHERE id = ?', [$email_queue['id']]);
|
||
|
||
if (Tools::isEmail($email_queue['to_email'])) {
|
||
|
||
Mail::send(
|
||
$email_queue['to_email'],
|
||
$email_queue['subject'],
|
||
$email_queue['template'],
|
||
json_decode($email_queue['array'])
|
||
);
|
||
|
||
} else {
|
||
echo $email_queue['to_email'] . ' 邮箱格式错误,已跳过' . PHP_EOL;
|
||
}
|
||
|
||
DB::commit();
|
||
|
||
} catch (Exception|ClientExceptionInterface $e) {
|
||
DB::rollBack();
|
||
echo $e->getMessage();
|
||
}
|
||
|
||
}
|
||
|
||
echo Tools::toDateTime(time()) . ' 邮件队列处理完成' . PHP_EOL;
|
||
}
|
||
}
|
||
|
||
public static function smtpClearDayCount()
|
||
{
|
||
$sDate = date("Y-m-d");
|
||
$r = DB::update("UPDATE smtp_list SET `day_count` = 0, `day_clear_date` = '".$sDate."' WHERE `day_count` >= `day_max`");
|
||
|
||
echo Tools::toDateTime(time()) . ' smtp的dayCount重置'.$r.'条' . PHP_EOL;
|
||
}
|
||
|
||
public static function processEmailQueue_bulk(): void
|
||
{
|
||
if ((new EmailQueue())->count() === 0) {
|
||
echo Tools::toDateTime(time()) . ' 队列邮件队列为空' . PHP_EOL;
|
||
} else {
|
||
//记录当前时间戳
|
||
$timestamp = time();
|
||
//邮件队列处理
|
||
while (true) {
|
||
if (time() - $timestamp > 299) {
|
||
echo Tools::toDateTime(time()) . '队列邮件队列处理超时,已跳过' . PHP_EOL;
|
||
break;
|
||
}
|
||
|
||
DB::beginTransaction();
|
||
|
||
try {
|
||
$sDate = date("Y-m-d");
|
||
$aSmtp = DB::select('SELECT * FROM smtp_list WHERE `day_clear_date` != "'.$sDate.'" AND `day_count` < `day_max` ORDER BY `day_clear_date` ASC LIMIT 1 FOR UPDATE SKIP LOCKED');
|
||
|
||
if (empty($aSmtp) || !isset($aSmtp[0])) {
|
||
echo Tools::toDateTime(time()) . ' 今日以没有可用smtp' . PHP_EOL;
|
||
DB::commit();
|
||
break;
|
||
}
|
||
$oSmtp = $aSmtp[0];
|
||
|
||
$email_queues_raw = DB::select('SELECT * FROM email_queue where `type` = "bulk" LIMIT 1 FOR UPDATE SKIP LOCKED');
|
||
|
||
if (count($email_queues_raw) === 0) {
|
||
DB::commit();
|
||
break;
|
||
}
|
||
|
||
$email_queues = array_map(static function ($value) {
|
||
return (array) $value;
|
||
}, $email_queues_raw);
|
||
$email_queue = $email_queues[0];
|
||
echo '发送邮件至 ' . $email_queue['to_email'] . PHP_EOL;
|
||
DB::delete('DELETE FROM email_queue WHERE id = ?', [$email_queue['id']]);
|
||
|
||
if (Tools::isEmail($email_queue['to_email'])) {
|
||
|
||
|
||
Mail::send_bulk(
|
||
$email_queue['to_email'],
|
||
$email_queue['subject'],
|
||
$email_queue['template'],
|
||
json_decode($email_queue['array']),
|
||
$oSmtp
|
||
);
|
||
|
||
DB::update("UPDATE smtp_list SET `day_count` = `day_count` + 1 WHERE id = ".$oSmtp->id);
|
||
|
||
|
||
} else {
|
||
echo $email_queue['to_email'] . ' 邮箱格式错误,已跳过' . PHP_EOL;
|
||
}
|
||
|
||
DB::commit();
|
||
|
||
} catch (Exception|ClientExceptionInterface $e) {
|
||
echo $e->getMessage();
|
||
}
|
||
|
||
}
|
||
|
||
echo Tools::toDateTime(time()) . ' 群发邮件队列处理完成' . PHP_EOL;
|
||
}
|
||
}
|
||
|
||
// 激活订单
|
||
// 作废
|
||
public static function processTabpOrderActivation(): void
|
||
{
|
||
|
||
return; // 作废
|
||
|
||
$users = User::all();
|
||
|
||
foreach ($users as $user) {
|
||
$user_id = $user->id;
|
||
// 获取用户账户等待激活的TABP订单
|
||
$pending_activation_orders = (new Order())->where('user_id', $user_id)
|
||
->where('status', 'pending_activation')
|
||
->where('product_type', 'tabp')
|
||
->orderBy('id')
|
||
->get();
|
||
// 获取用户账户已激活的TABP订单,一个用户同时只能有一个已激活的TABP订单
|
||
$activated_order = (new Order())->where('user_id', $user_id)
|
||
->where('status', 'activated')
|
||
->where('product_type', 'tabp')
|
||
->orderBy('id')
|
||
->first();
|
||
// * 如果用户流量已满,就直接激活待激活订单,不考虑是否有已激活。(之前想的是流量满时把订单标记成过期,这虽然也可以,但是业务逻辑会显得奇怪)
|
||
$ud = $user->u + $user->d;
|
||
// 待激活订单 > 0 && (没有已激活订单 || 用户流量满)
|
||
if (count($pending_activation_orders) > 0 && ($activated_order === null || $ud >= $user->transfer_enable)) {
|
||
// if ($activated_order === null && count($pending_activation_orders) > 0) {
|
||
// if (($activated_order === null && count($pending_activation_orders) > 0) || ($ud > $user->transfer_enable && count($pending_activation_orders) > 0)) {
|
||
$order = $pending_activation_orders[0];
|
||
// 获取TABP订单内容准备激活
|
||
$content = json_decode($order->product_content);
|
||
|
||
//// * 是用户流量满时,主动标记订单过期
|
||
// 按理说可以有多个已激活,但是以防万一,标记掉
|
||
// 假如等级还过期了,就是标记两次,无所谓
|
||
if ($ud >= $user->transfer_enable && $activated_order !== null) {
|
||
$activated_order->status = 'expired';
|
||
$activated_order->update_time = time();
|
||
$activated_order->save();
|
||
echo "TABP订单 #{$activated_order->id} 已过期(流量满了)。\n";
|
||
}
|
||
//// end
|
||
|
||
//// * 特别活动追加,季套餐赠月套餐,年套餐赠季套餐
|
||
if ($order->huodong_class && $order->huodong_class == "A") {
|
||
|
||
// 按理是大于30天,做个冗余
|
||
if ($content->class_time > 32) {
|
||
|
||
$oProduct = Product::where("name", $order->product_name)
|
||
->where("class_time", "<", $content->class_time)
|
||
->orderBy("class_time", "desc")
|
||
->first();
|
||
|
||
if ($oProduct) {
|
||
$oProductContent = json_decode($oProduct->content);
|
||
|
||
$content->class_time += $oProductContent->class_time;
|
||
$content->bandwidth += $oProductContent->bandwidth;
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
//// end
|
||
|
||
// 激活TABP
|
||
// 等级时间,流量,都是覆盖刷新,不是叠加
|
||
$user->u = 0;
|
||
$user->d = 0;
|
||
$user->transfer_today = 0;
|
||
$user->transfer_enable = Tools::toGB($content->bandwidth);
|
||
$user->class = $content->class;
|
||
$old_class_expire = new DateTime();
|
||
$user->class_expire = $old_class_expire
|
||
->modify('+' . $content->class_time . ' days')->format('Y-m-d H:i:s'); // 当前时间+订单等级时间
|
||
$user->node_group = $content->node_group;
|
||
$user->node_speedlimit = $content->speed_limit;
|
||
$user->node_iplimit = $content->ip_limit;
|
||
$user->save();
|
||
$order->status = 'activated';
|
||
$order->update_time = time();
|
||
$order->save();
|
||
echo "TABP订单 #{$order->id} 已激活。\n";
|
||
continue;
|
||
}
|
||
// 如果用户账户中有已激活的TABP订单,则判断是否过期
|
||
if ($activated_order !== null) {
|
||
$content = json_decode($activated_order->product_content);
|
||
|
||
// 原来用的是$content->time
|
||
// 这个time应该是原本的账号时间
|
||
if ($activated_order->update_time + $content->class_time * 86400 < time()) {
|
||
$activated_order->status = 'expired';
|
||
$activated_order->update_time = time();
|
||
$activated_order->save();
|
||
echo "TABP订单 #{$activated_order->id} 已过期。\n";
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
echo Tools::toDateTime(time()) . ' TABP订单激活处理完成' . PHP_EOL;
|
||
}
|
||
|
||
// 流量包激活,暂时没用
|
||
public static function processBandwidthOrderActivation(): void
|
||
{
|
||
$users = User::all();
|
||
|
||
foreach ($users as $user) {
|
||
$user_id = $user->id;
|
||
// 获取用户账户等待激活的流量包订单
|
||
$order = (new Order())->where('user_id', $user_id)
|
||
->where('status', 'pending_activation')
|
||
->where('product_type', 'bandwidth')
|
||
->orderBy('id')
|
||
->first();
|
||
|
||
if ($order !== null) {
|
||
// 获取流量包订单内容准备激活
|
||
$content = json_decode($order->product_content);
|
||
// 激活流量包
|
||
$user->transfer_enable += Tools::toGB($content->bandwidth);
|
||
$user->save();
|
||
$order->status = 'activated';
|
||
$order->update_time = time();
|
||
$order->save();
|
||
echo "流量包订单 #{$order->id} 已激活。\n";
|
||
}
|
||
}
|
||
|
||
echo Tools::toDateTime(time()) . ' 流量包订单激活处理完成' . PHP_EOL;
|
||
}
|
||
|
||
// 时间包激活,暂时没用
|
||
public static function processTimeOrderActivation(): void
|
||
{
|
||
$users = User::all();
|
||
|
||
foreach ($users as $user) {
|
||
$user_id = $user->id;
|
||
// 获取用户账户等待激活的时间包订单
|
||
$order = (new Order())->where('user_id', $user_id)
|
||
->where('status', 'pending_activation')
|
||
->where('product_type', 'time')
|
||
->orderBy('id')
|
||
->first();
|
||
|
||
if ($order !== null) {
|
||
$content = json_decode($order->product_content);
|
||
// 跳过当前账户等级不等于时间包等级的非免费用户订单
|
||
if ($user->class !== (int) $content->class && $user->class > 0) {
|
||
continue;
|
||
}
|
||
// 激活时间包
|
||
$user->class = $content->class;
|
||
$old_class_expire = new DateTime($user->class_expire);
|
||
$user->class_expire = $old_class_expire
|
||
->modify('+' . $content->class_time . ' days')->format('Y-m-d H:i:s');
|
||
$user->node_group = $content->node_group;
|
||
$user->node_speedlimit = $content->speed_limit;
|
||
$user->node_iplimit = $content->ip_limit;
|
||
$user->save();
|
||
$order->status = 'activated';
|
||
$order->update_time = time();
|
||
$order->save();
|
||
echo "时间包订单 #{$order->id} 已激活。\n";
|
||
}
|
||
}
|
||
|
||
echo Tools::toDateTime(time()) . ' 时间包订单激活处理完成' . PHP_EOL;
|
||
}
|
||
|
||
////// 新版组合拳,按循序巡行 //////
|
||
//// 支付成功,标记订单 # 步骤1
|
||
public static function orderToPlan(): void
|
||
{
|
||
self::_helper_log("支付完成 - 开始");
|
||
|
||
$iPayClass = $_ENV["user_payClass"];
|
||
|
||
$pending_payment_orders = (new Order())->where('status', 'payment_pending')->get(); // 这里还是无脑检索order了,但是现在order表可以只保留一年内数据,问题不大
|
||
|
||
$aUserInQueue = []; // 用户可能在5分钟之内多次下单,但一次只处理一个,坚固
|
||
foreach ($pending_payment_orders as $oOrder) {
|
||
|
||
if (in_array($oOrder->user_id, $aUserInQueue)) {
|
||
continue;
|
||
}
|
||
|
||
$invoice = (new Invoice())->where('order_id', $oOrder->id)->first();
|
||
|
||
if ($invoice === null) {
|
||
continue;
|
||
}
|
||
|
||
DB::beginTransaction();
|
||
|
||
try {
|
||
|
||
// 付款完成后
|
||
if (in_array($invoice->status, ['paid_gateway', 'paid_balance', 'paid_admin'])) {
|
||
|
||
$oUser = User::find($invoice->user_id);
|
||
|
||
$iPayAmount = $invoice->price - $invoice->money_use;
|
||
|
||
if ($oOrder->product_code == "code") { // 钱包充值
|
||
|
||
$iUserMoneyOld = $oUser->money;
|
||
$iUserMoneyNew = $oUser->money + $invoice->price;
|
||
$iAmount = $invoice->price;
|
||
|
||
$oUser->money = $iUserMoneyNew;
|
||
$oUser->total_pay += $iPayAmount;
|
||
$oUser->save();
|
||
|
||
(new UserMoneyLog())->add(
|
||
$oUser->id,
|
||
(float) $iUserMoneyOld,
|
||
(float) $iUserMoneyNew,
|
||
(float) $iAmount,
|
||
'钱包充值 #账单号:'.$invoice->id
|
||
);
|
||
|
||
$oOrder->status = "code_done";
|
||
$oOrder->_save();
|
||
|
||
self::_helper_log("订单".$oOrder->id."钱包充值到账");
|
||
} else if ($oUser->class < $iPayClass) { // 当前无套餐,直接进激活队列
|
||
|
||
$oUser->total_pay += $iPayAmount;
|
||
$oUser->save();
|
||
|
||
$oOrder->status = "pending";
|
||
$oOrder->_save();
|
||
|
||
$oPlanQueue = new PlanQueue();
|
||
$oPlanQueue->_add($oOrder, "new");
|
||
|
||
self::_helper_log("订单".$oOrder->id."进入到激活队列");
|
||
} else { // 当前有套餐,进入pending表
|
||
|
||
$oUser->total_pay += $iPayAmount;
|
||
$oUser->save();
|
||
|
||
$oOrder->status = "pending";
|
||
$oOrder->_save();
|
||
|
||
self::_helper_log("订单".$oOrder->id."转为待激活状态");
|
||
}
|
||
|
||
$aUserInQueue[] = $oOrder->user_id;
|
||
|
||
} else if ($oOrder->create_time + 86400 < time()) {
|
||
|
||
$invoice->status = 'cancelled';
|
||
$invoice->update_time = time();
|
||
$invoice->save();
|
||
|
||
$oOrder->status = 'cancelled';
|
||
$oOrder->update_time = time();
|
||
$oOrder->save();
|
||
|
||
if ($invoice->money_use > 0) {
|
||
$iUserMoneyOld = $oUser->money;
|
||
$oUser->money += $invoice->money_use;
|
||
$oUser->save();
|
||
(new UserMoneyLog())->add(
|
||
$oUser->id,
|
||
(float) $iUserMoneyOld,
|
||
(float) $oUser->money,
|
||
(float) $invoice->money_use,
|
||
'支付超时退回余额 #账单号:'.$invoice->id
|
||
);
|
||
}
|
||
|
||
self::_helper_log("已取消超时账单".$oOrder->id);
|
||
|
||
}
|
||
|
||
DB::commit();
|
||
|
||
} catch (\Exception $e) {
|
||
|
||
DB::rollBack();
|
||
|
||
// if ($oOrder) {
|
||
// $oOrder->error_code = "error";
|
||
// $oOrder->error_str = "支付未到账,请联系管理员";
|
||
// $oOrder->_save();
|
||
// }
|
||
|
||
$sMsg = self::_helper_toJson($e->getMessage());
|
||
self::_helper_log($sMsg, self::_eToArr($e, $sMsg));
|
||
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
//// 检查过期 # 步骤2
|
||
public static function plan_expireToQueue(): void
|
||
{
|
||
|
||
self::_helper_log("套餐过期标记 - 开始");
|
||
|
||
$iFreeClass = $_ENV["user_freeClass"];
|
||
|
||
$iPayClass = $_ENV["user_payClass"];
|
||
|
||
$oUserList = User::where("class", ">=", $iPayClass)->get();
|
||
|
||
foreach ($oUserList as $oUser) {
|
||
|
||
DB::beginTransaction();
|
||
|
||
try {
|
||
|
||
// $oUser->isPayClass = $oUser->class >= $iPayClass ? true : false;
|
||
|
||
if (strtotime($oUser->class_expire) < time()) { // 时间到期
|
||
self::_class_expire($oUser);
|
||
DB::commit();
|
||
continue;
|
||
}
|
||
|
||
if ($oUser->u + $oUser->d >= $oUser->transfer_enable) { // 流量用完
|
||
self::_class_expire($oUser);
|
||
DB::commit();
|
||
continue;
|
||
}
|
||
|
||
DB::commit();
|
||
|
||
} catch (\Exception $e) {
|
||
|
||
DB::rollBack();
|
||
|
||
$sMsg = self::_helper_toJson($e->getMessage());
|
||
self::_helper_log($sMsg, self::_eToArr($e, $sMsg));
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//// pendding转激活 # 步骤3
|
||
public static function planQueue_pendingToActivation()
|
||
{
|
||
self::_helper_log("套餐激活 - 开始");
|
||
$oPlanQueueList = PlanQueue::whereNull("status")->get();
|
||
|
||
foreach ($oPlanQueueList as $oPlanQueue) {
|
||
|
||
// $oPlanPending = PlanPending::where("user_id", $oPlanQueue->user_id)->where("status", "!=", "fail")->orderBy("id", "ASC")->first(); // * 待激活表
|
||
$oPlanPending = Order::where("user_id", $oPlanQueue->user_id)
|
||
->where("status", "pending")
|
||
->whereNull("error_code")
|
||
->orderBy("id", "ASC")
|
||
->first();
|
||
|
||
// 没有待激活套餐时,跳过。否则都必然$oPlanQueue->_delete();
|
||
if (!$oPlanPending) {
|
||
$oPlanQueue->type = "expire";
|
||
$oPlanQueue->save();
|
||
continue; // 没有待激活就直接桡过,而不是报错
|
||
}
|
||
|
||
DB::beginTransaction();
|
||
|
||
try {
|
||
|
||
$oProduct = Product::where("code", $oPlanPending->product_code)->first(); // * 商品表
|
||
|
||
// 没有对应商品时
|
||
if (!$oProduct) {
|
||
$oPlanPending->error_code = "fail";
|
||
$oPlanPending->error_str = "激活失败,该商品已从数据库存中移除,金额以退回至钱包。";
|
||
|
||
// 退回钱包
|
||
$oUser = User::find($oPlanQueue->user_id);
|
||
|
||
$iUserMoneyOld = $oUser->money;
|
||
$iUserMoneyNew = $oUser->money + $oPlanPending->user_price;
|
||
|
||
$oUser->money = $iUserMoneyNew;
|
||
$oUser->save();
|
||
|
||
(new UserMoneyLog())->add(
|
||
$oUser->id,
|
||
(float) $iUserMoneyOld,
|
||
(float) $iUserMoneyNew,
|
||
(float) $oPlanPending->user_price,
|
||
'套餐激活失败,金额退回钱包'
|
||
);
|
||
|
||
$oPlanQueue->_delete();
|
||
|
||
DB::commit();
|
||
|
||
continue;
|
||
}
|
||
|
||
//// 用户激活
|
||
$oProductContent = json_decode($oProduct->content);
|
||
|
||
$oUser = User::find($oPlanQueue->user_id);
|
||
|
||
self::_plan_to_user($oUser, $oProductContent); // 套餐赋予用户
|
||
|
||
// 以激活表
|
||
// $oPlanActivated = PlanActivated::where("user_id", $oPlanQueue->user_id)->orderBy("id", "ASC")->first(); // 目前已激活plan
|
||
$oPlanActivated = Order::where("user_id", $oPlanQueue->user_id)
|
||
->where("status", "activated")
|
||
->orderBy("id", "ASC")
|
||
->first();
|
||
|
||
if ($oPlanActivated) {
|
||
// self::plan_activatedToExpired($oPlanActivated); // 已激活转为过期
|
||
$oPlanActivated->status = "expired";
|
||
$oPlanActivated->_save();
|
||
}
|
||
|
||
// self::plan_pendingToActivated($oPlanPending); // 待激活转为激活
|
||
$oPlanPending->status = "activated";
|
||
$oPlanPending->_save();
|
||
|
||
$oPlanQueue->_delete();
|
||
|
||
DB::commit();
|
||
|
||
self::_helper_log("用户".$oUser->id."激活完成");
|
||
|
||
} catch (\Exception $e) {
|
||
|
||
DB::rollBack();
|
||
|
||
$oPlanQueue->status = "fail:planQueue_pendingToActivation";
|
||
$oPlanQueue->type .= "_fail_".rand(1, 9999);
|
||
$oPlanQueue->_save();
|
||
|
||
// $oPlanPending = $oPlanPending::
|
||
// $oPlanPending = PlanPending::where("user_id", $oPlanQueue->user_id)->where("status", "!=", "fail")->orderBy("id", "ASC")->first();
|
||
|
||
if ($oPlanPending) {
|
||
$oPlanPending->error_code = "error";
|
||
$oPlanPending->error_str = "套餐激活失败,请联系管理员";
|
||
$oPlanPending->_save();
|
||
}
|
||
|
||
$sMsg = self::_helper_toJson($e->getMessage());
|
||
|
||
self::_helper_log($sMsg, self::_eToArr($e, $sMsg));
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
// 自动续订 # 步骤 4
|
||
public static function planQueue_expireToBuy()
|
||
{
|
||
self::_helper_log("自动续订 - 开始");
|
||
|
||
$oPlanQueueList = PlanQueue::where("type", "expire")->whereNull("status")->get();
|
||
|
||
foreach ($oPlanQueueList as $oPlanQueue) {
|
||
|
||
// 检查自动续订是否开启
|
||
$oUser = User::where("id", $oPlanQueue->user_id)->first(); // * 数据
|
||
|
||
if ($oUser->autorenew != 1) {
|
||
continue;
|
||
}
|
||
|
||
// $oPlanActivated = PlanActivated::where("user_id", $oPlanQueue->user_id)->orderBy("id", "ASC")->first(); // * 当前激活套餐
|
||
$oPlanActivated = Order::where("user_id", $oPlanQueue->user_id)->where("status", "activated")->OrderBy("id", "ASC")->first();
|
||
|
||
if (!$oPlanActivated) {
|
||
continue;
|
||
}
|
||
|
||
DB::beginTransaction();
|
||
|
||
try {
|
||
|
||
//// 开始自动续订
|
||
$iUserMoneyOld = $oUser->money;
|
||
$iUserMoneyNew = $oUser->money - $oPlanActivated->user_price;
|
||
|
||
// 余额不足
|
||
if ($iUserMoneyNew < 0) {
|
||
// 关闭自动订阅
|
||
$oUser->autorenew = 0;
|
||
$oUser->save();
|
||
|
||
// todo 发站内信 成功失败都发
|
||
$text = "钱包余额不足,自动续订失败。";
|
||
Notification::notifyUser($oUser, $_ENV['appName'] . ' - 自动续订失败', $text);
|
||
|
||
DB::commit();
|
||
continue;
|
||
}
|
||
|
||
// 扣款
|
||
$oUser->money = $iUserMoneyNew;
|
||
$oUser->save();
|
||
|
||
(new UserMoneyLog())->add(
|
||
$oUser->id,
|
||
$iUserMoneyOld,
|
||
(float) $iUserMoneyNew,
|
||
-$oPlanActivated->user_price,
|
||
'余额抵付 #账单号:'.$oPlanActivated->id
|
||
);
|
||
|
||
// 创建订单
|
||
$order = new Order();
|
||
$order->user_id = $oPlanQueue->user_id;
|
||
$order->product_code = $oPlanActivated->product_code;
|
||
$order->user_product_name = $oPlanActivated->user_product_name;
|
||
$order->user_coupon = $oPlanActivated->user_coupon;
|
||
$order->user_price = $oPlanActivated->user_price;
|
||
$order->status = 'payment_pending';
|
||
$order->create_time = time();
|
||
$order->update_time = time();
|
||
$order->_save();
|
||
|
||
$invoice = new Invoice();
|
||
$invoice->user_id = $oUser->id;
|
||
$invoice->order_id = $order->id;
|
||
$invoice->price = $oPlanActivated->user_price;
|
||
$invoice->status = 'paid_balance';
|
||
$invoice->create_time = time();
|
||
$invoice->update_time = time();
|
||
$invoice->pay_time = time();
|
||
$invoice->money_use = $oPlanActivated->user_price;
|
||
$invoice->save();
|
||
|
||
$text = "自动续订成功,钱包金额扣除".$oPlanActivated->user_price."元,还剩".$iUserMoneyNew."元。";
|
||
Notification::notifyUser($oUser, $_ENV['appName'] . ' - 自动续订成功', $text);
|
||
|
||
$oPlanQueue->_delete();
|
||
|
||
self::_helper_log("用户".$oUser->id."续订购买套餐成功");
|
||
|
||
DB::commit();
|
||
|
||
// continue;
|
||
|
||
} catch (\Exception $e) {
|
||
|
||
DB::rollBack();
|
||
|
||
$sMsg = self::_helper_toJson($e->getMessage());
|
||
|
||
self::_helper_log($sMsg, self::_eToArr($e, $sMsg));
|
||
|
||
$oPlanQueue->status = "fail:planQueue_expireToBuy";
|
||
$oPlanQueue->type .= "_fail_".rand(1, 9999);
|
||
$oPlanQueue->_save();
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
//// 过期处理完成 # 步骤 5
|
||
public static function planQueue_expireDone()
|
||
{
|
||
self::_helper_log("过期 - 开始");
|
||
|
||
$text = '您好,系统发现您的套餐已经过期了。';
|
||
$reset_traffic = $_ENV['class_expire_reset_traffic'];
|
||
$reset_day = $_ENV['class_expire_reset_day'];
|
||
$iPayClass = $_ENV["user_payClass"];
|
||
$iFreeClass = $_ENV["user_freeClass"];
|
||
|
||
$iToEnable = 0;
|
||
$iToExpire = date('Y-m-d H:i:s');
|
||
$iToClass = 0;
|
||
|
||
$oPlanExpireQueueList = PlanQueue::where("type", "expire")->whereNull("status")->get();
|
||
|
||
foreach ($oPlanExpireQueueList as $oPlanExpireQueue)
|
||
{
|
||
|
||
DB::beginTransaction();
|
||
|
||
try {
|
||
|
||
$oUser = User::where("id", $oPlanExpireQueue->user_id)->first();
|
||
|
||
//// activated转移到expired
|
||
// $oPlanActivated = PlanActivated::where("user_id", $oPlanExpireQueue->user_id)->first(); // 必然有,没有自然报错,user唯一
|
||
$oPlanActivated = Order::where("user_id", $oPlanExpireQueue->user_id)->where("status", "activated")->first(); // 没有就不管,只过期用户
|
||
if ($oPlanActivated) {
|
||
$oPlanActivated->status = "expired";
|
||
$oPlanActivated->update_time = time();
|
||
$oPlanActivated->_save();
|
||
// self::plan_activatedToExpired($oPlanActivated);
|
||
}
|
||
//// end
|
||
|
||
//// 通知
|
||
if ($reset_traffic >= 0) { // 如果设置了那个,付费用户过期转成体验用户。没设置就直接转普通用户。
|
||
$iToEnable = Tools::toGB($reset_traffic);
|
||
$iToExpire = date('Y-m-d H:i:s', strtotime("+$reset_day days"));
|
||
$iToClass = $iFreeClass;
|
||
$text .= '已转为免费体验帐户,赠送' . $reset_traffic . 'GB体验流量,'.$reset_day.'天体验时长。';
|
||
}
|
||
|
||
$oUser->class = $iToClass;
|
||
$oUser->u = 0;
|
||
$oUser->d = 0;
|
||
$oUser->transfer_today = 0;
|
||
$oUser->transfer_enable = $iToEnable;
|
||
$oUser->class_expire = $iToExpire;
|
||
$oUser->save();
|
||
|
||
Notification::notifyUser($oUser, $_ENV['appName'] . '-您的套餐已经过期', $text);
|
||
|
||
// try {
|
||
// Notification::notifyUser($oUser, $_ENV['appName'] . '-您的套餐已经过期', $text);
|
||
// } catch (GuzzleException|ClientExceptionInterface|TelegramSDKException $e) {
|
||
// echo $e->getMessage() . PHP_EOL;
|
||
// }
|
||
//// end
|
||
|
||
$oPlanExpireQueue->delete();
|
||
|
||
self::_helper_log("用户".$oUser->id."彻底过期");
|
||
|
||
DB::commit();
|
||
|
||
} catch (\Exception $e) {
|
||
|
||
DB::rollBack();
|
||
|
||
$sMsg = self::_helper_toJson($e->getMessage());
|
||
|
||
self::_helper_log($sMsg, self::_eToArr($e, $sMsg));
|
||
|
||
$oPlanExpireQueue->status = "fail:planQueue_expireDone";
|
||
$oPlanExpireQueue->type .= "_fail_".rand(1, 9999);
|
||
$oPlanExpireQueue->_save();
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//// helper系列
|
||
private static function _class_expire(&$oUser)
|
||
{
|
||
|
||
$oPlanQueue = new PlanQueue();
|
||
$oPlanQueue->user_id = $oUser->id;
|
||
$oPlanQueue->type = "expire";
|
||
$oPlanQueue->updated_at = time();
|
||
$oPlanQueue->save();
|
||
|
||
self::_helper_log("用户id".$oPlanQueue->user_id."加入plan过期队列");
|
||
|
||
}
|
||
|
||
// private static function plan_activatedToExpired(&$oPlanActivated)
|
||
// {
|
||
// if (!$oPlanActivated) {
|
||
// return false;
|
||
// }
|
||
//
|
||
// $oPlanExpired = new PlanExpired();
|
||
// $oPlanExpired->_add($oPlanActivated);
|
||
//
|
||
// return $oPlanActivated->_delete();
|
||
// }
|
||
|
||
// private static function plan_pendingToActivated(&$oPlanPending)
|
||
// {
|
||
// if (!$oPlanPending) {
|
||
// return false;
|
||
// }
|
||
//
|
||
// $oPlanActivated = new PlanActivated();
|
||
// $oPlanActivated->_add($oPlanPending);
|
||
//
|
||
// return $oPlanPending->_delete();
|
||
// }
|
||
|
||
public static function _helper_toJson($data)
|
||
{
|
||
return json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||
}
|
||
|
||
// public static function _helper_fail(&$oPlanPending)
|
||
// {
|
||
//
|
||
// $oPlanPending->status_str = "套餐激活失败,请联系管理员。";
|
||
// $oPlanPending->status = "fail";
|
||
// $oPlanPending->_save();
|
||
//
|
||
// }
|
||
|
||
// private static function _eToArr($oError, $sTitle = false)
|
||
// {
|
||
// $arr = [];
|
||
//
|
||
// if ($sTitle) {
|
||
// $arr['title'] = $sTitle;
|
||
// }
|
||
//
|
||
// $arr['code'] = $oError->getCode();
|
||
// $arr['file'] = $oError->getFile();
|
||
// $arr['line'] = $oError->getLine();
|
||
//
|
||
// return $arr;
|
||
// }
|
||
|
||
private static function _helper_log($sMsg, $sTgMsg = false)
|
||
{
|
||
echo Tools::toDateTime(time()).' '.$sMsg.PHP_EOL;
|
||
|
||
if ($sTgMsg) {
|
||
$oTelegramV2 = new TelegramV2();
|
||
$oTelegramV2->send($sTgMsg, "arr");
|
||
}
|
||
}
|
||
|
||
// private static function _helper_throw($sMsg, $aTgMsg = [])
|
||
// {
|
||
// if ($aTgMsg) {
|
||
// $oTelegramV2 = new TelegramV2();
|
||
// $oTelegramV2->send(json_encode($aTgMsg));
|
||
// }
|
||
//
|
||
// throw new \Exception($sMsg);
|
||
// }
|
||
|
||
private static function _plan_to_user(&$oUser, $aProductContent)
|
||
{
|
||
$oUser->class = $aProductContent->class;
|
||
$oUser->class_expire = date('Y-m-d H:i:s', strtotime("+$aProductContent->class_time days"));
|
||
$oUser->transfer_enable = Tools::toGB($aProductContent->bandwidth);
|
||
$oUser->u = 0;
|
||
$oUser->d = 0;
|
||
$oUser->transfer_today = 0;
|
||
$oUser->node_iplimit = $aProductContent->ip_limit;
|
||
$oUser->node_speedlimit = $aProductContent->speed_limit;
|
||
$oUser->save();
|
||
}
|
||
//// helper order 系列 end
|
||
|
||
////// 新版组合拳 end //////
|
||
|
||
public static function removeInactiveUserLinkAndInvite(): void
|
||
{
|
||
$inactive_users = (new User())->where('is_inactive', 1)->get();
|
||
|
||
foreach ($inactive_users as $user) {
|
||
$user->removeLink();
|
||
$user->removeInvite();
|
||
}
|
||
|
||
echo Tools::toDateTime(time()) . ' Successfully removed inactive user\'s Link and Invite' . PHP_EOL;
|
||
}
|
||
|
||
// 废弃
|
||
public static function resetNodeBandwidth(): void
|
||
{
|
||
(new Node())->where('bandwidthlimit_resetday', date('d'))->update(['node_bandwidth' => 0]);
|
||
|
||
echo Tools::toDateTime(time()) . ' 重设节点流量完成' . PHP_EOL;
|
||
}
|
||
|
||
// 机器到日期重置流量
|
||
public static function resetDuckBandwidth(): void
|
||
{
|
||
(new Ducks())->where('width_reset_day', date('d'))->update(['use_width' => 0]);
|
||
|
||
echo Tools::toDateTime(time()) . ' 重设机器流量完成' . PHP_EOL;
|
||
}
|
||
|
||
// public static function resetZhuanfaBandwidth(): void
|
||
// {
|
||
// (new Ducks())->where('end_date', date('Y-m-d'))->update(['use_width' => 0]);
|
||
//
|
||
// echo Tools::toDateTime(time()) . ' 重设机器流量完成' . PHP_EOL;
|
||
// }
|
||
|
||
// 每小时,统计节点流量,入库,tg警报
|
||
public static function mergeBandWidth(): void
|
||
{
|
||
|
||
$oNodeAll = Node::where('type', 1)->get();
|
||
|
||
$aZhuanfaFlowNow = [];
|
||
$aDuckFlowNow = [];
|
||
$sMsg = "";
|
||
|
||
// 统计node流量
|
||
foreach ($oNodeAll as $oNodeRow) {
|
||
|
||
if ($oNodeRow->node_bandwidth == 0) {
|
||
|
||
if ($oNodeRow->is_shadow != 1) {
|
||
|
||
$sMsg .= '🚨【'.$oNodeRow->name."】小时未耗流,可能异常。\n";
|
||
|
||
}
|
||
|
||
}
|
||
|
||
@$aZhuanfaFlowNow[$oNodeRow->zhuanfa_code] += $oNodeRow->node_bandwidth;
|
||
@$aDuckFlowNow[$oNodeRow->duck_code] += $oNodeRow->node_bandwidth;
|
||
|
||
}
|
||
|
||
// 入库zhunafa
|
||
foreach ($aZhuanfaFlowNow as $k => $v) {
|
||
|
||
if ($v) {
|
||
Zhuanfas::where('code', $k)->increment('today_width', $v);
|
||
Zhuanfas::where('code', $k)->increment('use_width', $v);
|
||
}
|
||
|
||
}
|
||
|
||
// 入库duck
|
||
foreach ($aDuckFlowNow as $k => $v) {
|
||
|
||
if ($v) {
|
||
Ducks::where('code', $k)->increment('today_width', $v);
|
||
Ducks::where('code', $k)->increment('use_width', $v);
|
||
}
|
||
|
||
}
|
||
|
||
// 清空node流量
|
||
Node::query()->update(['node_bandwidth' => 0]);
|
||
|
||
if ($sMsg) {
|
||
(new Telegram())->send(0, $sMsg);
|
||
}
|
||
|
||
}
|
||
|
||
// 每日报表
|
||
public static function reportBandWidth(): void
|
||
{
|
||
|
||
$oZhuanfas = new Zhuanfas();
|
||
$oDucks = new Ducks();
|
||
|
||
// 流量报告,转发
|
||
$oTgSendFormat = new TgSendFormat();
|
||
$oTgSendFormat->sTitleEmoji = "\n\n";
|
||
$oTgSendFormat->sTitle = "# 转发流量";
|
||
$today = new DateTime();
|
||
|
||
$oZhuanfasAll = $oZhuanfas->all();
|
||
foreach ($oZhuanfasAll as $oZhuanfasRow) {
|
||
|
||
$targetDate = new DateTime($oZhuanfasRow->end_date);
|
||
$interval = $today->diff($targetDate);
|
||
|
||
if ($today > $targetDate) {
|
||
$iDiffDay = -$interval->days;
|
||
} else {
|
||
$iDiffDay = $interval->days;
|
||
}
|
||
|
||
$oTgSendFormat->rowAdd(
|
||
$oZhuanfasRow->name,
|
||
$oZhuanfasRow->today_width,
|
||
$oZhuanfasRow->use_width,
|
||
$oZhuanfasRow->max_width,
|
||
$iDiffDay
|
||
);
|
||
|
||
}
|
||
|
||
$sTgReport = $oTgSendFormat->typeA();
|
||
|
||
(new Telegram())->send(0, $sTgReport);
|
||
|
||
// 流量报告,机器
|
||
$oTgSendFormat = new TgSendFormat();
|
||
$oTgSendFormat->sTitleEmoji = "\n\n";
|
||
$oTgSendFormat->sTitle = "# 机器流量";
|
||
|
||
$oDucksAll = $oDucks->orderBy('code')->get();
|
||
foreach ($oDucksAll as $oDucksRow) {
|
||
|
||
if ($oDucksRow->width_reset_day == 0) {
|
||
$iWidthResetDay = 0;
|
||
} if ($oDucksRow->width_reset_day > date('d')) {
|
||
$iWidthResetDay = $oDucksRow->width_reset_day - date('d');
|
||
} else {
|
||
$date = new DateTime();
|
||
$date->modify('first day of next month');
|
||
$date->setDate((int)$date->format('Y'), (int)$date->format('m'), $oDucksRow->width_reset_day);
|
||
$sEndDate = $date;
|
||
|
||
$currentDate = new DateTime();
|
||
$interval = $currentDate->diff($sEndDate);
|
||
$iWidthResetDay = $interval->days;
|
||
}
|
||
|
||
$oTgSendFormat->rowAdd(
|
||
$oDucksRow->code,
|
||
$oDucksRow->today_width,
|
||
$oDucksRow->use_width,
|
||
$oDucksRow->max_width,
|
||
$iWidthResetDay,
|
||
$oDucksRow->memo
|
||
);
|
||
|
||
}
|
||
|
||
$sTgReport = $oTgSendFormat->typeA();
|
||
|
||
(new Telegram())->send(0, $sTgReport);
|
||
|
||
}
|
||
|
||
// 每日清空duck和转发的每日流量
|
||
public static function clearTodayWidth(): void
|
||
{
|
||
Ducks::query()->update(['today_width' => 0]);
|
||
Zhuanfas::query()->update(['today_width' => 0]);
|
||
}
|
||
|
||
public static function reportBandWidth_back(): void
|
||
{
|
||
$oNode = new Node();
|
||
$oZhuanfas = new Zhuanfas();
|
||
$oDucks = new Ducks();
|
||
|
||
$oNodeAll = $oNode->all();
|
||
|
||
foreach ($oNodeAll as $oNodeRow) {
|
||
|
||
@ $iZhuanfaFlowToday[$oNodeRow->zhuanfa_code] += $oNodeRow->node_bandwidth;
|
||
@ $iDuckFlowToday[$oNodeRow->duck_code] += $oNodeRow->node_bandwidth;
|
||
|
||
$oZhuanfas->where('code', $oNodeRow->zhuanfa_code)->increment('use_width', $oNodeRow->node_bandwidth);
|
||
$oDucks->where('code', $oNodeRow->duck_code)->increment('use_width', $oNodeRow->node_bandwidth);
|
||
$oNode->where('id', $oNodeRow->id)->update(['node_bandwidth' => 0]);
|
||
|
||
}
|
||
|
||
|
||
// 流量报告,转发
|
||
$oTgSendFormat = new TgSendFormat();
|
||
$oTgSendFormat->sTitleEmoji = "⚡️⚡️⚡️⚡️⚡️⚡️";
|
||
$oTgSendFormat->sTitle = "# 转发流量";
|
||
$today = new DateTime();
|
||
|
||
$oZhuanfasAll = $oZhuanfas->all();
|
||
foreach ($oZhuanfasAll as $oZhuanfasRow) {
|
||
|
||
$targetDate = new DateTime($oZhuanfasRow->end_date);
|
||
$interval = $today->diff($targetDate);
|
||
|
||
$oTgSendFormat->rowAdd(
|
||
$oZhuanfasRow->name,
|
||
$iZhuanfaFlowToday[$oZhuanfasRow->code],
|
||
$oZhuanfasRow->use_width,
|
||
$oZhuanfasRow->max_width,
|
||
$interval->days
|
||
);
|
||
|
||
}
|
||
|
||
$sTgReport = $oTgSendFormat->typeA();
|
||
|
||
(new Telegram())->send(0, $sTgReport);
|
||
|
||
// 流量报告,机器
|
||
$oTgSendFormat = new TgSendFormat();
|
||
$oTgSendFormat->sTitleEmoji = "\n\n";
|
||
$oTgSendFormat->sTitle = "# 机器流量";
|
||
|
||
$oDucksAll = $oDucks->orderBy('code')->get();
|
||
foreach ($oDucksAll as $oDucksRow) {
|
||
|
||
if ($oDucksRow->width_reset_day == 0) {
|
||
$iWidthResetDay = 0;
|
||
} if ($oDucksRow->width_reset_day > date('d')) {
|
||
$iWidthResetDay = $oDucksRow->width_reset_day - date('d');
|
||
} else {
|
||
$date = new DateTime();
|
||
$date->modify('first day of next month');
|
||
$date->setDate((int)$date->format('Y'), (int)$date->format('m'), $oDucksRow->width_reset_day);
|
||
$sEndDate = $date;
|
||
|
||
$currentDate = new DateTime();
|
||
$interval = $currentDate->diff($sEndDate);
|
||
$iWidthResetDay = $interval->days;
|
||
}
|
||
|
||
$oTgSendFormat->rowAdd(
|
||
$oDucksRow->code,
|
||
$iDuckFlowToday[$oDucksRow->code] ?? 0,
|
||
$oDucksRow->use_width,
|
||
$oDucksRow->max_width,
|
||
$iWidthResetDay
|
||
);
|
||
|
||
}
|
||
|
||
$sTgReport = $oTgSendFormat->typeA();
|
||
|
||
(new Telegram())->send(0, $sTgReport);
|
||
|
||
}
|
||
|
||
|
||
// 用户流量每日重置
|
||
public static function resetTodayBandwidth(): void
|
||
{
|
||
(new User())->query()->update(['transfer_today' => 0]);
|
||
|
||
echo Tools::toDateTime(time()) . ' 重设用户每日流量完成' . PHP_EOL;
|
||
}
|
||
|
||
// 这是那个每月几日重置
|
||
// 是重置免费用户
|
||
// 现在没用了,傻逼功能。用户光有流量没有等级照样用不了,取消等级限制则变成所有用户都运作,根本不合理
|
||
public static function resetFreeUserBandwidth(): void
|
||
{
|
||
// $freeUsers = (new User())->where('class', 0)
|
||
// ->where('auto_reset_day', date('d'))->get();
|
||
//
|
||
// foreach ($freeUsers as $user) {
|
||
// try {
|
||
// Notification::notifyUser(
|
||
// $user,
|
||
// $_ENV['appName'] . '-免费流量重置通知',
|
||
// '你好,你的免费流量已经被重置为' . $user->auto_reset_bandwidth . 'GB。'
|
||
// );
|
||
// } catch (GuzzleException|ClientExceptionInterface|TelegramSDKException $e) {
|
||
// echo $e->getMessage() . PHP_EOL;
|
||
// }
|
||
//
|
||
// $user->u = 0;
|
||
// $user->d = 0;
|
||
// $user->transfer_enable = $user->auto_reset_bandwidth * 1024 * 1024 * 1024;
|
||
// $user->save();
|
||
// }
|
||
//
|
||
// echo Tools::toDateTime(time()) . ' 免费用户流量重置完成' . PHP_EOL;
|
||
}
|
||
|
||
public static function resetFreeUserBandwidth_new(): void
|
||
{
|
||
echo 1111;
|
||
}
|
||
|
||
// 财务日报,好像没用
|
||
public static function sendDailyFinanceMail(): void
|
||
{
|
||
$today = strtotime('00:00:00');
|
||
$paylists = (new Paylist())->where('status', 1)
|
||
->whereBetween('datetime', [strtotime('-1 day', $today), $today])->get();
|
||
$text_html = '<table border=1><tr><td>金额</td><td>用户ID</td><td>用户名</td><td>充值时间</td>';
|
||
|
||
foreach ($paylists as $paylist) {
|
||
$text_html .= '<tr>';
|
||
$text_html .= '<td>' . $paylist->total . '</td>';
|
||
$text_html .= '<td>' . $paylist->userid . '</td>';
|
||
$text_html .= '<td>' . (new User())->find($paylist->userid)->user_name . '</td>';
|
||
$text_html .= '<td>' . Tools::toDateTime((int) $paylist->datetime) . '</td>';
|
||
$text_html .= '</tr>';
|
||
}
|
||
|
||
$text_html .= '</table>';
|
||
$text_html .= '<br>昨日总收入笔数:' . count($paylists) . '<br>昨日总收入金额:' . $paylists->sum('total');
|
||
echo 'Sending daily finance email to admin user' . PHP_EOL;
|
||
|
||
try {
|
||
Notification::notifyAdmin(
|
||
'财务日报',
|
||
$text_html,
|
||
'finance.tpl'
|
||
);
|
||
} catch (GuzzleException|ClientExceptionInterface|TelegramSDKException $e) {
|
||
echo $e->getMessage() . PHP_EOL;
|
||
}
|
||
|
||
echo Tools::toDateTime(time()) . ' 成功发送财务日报' . PHP_EOL;
|
||
}
|
||
|
||
// 财务周报,好像没用
|
||
public static function sendWeeklyFinanceMail(): void
|
||
{
|
||
$today = strtotime('00:00:00');
|
||
$paylists = (new Paylist())->where('status', 1)
|
||
->whereBetween('datetime', [strtotime('-1 week', $today), $today])
|
||
->get();
|
||
|
||
$text_html = '<br>上周总收入笔数:' . count($paylists) . '<br>上周总收入金额:' . $paylists->sum('total');
|
||
echo 'Sending weekly finance email to admin user' . PHP_EOL;
|
||
|
||
try {
|
||
Notification::notifyAdmin(
|
||
'财务周报',
|
||
$text_html,
|
||
'finance.tpl'
|
||
);
|
||
} catch (GuzzleException|ClientExceptionInterface|TelegramSDKException $e) {
|
||
echo $e->getMessage() . PHP_EOL;
|
||
}
|
||
|
||
echo Tools::toDateTime(time()) . ' 成功发送财务周报' . PHP_EOL;
|
||
}
|
||
|
||
// 财务越好,好像没用
|
||
public static function sendMonthlyFinanceMail(): void
|
||
{
|
||
$today = strtotime('00:00:00');
|
||
$paylists = (new Paylist())->where('status', 1)
|
||
->whereBetween('datetime', [strtotime('-1 month', $today), $today])
|
||
->get();
|
||
|
||
$text_html = '<br>上月总收入笔数:' . count($paylists) . '<br>上月总收入金额:' . $paylists->sum('total');
|
||
echo 'Sending monthly finance email to admin user' . PHP_EOL;
|
||
|
||
try {
|
||
Notification::notifyAdmin(
|
||
'财务月报',
|
||
$text_html,
|
||
'finance.tpl'
|
||
);
|
||
} catch (GuzzleException|ClientExceptionInterface|TelegramSDKException $e) {
|
||
echo $e->getMessage() . PHP_EOL;
|
||
}
|
||
|
||
echo Tools::toDateTime(time()) . ' 成功发送财务月报' . PHP_EOL;
|
||
}
|
||
|
||
// 流量提醒
|
||
// 只提醒付费用户
|
||
public static function sendPaidUserUsageLimitNotification(): void
|
||
{
|
||
$paidUsers = (new User())->where('class', '>=', 2)->get();
|
||
|
||
foreach ($paidUsers as $user) {
|
||
$user_traffic_left = $user->transfer_enable - $user->u - $user->d;
|
||
$under_limit = false;
|
||
$unit_text = '';
|
||
|
||
if ($_ENV['notify_limit_mode'] === 'per' &&
|
||
$user_traffic_left / $user->transfer_enable * 100 < $_ENV['notify_limit_value']
|
||
) {
|
||
$under_limit = true;
|
||
$unit_text = '%';
|
||
} elseif ($_ENV['notify_limit_mode'] === 'mb' &&
|
||
Tools::flowToMB($user_traffic_left) < $_ENV['notify_limit_value']
|
||
) {
|
||
$under_limit = true;
|
||
$unit_text = 'MB';
|
||
}
|
||
|
||
if ($under_limit && ! $user->traffic_notified) {
|
||
try {
|
||
Notification::notifyUser(
|
||
$user,
|
||
$_ENV['appName'] . '-你的剩余流量过低',
|
||
'你好,系统发现你剩余流量已经低于 ' . $_ENV['notify_limit_value'] . $unit_text . ' 。',
|
||
);
|
||
|
||
$user->traffic_notified = true;
|
||
} catch (GuzzleException|ClientExceptionInterface|TelegramSDKException $e) {
|
||
$user->traffic_notified = false;
|
||
echo $e->getMessage() . PHP_EOL;
|
||
}
|
||
|
||
$user->save();
|
||
} elseif (! $under_limit && $user->traffic_notified) {
|
||
$user->traffic_notified = false;
|
||
$user->save();
|
||
}
|
||
}
|
||
|
||
echo Tools::toDateTime(time()) . ' 付费用户用量限制提醒完成' . PHP_EOL;
|
||
}
|
||
|
||
public static function sendDailyTrafficReport(): void
|
||
{
|
||
$users = (new User())->whereIn('daily_mail_enable', [1, 2])->get();
|
||
$ann_latest_raw = (new Ann())->orderBy('date', 'desc')->first();
|
||
|
||
if ($ann_latest_raw === null) {
|
||
$ann_latest = '<br><br>';
|
||
} else {
|
||
$ann_latest = $ann_latest_raw->content . '<br><br>';
|
||
}
|
||
|
||
foreach ($users as $user) {
|
||
$user->sendDailyNotification($ann_latest);
|
||
}
|
||
|
||
echo Tools::toDateTime(time()) . ' 成功发送每日流量报告' . PHP_EOL;
|
||
}
|
||
|
||
/**
|
||
* @throws TelegramSDKException
|
||
*/
|
||
public static function sendTelegramDailyJob(): void
|
||
{
|
||
(new Telegram())->send(0, Config::obtain('telegram_daily_job_text'));
|
||
|
||
echo Tools::toDateTime(time()) . ' 成功发送 Telegram 每日任务提示' . PHP_EOL;
|
||
}
|
||
|
||
/**
|
||
* @throws TelegramSDKException
|
||
*/
|
||
public static function sendTelegramDiary(): void
|
||
{
|
||
(new Telegram())->send(
|
||
0,
|
||
str_replace(
|
||
[
|
||
'%getTodayCheckinUser%',
|
||
'%lastday_total%',
|
||
],
|
||
[
|
||
Analytics::getTodayCheckinUser(),
|
||
Analytics::getTodayTrafficUsage(),
|
||
],
|
||
Config::obtain('telegram_diary_text')
|
||
)
|
||
);
|
||
|
||
echo Tools::toDateTime(time()) . ' 成功发送 Telegram 系统运行日志' . PHP_EOL;
|
||
}
|
||
|
||
public static function updateNodeIp(): void
|
||
{
|
||
$nodes = (new Node())->where('type', 1)->get();
|
||
|
||
foreach ($nodes as $node) {
|
||
$node->updateNodeIp();
|
||
$node->save();
|
||
}
|
||
|
||
echo Tools::toDateTime(time()) . ' 更新节点 IP 完成' . PHP_EOL;
|
||
}
|
||
}
|