<?php
set_time_limit(600);  // 10分钟，防止大量账号时超时
ini_set('memory_limit', '256M');
define('IN_CRON', true);
include(dirname(__DIR__) . '/includes/common.php');

$forceRun = false;
if (php_sapi_name() === 'cli' && !empty($argv) && is_array($argv)) {
    foreach ($argv as $arg) {
        if ($arg === '--force' || $arg === '-f') {
            $forceRun = true;
            break;
        }
    }
}
if (php_sapi_name() !== 'cli' && isset($_GET['force']) && strval($_GET['force']) === '1') {
    $forceRun = true;
}

if (php_sapi_name() !== 'cli') {
    $key = isset($_GET['key']) ? daddslashes($_GET['key']) : '';
    if ($key === '' || $key !== (string)($conf['cronkey'] ?? '')) {
        exit('监控密钥错误');
    }
}

// 秒赞任务监控频率（秒）与并发锁
$now = time();
$qzoneCronInterval = isset($conf['qzone_cron_interval']) ? intval($conf['qzone_cron_interval']) : 60;
if ($qzoneCronInterval < 10) $qzoneCronInterval = 10;

// 子请求（带worker参数）跳过运行锁检查
$isWorkerRequest = isset($_GET['worker']) && isset($_GET['total']) && intval($_GET['total']) > 0;
if (!$isWorkerRequest) {
    $lockFp = @fopen(__DIR__ . '/qzone_cron.lock', 'c+');
    if (!$lockFp) {
        exit('秒赞任务锁文件创建失败');
    }
    if (!@flock($lockFp, LOCK_EX | LOCK_NB)) {
        exit('秒赞任务正在执行中');
    }
    register_shutdown_function(function() use ($lockFp) {
        @flock($lockFp, LOCK_UN);
        @fclose($lockFp);
    });

    $runningUntil = intval($conf['time_qzone_cron_running'] ?? 0);
    $runningRemain = $runningUntil - $now;
    $runningStaleThreshold = max($qzoneCronInterval * 3, 120);
    if ($runningRemain > 0) {
        if (!$forceRun && $runningRemain <= $runningStaleThreshold) {
            exit("秒赞任务正在执行中，剩余{$runningRemain}秒");
        }
        qzone_cron_log("检测到运行锁(剩余{$runningRemain}秒)，" . ($forceRun ? "已强制继续执行" : "已自动释放"));
    }
    $DB->exec("REPLACE INTO `pre_config` SET v='".($now + $runningStaleThreshold)."',k='time_qzone_cron_running'");
    register_shutdown_function(function() use ($DB) {
        $DB->exec("REPLACE INTO `pre_config` SET v='".time()."',k='time_qzone_cron_running'");
    });

    $lastRunTime = intval($conf['time_qzone_cron'] ?? 0);
    $nextRunRemain = ($lastRunTime + $qzoneCronInterval) - $now;
    if (!$forceRun && $nextRunRemain > 0) {
        if (php_sapi_name() === 'cli') {
            exit;
        }
        exit("未到执行时间，请 {$nextRunRemain} 秒后再试");
    }
    $DB->exec("REPLACE INTO `pre_config` SET v='{$now}',k='time_qzone_cron'");
}

require_once dirname(__DIR__) . '/includes/lib/qzone/QzoneService.php';
require_once dirname(__DIR__) . '/includes/lib/qzone/QzoneHelper.php';
require_once dirname(__DIR__) . '/includes/robot_fun.php';

$maxAccountsPerRun = isset($conf['qzone_max_accounts_per_run']) ? max(1, intval($conf['qzone_max_accounts_per_run'])) : 50;
$multithread = isset($conf['qzone_multithread']) && $conf['qzone_multithread'] == '1';
$threadCount = $multithread ? max(2, min(16, intval($conf['qzone_thread_count'] ?? 4))) : 1;
$accountsPerThread = max(0, intval($conf['qzone_accounts_per_thread'] ?? 0));

// 非多线程模式下，根据配置设置每轮最大账号数
// 0=无限制（处理所有账号），>0=限制为指定数量
if (!$multithread && $accountsPerThread > 0) {
    $maxAccountsPerRun = $accountsPerThread;
} elseif (!$multithread && $accountsPerThread == 0) {
    $maxAccountsPerRun = PHP_INT_MAX; // 无限制
}
$forkedPids = [];

// URL访问模式下，自动触发多线程（通过curl并发请求）
if ($multithread && $threadCount > 1 && !$isWorkerRequest && php_sapi_name() !== 'cli') {
    qzone_cron_log("URL模式自动触发多线程，线程数={$threadCount}");
    $baseUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
    $key = isset($_GET['key']) ? daddslashes($_GET['key']) : '';
    
    $mh = curl_multi_init();
    $handles = [];
    $urls = [];
    
    for ($w = 0; $w < $threadCount; $w++) {
        $url = $baseUrl . "?key={$key}&worker={$w}&total={$threadCount}";
        $urls[] = $url;
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 600);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_multi_add_handle($mh, $ch);
        $handles[] = $ch;
        qzone_cron_log("触发线程{$w}: {$url}");
    }
    
    $running = null;
    do {
        curl_multi_exec($mh, $running);
        curl_multi_select($mh);
    } while ($running > 0);
    
    // 获取每个子请求的响应
    foreach ($handles as $i => $ch) {
        $response = curl_multi_getcontent($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        qzone_cron_log("线程{$i} 完成: HTTP={$httpCode}, 错误={$error}, 响应长度=" . strlen($response));
        curl_multi_remove_handle($mh, $ch);
        curl_close($ch);
    }
    curl_multi_close($mh);
    
    qzone_cron_log("所有线程执行完成");
    echo '多线程执行完成';
    exit;
}

qzone_cron_log("========== 开始执行秒赞任务 ==========");

    try {
    qzone_cleanup_old_logs();
    
    // 确保下次执行时间字段存在
    $configCols = $DB->getAll("SHOW COLUMNS FROM " . DBQZ . "qzone_config");
    $configColNames = [];
    foreach ((array)$configCols as $col) {
        if (!empty($col['Field'])) $configColNames[$col['Field']] = true;
    }
    if (empty($configColNames['ssmz_next_exec_time'])) {
        $DB->exec("ALTER TABLE " . DBQZ . "qzone_config ADD COLUMN `ssmz_next_exec_time` datetime DEFAULT NULL COMMENT '秒赞下次执行时间' AFTER `ssmz_cycle`");
    }
    if (empty($configColNames['ssmp_next_exec_time'])) {
        $DB->exec("ALTER TABLE " . DBQZ . "qzone_config ADD COLUMN `ssmp_next_exec_time` datetime DEFAULT NULL COMMENT '秒评下次执行时间' AFTER `ssmp_cycle`");
    }
    
    $qqListRaw = $DB->getAll("SELECT c.*, q.*, c.id AS config_id, c.qid AS config_qid, u.email FROM " . DBQZ . "qzone_qq q 
        LEFT JOIN " . DBQZ . "qzone_config c ON q.id=c.qid 
        LEFT JOIN " . DBQZ . "user u ON q.user_id=u.zid
        WHERE q.login_status IN (0,1)
        ORDER BY COALESCE(c.last_monitor_time, '1970-01-01 00:00:00') ASC, q.id ASC");
    $qqList = [];
    foreach ((array)$qqListRaw as $row) {
        if (empty($row['qq'])) continue;
        $rowIsVip = !empty($row['vip_time']) && strtotime($row['vip_time']) > time();
        $cloudVipAllowed = (($conf['qzone_cloud_cookie'] ?? '0') != '1') || $rowIsVip;
        $cloudFeatureEnabled = (($conf['qzone_cloud_update_status'] ?? '1') == '1');
        $cloudUserEnabled = intval($row['cloud_auto_update_ck'] ?? 0) === 1;
        $cloudAutoEnabled = $cloudFeatureEnabled && $cloudUserEnabled && $cloudVipAllowed;
        if (intval($row['login_status'] ?? 0) === 1 && !$cloudAutoEnabled) continue;
        $qqList[] = $row;
    }

    if (empty($qqList)) {
        $totalCount = is_array($qqListRaw) ? count($qqListRaw) : 0;
        $msg = "没有需要处理的QQ账号（总账号{$totalCount}，可执行0）";
        qzone_cron_log($msg);
        if (php_sapi_name() === 'cli') exit;
        exit($msg);
    }

    $workerId = null;
    $workerTotal = 1;

    if ($multithread && $threadCount > 1) {
        if ($isWorkerRequest) {
            $workerId = intval($_GET['worker']);
            $workerTotal = max(1, intval($_GET['total']));
            $slice = [];
            foreach ($qqList as $qq) {
                $qid = intval($qq['id'] ?? 0);
                if ($qid <= 0) continue;
                if (($qid % $workerTotal) === $workerId) $slice[] = $qq;
            }
            $qqList = $accountsPerThread > 0 ? array_slice($slice, 0, $accountsPerThread) : $slice;
            $maxAccountsPerRun = count($qqList);
            qzone_cron_log("多线程[GET] worker={$workerId}/{$workerTotal}，本进程处理 " . count($qqList) . " 个账号");
        } elseif (php_sapi_name() === 'cli' && function_exists('pcntl_fork')) {
            $workerId = 0;
            $workerTotal = $threadCount;
            $forkedPids = [];
            for ($w = 1; $w < $threadCount; $w++) {
                $pid = @pcntl_fork();
                if ($pid === -1) break;
                if ($pid === 0) {
                    $workerId = $w;
                    $forkedPids = null;
                    break;
                }
                $forkedPids[] = $pid;
            }
            $slice = [];
            foreach ($qqList as $qq) {
                $qid = intval($qq['id'] ?? 0);
                if ($qid <= 0) continue;
                if (($qid % $workerTotal) === $workerId) $slice[] = $qq;
            }
            $qqList = $accountsPerThread > 0 ? array_slice($slice, 0, $accountsPerThread) : $slice;
            $maxAccountsPerRun = count($qqList);
            qzone_cron_log("多线程[fork] worker={$workerId}/{$workerTotal}，本进程处理 " . count($qqList) . " 个账号");
        }
    }

    $totalCount = is_array($qqListRaw) ? count($qqListRaw) : 0;
    if ($workerId === null) {
        if ($multithread) {
            qzone_cron_log("找到 " . count($qqList) . " 个可执行账号（总账号{$totalCount}），多线程模式，线程数{$threadCount}");
        } else {
            $limitText = $accountsPerThread > 0 ? "最多处理{$accountsPerThread}个" : "无限制";
            qzone_cron_log("找到 " . count($qqList) . " 个可执行账号（总账号{$totalCount}），{$limitText}");
        }
    }

    $processedThisRun = 0;
    $tryCloudRefresh = function($qqRow, $qid, $uin) use ($DB, $conf) {
        $userId = intval($qqRow['user_id'] ?? 0);
        if ($userId <= 0) return ['ok' => false, 'msg' => '用户ID无效'];
        $qqEscaped = daddslashes($uin);
        $cloudEnabled = (($conf['cloud_enabled'] ?? '1') == '1');
        $dgEnabled = (($conf['dg_open'] ?? '0') == '1');
        if (!$cloudEnabled && !$dgEnabled) return ['ok' => false, 'msg' => '云端/代挂功能未开启'];
        $srcType = 'cloud';
        $srcName = '云端版';
        $cloudQQ = $cloudEnabled ? $DB->getRow("SELECT id,cityid,login_zt FROM pre_qq WHERE qq='{$qqEscaped}' AND zid='{$userId}' LIMIT 1") : null;
        $dgQQ = null;
        if ($dgEnabled) {
            $dgQQ = $DB->getRow("SELECT id,cityid,login_zt FROM pre_dg_qq WHERE qq='{$qqEscaped}' AND zid='{$userId}' LIMIT 1");
        }
        if (!$cloudQQ && !$dgQQ) return ['ok' => false, 'msg' => '云端/代挂未添加该QQ'];
        if ($cloudQQ && intval($cloudQQ['login_zt']) === 1) {
        } elseif ($dgQQ && intval($dgQQ['login_zt']) === 1) {
            $cloudQQ = $dgQQ;
            $srcType = 'dg';
            $srcName = '代挂版';
        } else {
            if ($cloudQQ && $dgQQ) return ['ok' => false, 'msg' => '云端/代挂离线'];
            if ($cloudQQ) return ['ok' => false, 'msg' => '云端版离线'];
            return ['ok' => false, 'msg' => '代挂版离线'];
        }

        $cityid = intval($cloudQQ['cityid'] ?? 0);
        if ($cityid <= 0) return ['ok' => false, 'msg' => $srcName . '未绑定登录节点'];
        $login = get_login_config($cityid);
        if (!$login) return ['ok' => false, 'msg' => $srcName . '登录节点不存在'];
        if (isset($login['status']) && intval($login['status']) !== 1) return ['ok' => false, 'msg' => $srcName . '登录节点已停用'];

        $result = get_Cookies($login, $uin);
        if (!is_array($result)) return ['ok' => false, 'msg' => '云端接口返回异常'];
        if (($result['retcode'] ?? 0) != 200 || ($result['bool'] ?? false) !== true) {
            return ['ok' => false, 'msg' => ($result['msg'] ?? ($srcName . '获取CK失败'))];
        }
        $cookies = trim((string)($result['Cookies'] ?? ''));
        if ($cookies === '') return ['ok' => false, 'msg' => $srcName . '未返回Cookies'];

        preg_match('/(?:^|;\s*)skey=([^;]+)/i', $cookies, $skeyMatch);
        preg_match('/(?:^|;\s*)p_skey=([^;]+)/i', $cookies, $pskeyMatch);
        $skey = trim($skeyMatch[1] ?? '');
        $pskey = trim($pskeyMatch[1] ?? '');
        if ($skey === '' || $pskey === '') return ['ok' => false, 'msg' => $srcName . 'Cookie缺少skey或p_skey'];

        $gtk = QzoneService::qzoneGetGTK($pskey);
        $qzonetoken = QzoneService::qzoneGetQzonetoken($uin, $skey, $pskey);

        $skeyDb = daddslashes($skey);
        $pskeyDb = daddslashes($pskey);
        $gtkDb = daddslashes($gtk);
        $qzonetokenDb = daddslashes($qzonetoken);
        $DB->exec("UPDATE " . DBQZ . "qzone_qq SET skey='{$skeyDb}', pskey='{$pskeyDb}', gtk='{$gtkDb}', qzonetoken='{$qzonetokenDb}', login_status=0, login_time=NOW() WHERE id='{$qid}'");

        qzone_log_to_db($qid, $srcType, '从' . $srcName . '自动更新成功', 1);

        return ['ok' => true, 'skey' => $skey, 'pskey' => $pskey, 'gtk' => $gtk, 'qzonetoken' => $qzonetoken];
    };

    foreach ($qqList as $qq) {
        if ($processedThisRun >= $maxAccountsPerRun) {
            qzone_cron_log("已达本轮处理上限({$maxAccountsPerRun})，下一轮继续");
            break;
        }
        $qid = intval($qq['id'] ?? 0);
        if ($qid <= 0) {
            qzone_cron_log("检测到异常账号记录，缺少有效ID，已跳过");
            continue;
        }
        $uin = $qq['qq'];
        $skey = $qq['skey'];
        $pskey = $qq['pskey'];
        $isVip = strtotime($qq['vip_time']) > time();
        $zdfssVipOnly = intval($conf['qzone_zdfss_vip'] ?? 1) === 1;
        $zdfssDeleteVipOnly = intval($conf['qzone_zdfss_delete_vip'] ?? 1) === 1;
        $clearSsVipOnly = intval($conf['qzone_clear_ss_vip'] ?? 1) === 1;
        $clearLyVipOnly = intval($conf['qzone_clear_ly_vip'] ?? 1) === 1;
        $zdfssEnabled = intval($qq['zdfss_switch'] ?? 0) === 1 && (!$zdfssVipOnly || $isVip);
        $clearSsEnabled = intval($qq['clear_ss_switch'] ?? 0) === 1 && (!$clearSsVipOnly || $isVip);
        $clearLyEnabled = intval($qq['clear_ly_switch'] ?? 0) === 1 && (!$clearLyVipOnly || $isVip);
        
        // 秒赞频率设置
        $ssmzCycleVipOnly = intval($conf['qzone_ssmz_cycle_vip'] ?? 0) === 1;
        $freeSsmzCycle = max(20, intval($conf['qzone_free_ssmz_cycle'] ?? 60));
        if ($ssmzCycleVipOnly && !$isVip) {
            $defaultSsmzCycle = $freeSsmzCycle;
        } else {
            $defaultSsmzCycle = intval($conf['qzone_cron_interval'] ?? 60);
        }
        
        // 秒评频率设置
        $ssmpCycleVipOnly = intval($conf['qzone_ssmp_cycle_vip'] ?? 0) === 1;
        $freeSsmpCycle = max(20, intval($conf['qzone_free_ssmp_cycle'] ?? 60));
        if ($ssmpCycleVipOnly && !$isVip) {
            $defaultSsmpCycle = $freeSsmpCycle;
        } else {
            $defaultSsmpCycle = intval($conf['qzone_cron_interval'] ?? 60);
        }
        
        qzone_cron_log("QQ {$uin} [" . ($isVip ? 'VIP' : '免费') . "] 秒赞频率VIP限制=" . ($ssmzCycleVipOnly ? '开启' : '关闭') . ", 秒评频率VIP限制=" . ($ssmpCycleVipOnly ? '开启' : '关闭'));
        
        // 更新最后监控时间
        $DB->exec("UPDATE " . DBQZ . "qzone_config SET last_monitor_time=NOW() WHERE qid='{$qid}'");
        $notifyEnabled = false;
        $configRow = $DB->getRow("SELECT invalid_remind_switch FROM " . DBQZ . "qzone_config WHERE qid='{$qid}' LIMIT 1");
        if ($configRow) {
            $notifyEnabled = intval($configRow['invalid_remind_switch']) === 1;
        }
        $trySendExpireNotify = function($qqRow, $uinValue, $notifyOn) {
            if (!$notifyOn) {
                return false;
            }
            $userEmail = trim((string)($qqRow['email'] ?? ''));
            $sendEmail = $userEmail !== '' ? $userEmail : $uinValue . '@qq.com';
            return qzone_send_expire_notify($qqRow, $sendEmail);
        };
        $cloudVipAllowed = (($conf['qzone_cloud_cookie'] ?? '0') != '1') || $isVip;
        $cloudFeatureEnabled = (($conf['qzone_cloud_update_status'] ?? '1') == '1');
        $cloudUserEnabled = intval($qq['cloud_auto_update_ck'] ?? 0) === 1;
        $cloudAutoEnabled = $cloudFeatureEnabled && $cloudUserEnabled && $cloudVipAllowed;
        $cloudDisabledReason = '';
        if (!$cloudFeatureEnabled) {
            $cloudDisabledReason = '后台未开启从云端版更新状态';
        } elseif (!$cloudUserEnabled) {
            $cloudDisabledReason = '该QQ未开启从云端版自动更新';
        } elseif (!$cloudVipAllowed) {
            $cloudDisabledReason = '该QQ未满足云端更新权限';
        }

        $currentStatus = intval($qq['login_status'] ?? 0);
        if ($currentStatus == 1) {
            if (!empty($skey) && !empty($pskey) && QzoneService::check_status($uin, $skey, $pskey)) {
                $DB->exec("UPDATE " . DBQZ . "qzone_qq SET login_status=0, login_time=NOW() WHERE id='{$qid}'");
                qzone_cron_log("QQ {$uin} 原状态离线，但本次检测CK有效，已自动恢复在线");
            } elseif (!$cloudAutoEnabled) {
                qzone_cron_log("QQ {$uin} 已离线，且未开启云端自动更新，跳过执行");
                continue;
            } else {
                $refreshResult = $tryCloudRefresh($qq, $qid, $uin);
                if (empty($refreshResult['ok'])) {
                    qzone_cron_log("QQ {$uin} 离线自动更新失败：" . ($refreshResult['msg'] ?? '未知错误'));
                    continue;
                }
                $skey = $refreshResult['skey'];
                $pskey = $refreshResult['pskey'];
                $gtk = $refreshResult['gtk'];
                $qzonetoken = $refreshResult['qzonetoken'];
                qzone_cron_log("QQ {$uin} 离线后已从云端自动更新CK，继续执行任务");
            }
        }

        if (empty($skey) || empty($pskey)) {
            $cookieFailReason = 'Cookie缺失';
            if ($cloudAutoEnabled) {
                $refreshResult = $tryCloudRefresh($qq, $qid, $uin);
                if (!empty($refreshResult['ok'])) {
                    $skey = $refreshResult['skey'];
                    $pskey = $refreshResult['pskey'];
                    $gtk = $refreshResult['gtk'];
                    $qzonetoken = $refreshResult['qzonetoken'];
                    qzone_cron_log("QQ {$uin} Cookie缺失，已从云端自动补全");
                } else {
                    $cookieFailReason = 'Cookie缺失且云端补全失败：' . ($refreshResult['msg'] ?? '未知错误');
                    qzone_cron_log("QQ {$uin} {$cookieFailReason}");
                }
            } else {
                $cookieFailReason = 'Cookie缺失，' . $cloudDisabledReason;
                qzone_cron_log("QQ {$uin} {$cookieFailReason}");
            }
            if (empty($skey) || empty($pskey)) {
                $oldStatus = intval($DB->getColumn("SELECT login_status FROM " . DBQZ . "qzone_qq WHERE id='{$qid}' LIMIT 1"));
                $DB->exec("UPDATE " . DBQZ . "qzone_qq SET login_status=1 WHERE id='{$qid}'");
                qzone_log_to_db($qid, 'error', $cookieFailReason . '，请重新登录', 0);
                
                if ($oldStatus == 0) {
                    $trySendExpireNotify($qq, $uin, $notifyEnabled);
                }
                continue;
            }
        }

        $gtk = QzoneService::qzoneGetGTK($pskey);
        $qzonetoken = QzoneService::qzoneGetQzonetoken($uin, $skey, $pskey);

        qzone_cron_log("处理QQ: {$uin}" . ($isVip ? ' [VIP]' : ' [免费版]'));

        if (!QzoneService::check_status($uin, $skey, $pskey)) {
            $offlineReason = 'Cookie已失效';
            if ($cloudAutoEnabled) {
                $refreshResult = $tryCloudRefresh($qq, $qid, $uin);
                if (!empty($refreshResult['ok'])) {
                    $skey = $refreshResult['skey'];
                    $pskey = $refreshResult['pskey'];
                    $gtk = $refreshResult['gtk'];
                    $qzonetoken = $refreshResult['qzonetoken'];
                    qzone_cron_log("QQ {$uin} Cookie失效后已从云端自动更新CK，继续执行任务");
                } else {
                    $offlineReason = 'Cookie失效后云端更新失败：' . ($refreshResult['msg'] ?? '未知错误');
                    qzone_cron_log("QQ {$uin} {$offlineReason}");
                }
            } else {
                $offlineReason = 'Cookie失效，' . $cloudDisabledReason;
                qzone_cron_log("QQ {$uin} {$offlineReason}");
            }
            if (!QzoneService::check_status($uin, $skey, $pskey)) {
                $oldStatus = intval($DB->getColumn("SELECT login_status FROM " . DBQZ . "qzone_qq WHERE id='{$qid}' LIMIT 1"));
                $DB->exec("UPDATE " . DBQZ . "qzone_qq SET login_status=1 WHERE id='{$qid}'");
                qzone_log_to_db($qid, 'error', $offlineReason . '，请重新登录', 0);
                
                if ($oldStatus == 0) {
                    $trySendExpireNotify($qq, $uin, $notifyEnabled);
                }
                continue;
            }
        }

        $hasAnyTaskEnabled = intval($qq['ssmz_switch'] ?? 0) === 1
            || intval($qq['ssmp_switch'] ?? 0) === 1
            || $zdfssEnabled
            || intval($qq['zfss_switch'] ?? 0) === 1
            || intval($qq['sign_switch'] ?? 0) === 1
            || $clearSsEnabled
            || $clearLyEnabled;
        if (!$hasAnyTaskEnabled) {
            qzone_cron_log("QQ {$uin} 监控正常，未开启任何任务");
            continue;
        }
        $processedThisRun++;

        if ($qq['ssmz_switch'] == 1) {
            // 任务周期：优先用户设置，否则使用默认频率
            // 兼容 ssmz_cycle 和 ssmz_exec_cycle 字段
            $cycle = intval($qq['ssmz_cycle'] ?? 0);
            if ($cycle <= 0) $cycle = intval($qq['ssmz_exec_cycle'] ?? 0);
            if ($cycle < 20) $cycle = $defaultSsmzCycle;
            // VIP限制检查：免费用户使用免费频率
            if ($ssmzCycleVipOnly && !$isVip) {
                $cycle = $freeSsmzCycle;
            }
            
            // 使用下次执行时间判断（允许3秒容差，避免因时间误差跳过）
            $nextExecTime = $qq['ssmz_next_exec_time'] ?? null;
            $nowTime = time();
            $shouldExec = false;
            $tolerance = 3; // 容差秒数
            
            if (empty($nextExecTime)) {
                // 首次执行或无记录，立即执行
                $shouldExec = true;
                qzone_cron_log("秒赞: 无下次执行时间记录，立即执行");
            } else {
                $nextExecTimestamp = strtotime($nextExecTime);
                $remainSeconds = $nextExecTimestamp - $nowTime;
                if ($remainSeconds <= $tolerance) {
                    $shouldExec = true;
                    if ($remainSeconds <= 0) {
                        $waitedSeconds = abs($remainSeconds);
                        qzone_cron_log("秒赞: 已到达执行时间，周期={$cycle}s，已等待{$waitedSeconds}秒");
                    } else {
                        qzone_cron_log("秒赞: 接近执行时间（剩余{$remainSeconds}秒），容差内执行");
                    }
                } else {
                    qzone_cron_log("秒赞: 未到执行时间，周期={$cycle}s，剩余{$remainSeconds}秒，跳过");
                }
            }
            
            if ($shouldExec) {
                // 更新下次执行时间（先更新，防止并发重复执行）
                $nextExecDateTime = date('Y-m-d H:i:s', $nowTime + $cycle);
                $DB->exec("UPDATE " . DBQZ . "qzone_config SET ssmz_next_exec_time='{$nextExecDateTime}' WHERE qid='{$qid}'");
                
                qzone_cron_log("执行说说秒赞...");
                $qzoneList = QzoneService::getQzoneList($uin, $skey, $pskey, $gtk, $qzonetoken);
                $execResult = '';
                $execStatus = 0;
                if ($qzoneList) {
                    $whitelist = qzone_parse_qq_list($qq['ssmz_whitelist'] ?? '');
                    $blacklist = qzone_parse_qq_list($qq['ssmz_blacklist'] ?? '');
                    $hourlyMax = $isVip ? intval($qq['ssmz_hourly_max'] ?? 0) : 0;
                    if (!$isVip && intval($conf['qzone_ssmz_hourly_vip'] ?? 0) === 1) {
                        $hourlyMax = max(0, intval($conf['qzone_free_hourly_ssmz'] ?? 0));
                    }

                    if ($hourlyMax > 0) {
                        $hourCount = $DB->getColumn("SELECT COUNT(*) FROM " . DBQZ . "qzone_log WHERE qid='{$qid}' AND type='ssmz' AND status=1 AND create_time > DATE_SUB(NOW(), INTERVAL 1 HOUR)");
                        if ($hourCount >= $hourlyMax) {
                            qzone_cron_log("QQ {$uin} 达到每小时点赞上限({$hourCount}/{$hourlyMax})");
                            $qzoneList = [];
                        }
                    }

                    $likeCount = 0;
                    foreach ($qzoneList as $item) {
                        if ($likeCount >= 8) break;
                        if ($item['is_like']) continue;
                        $touin = (string)($item['touin'] ?? '');
                        if (!empty($whitelist) && !in_array($touin, $whitelist, true)) continue;
                        if (!empty($blacklist) && in_array($touin, $blacklist, true)) continue;
                        $feedKey = qzone_get_feed_unique_key($item);
                        if (qzone_has_seen_feed('ssmz', $qid, $feedKey)) continue;

                        $result = QzoneService::like_h5($uin, $skey, $pskey, $qzonetoken, $gtk, $item['touin'], $item['appid'], urlencode($item['uinkey']), urlencode($item['curkey']));
                        $status = strpos($result, '成功') !== false ? 1 : 0;
                        qzone_log_to_db($qid, 'ssmz', $result, $status, $feedKey);
                        $likeCount++;
                        qzone_cron_log("QQ {$uin} {$result}");
                        if ($status == 1) $execStatus = 1;

                        if (strpos($result, '失效') !== false) {
                            qzone_update_qq_status($qid, 1);
                            break 2;
                        }
                        usleep(200000);
                    }
                    if ($likeCount == 0) {
                        qzone_cron_log("没有需要点赞的说说");
                        $execResult = '没有需要点赞的说说';
                    } else {
                        $execResult = "成功点赞{$likeCount}条说说";
                    }
                } else {
                    $execResult = '获取说说列表失败';
                    qzone_cron_log("QQ {$uin} 获取说说列表失败");
                }
                
                // 不再写入开始任务日志，按每条实际操作记录明细日志
            }
        }

        if ($qq['ssmp_switch'] == 1) {
            // 任务周期：优先用户设置，否则使用默认频率
            // 兼容 ssmp_cycle 和 ssmp_exec_cycle 字段
            $cycle = intval($qq['ssmp_cycle'] ?? 0);
            if ($cycle <= 0) $cycle = intval($qq['ssmp_exec_cycle'] ?? 0);
            if ($cycle < 20) $cycle = $defaultSsmpCycle;
            // VIP限制检查：免费用户使用免费频率
            if ($ssmpCycleVipOnly && !$isVip) {
                $cycle = $freeSsmpCycle;
            }
            
            // 使用下次执行时间判断（允许3秒容差，避免因时间误差跳过）
            $nextExecTime = $qq['ssmp_next_exec_time'] ?? null;
            $nowTime = time();
            $shouldExec = false;
            $tolerance = 3; // 容差秒数
            
            if (empty($nextExecTime)) {
                // 首次执行或无记录，立即执行
                $shouldExec = true;
                qzone_cron_log("秒评: 无下次执行时间记录，立即执行");
            } else {
                $nextExecTimestamp = strtotime($nextExecTime);
                $remainSeconds = $nextExecTimestamp - $nowTime;
                if ($remainSeconds <= $tolerance) {
                    $shouldExec = true;
                    if ($remainSeconds <= 0) {
                        $waitedSeconds = abs($remainSeconds);
                        qzone_cron_log("秒评: 已到达执行时间，周期={$cycle}s，已等待{$waitedSeconds}秒");
                    } else {
                        qzone_cron_log("秒评: 接近执行时间（剩余{$remainSeconds}秒），容差内执行");
                    }
                } else {
                    qzone_cron_log("秒评: 未到执行时间，周期={$cycle}s，剩余{$remainSeconds}秒，跳过");
                }
            }
            
            if ($shouldExec) {
                // 更新下次执行时间（先更新，防止并发重复执行）
                $nextExecDateTime = date('Y-m-d H:i:s', $nowTime + $cycle);
                $DB->exec("UPDATE " . DBQZ . "qzone_config SET ssmp_next_exec_time='{$nextExecDateTime}' WHERE qid='{$qid}'");
                
                qzone_cron_log("执行说说秒评...");
                $qzoneList = QzoneService::getQzoneList($uin, $skey, $pskey, $gtk, $qzonetoken);
                $execResult = '';
                $execStatus = 0;
                if ($qzoneList) {
                    $whitelist = qzone_parse_qq_list($qq['ssmp_whitelist'] ?? '');
                    $blacklist = qzone_parse_qq_list($qq['ssmp_blacklist'] ?? '');
                    $hourlyMax = $isVip ? intval($qq['ssmp_hourly_max'] ?? 0) : 0;
                    if (!$isVip && intval($conf['qzone_ssmp_hourly_vip'] ?? 0) === 1) {
                        $hourlyMax = max(0, intval($conf['qzone_free_hourly_ssmp'] ?? 0));
                    }
                    $comment = $qq['ssmp_comment'] ?? '';
                    $images = qzone_parse_image_list($qq['ssmp_images'] ?? ($qq['ssmp_pic_url'] ?? ''));

                    if (empty($comment)) {
                        qzone_cron_log("未设置评论内容，跳过");
                        $execResult = '未设置评论内容';
                    } else {
                        if ($hourlyMax > 0) {
                            $hourCount = $DB->getColumn("SELECT COUNT(*) FROM " . DBQZ . "qzone_log WHERE qid='{$qid}' AND type='ssmp' AND status=1 AND create_time > DATE_SUB(NOW(), INTERVAL 1 HOUR)");
                            if ($hourCount >= $hourlyMax) {
                                qzone_cron_log("QQ {$uin} 达到每小时评论上限({$hourCount}/{$hourlyMax})");
                                $qzoneList = [];
                            }
                        }

                        $commentArr = explode("\n", $comment);
                        $commentCount = 0;

                        foreach ($qzoneList as $item) {
                            if ($commentCount >= 5) break;
                            if ($item['is_comment']) continue;
                            $touin = (string)($item['touin'] ?? '');
                            // 白名单：填写后仅处理白名单中的QQ
                            if (!empty($whitelist) && !in_array($touin, $whitelist, true)) continue;
                            // 黑名单：始终跳过
                            if (!empty($blacklist) && in_array($touin, $blacklist, true)) continue;
                            $feedKey = qzone_get_feed_unique_key($item);
                            if (qzone_has_seen_feed('ssmp', $qid, $feedKey)) continue;

                            $currentComment = trim($commentArr[array_rand($commentArr)]);
                            $currentComment = QzoneHelper::parseContent($currentComment);
                            $currentComment = replace_text_variable($currentComment);

                            if (!$isVip && !empty($conf['qzone_tail_pl'])) {
                                $currentComment .= $conf['qzone_tail_pl'];
                            }

                            $richval = null;
                            if (!empty($images)) {
                                $imgUrl = $images[array_rand($images)];
                                qzone_cron_log("QQ {$uin} 准备上传图片: {$imgUrl}");
                                $imageUrl = QzoneService::uploadimg_pc($uin, $skey, $pskey, $imgUrl, true);
                                qzone_cron_log("QQ {$uin} 图片上传结果: " . var_export($imageUrl, true));
                                if ($imageUrl !== false) {
                                    $richval = $imageUrl;
                                } else {
                                    qzone_cron_log("QQ {$uin} 图片上传失败: {$imgUrl}");
                                }
                            }

                            $result = QzoneService::comment_h5($uin, $skey, $pskey, $currentComment, $item['touin'], $item['ssid'], $item['from'], $richval);
                            
                            if (strpos($result, '链接不是有效链接') !== false && $richval !== null) {
                                qzone_cron_log("QQ {$uin} 图片评论失败，尝试降级为文字评论");
                                $result = QzoneService::comment_h5($uin, $skey, $pskey, $currentComment, $item['touin'], $item['ssid'], $item['from'], null);
                            }
                            
                            $status = strpos($result, '成功') !== false ? 1 : 0;
                            qzone_log_to_db($qid, 'ssmp', $result, $status, $feedKey);
                            $commentCount++;
                            qzone_cron_log("QQ {$uin} {$result}");
                            if ($status == 1) $execStatus = 1;

                            if (strpos($result, '失效') !== false) {
                                qzone_update_qq_status($qid, 1);
                                break 2;
                            }
                            if (strpos($result, '频繁') !== false) break;
                            usleep(300000);
                        }
                        if ($commentCount == 0) {
                            qzone_cron_log("没有需要评论的说说");
                            $execResult = '没有需要评论的说说';
                        } else {
                            $execResult = "成功评论{$commentCount}条说说";
                        }
                    }
                } else {
                    $execResult = '获取说说列表失败';
                    qzone_cron_log("QQ {$uin} 获取说说列表失败");
                }
                
                // 不再写入开始任务日志，按每条实际操作记录明细日志
            }
        }

        if ($zdfssEnabled) {
            qzone_cron_log("执行自动发说说...");

            // 任务周期：优先 zdfss_cycle(分钟)，兼容 zdfss_exec_cycle(秒)
            $zdfssCycleMinutes = intval($qq['zdfss_cycle'] ?? 0);
            if ($zdfssCycleMinutes > 0) {
                $cycle = $zdfssCycleMinutes * 60; // 分钟转秒
            } else {
                $cycle = intval($qq['zdfss_exec_cycle'] ?? 0);
            }
            if ($cycle < 60) $cycle = 3600; // 默认1小时
            $lastTime = $DB->getColumn("SELECT create_time FROM " . DBQZ . "qzone_log WHERE qid='{$qid}' AND type='zdfss' ORDER BY id DESC LIMIT 1");
            $elapsed = $lastTime ? (time() - strtotime($lastTime)) : 0;
            // 允许1秒误差
            if ($lastTime && $elapsed < $cycle - 1) {
                qzone_cron_log("未到执行周期({$cycle}秒)，跳过");
            } else {
                $content = $qq['zdfss_content'] ?? '';
                $images = qzone_parse_image_list($qq['zdfss_images'] ?? ($qq['zdfss_pic_url'] ?? ''));
                $blacklist = json_decode($qq['zdfss_whitelist'] ?? '[]', true) ?: [];

                if (empty($content)) {
                    qzone_cron_log("未设置说说内容，跳过");
                } else {
                    if (intval($qq['zdfss_delete_prev'] ?? 0) === 1 && (!$zdfssDeleteVipOnly || $isVip)) {
                        $myNews = QzoneService::getMyNews($uin, $skey, $pskey, $qzonetoken, $gtk);
                        if ($myNews['code'] == 200 && !empty($myNews['data'])) {
                            $prevSsid = $myNews['data'][0]['id']['cellid'] ?? '';
                            if ($prevSsid) {
                                $delResult = QzoneService::delete_shuo_h5($uin, $skey, $pskey, $gtk, $qzonetoken, $prevSsid);
                                $delStatus = (is_array($delResult) && isset($delResult['code']) && intval($delResult['code']) == 200) ? 1 : 0;
                                $delMsg = is_array($delResult) && !empty($delResult['msg']) ? $delResult['msg'] : '删除上一条说说结果未知';
                                qzone_log_to_db($qid, 'zdfss', '发说说前删除上一条：' . $delMsg, $delStatus, $prevSsid);
                                qzone_cron_log("QQ {$uin} 发说说前删除上一条：{$delMsg}");
                            } else {
                                qzone_log_to_db($qid, 'zdfss', '发说说前删除上一条：未找到可删除说说', 0);
                                qzone_cron_log("QQ {$uin} 发说说前删除上一条：未找到可删除说说");
                            }
                        } else {
                            $msg = is_array($myNews) && !empty($myNews['msg']) ? $myNews['msg'] : '获取上一条说说失败';
                            qzone_log_to_db($qid, 'zdfss', '发说说前删除上一条：' . $msg, 0);
                            qzone_cron_log("QQ {$uin} 发说说前删除上一条：{$msg}");
                        }
                    } elseif (intval($qq['zdfss_delete_prev'] ?? 0) === 1 && $zdfssDeleteVipOnly && !$isVip) {
                        qzone_cron_log("QQ {$uin} 发说说前删除上一条：未满足VIP权限，已跳过");
                    }

                    $content = QzoneHelper::randLine($content);
                    $content = QzoneHelper::parseContent($content);
                    $content = replace_text_variable($content);

                    if (!$isVip && !empty($conf['qzone_tail_zdfss'])) {
                        $content .= $conf['qzone_tail_zdfss'];
                    }

                    $richval = null;
                    if (!empty($images)) {
                        $imgUrl = $images[array_rand($images)];
                        $richval = QzoneService::uploadimg_pc($uin, $skey, $pskey, $imgUrl);
                    }

                    $listParam = false;
                    if (!empty($blacklist)) {
                        qzone_cron_log("不可见好友: " . implode(',', $blacklist));
                    }

                    $result = QzoneService::shuos($uin, $skey, $pskey, $content, $richval, $listParam, $blacklist);
                    $status = $result['code'] == 0 ? 1 : 0;
                    qzone_log_to_db($qid, 'zdfss', $result['msg'], $status);
                    qzone_cron_log("QQ {$uin} {$result['msg']}");
                }
            }
        } elseif (intval($qq['zdfss_switch'] ?? 0) === 1 && $zdfssVipOnly && !$isVip) {
            qzone_cron_log("QQ {$uin} 自动发说说：未满足VIP权限，已跳过");
        }

        if ($qq['zfss_switch'] == 1) {
            qzone_cron_log("执行转发说说...");

            // 任务周期：使用默认频率
            $zfssCycle = intval($conf['qzone_cron_interval'] ?? 60);
            if ($zfssCycle < 20) $zfssCycle = 60;
            $lastTime = $DB->getColumn("SELECT create_time FROM " . DBQZ . "qzone_log WHERE qid='{$qid}' AND type='zfss' ORDER BY id DESC LIMIT 1");
            $elapsed = $lastTime ? (time() - strtotime($lastTime)) : 0;
            // 允许1秒误差
            if ($lastTime && $elapsed < $zfssCycle - 1) {
                qzone_cron_log("未到执行周期({$zfssCycle}秒)，跳过");
            } else {
                $rawWhitelist = $qq['zfss_whitelist'] ?? ($qq['zfss_forward_list'] ?? '');
                $whitelist = json_decode((string)$rawWhitelist, true);
                if (!is_array($whitelist)) {
                    $parts = preg_split('/[\*\s,，\r\n]+/', (string)$rawWhitelist);
                    $whitelist = [];
                    foreach ((array)$parts as $p) {
                        $p = trim($p);
                        if ($p !== '') $whitelist[] = $p;
                    }
                }
                $whitelist = array_values(array_unique(array_map('strval', (array)$whitelist)));
                if (empty($whitelist)) {
                    qzone_cron_log("未设置转发白名单，跳过");
                } else {
                    $qzoneList = QzoneService::getQzoneList($uin, $skey, $pskey, $gtk, $qzonetoken);
                    if ($qzoneList) {
                        $forwardCount = 0;
                        foreach ($qzoneList as $item) {
                            if ($forwardCount >= 3) break;
                            if (!in_array((string)$item['touin'], $whitelist, true)) continue;
                            $feedKey = qzone_get_feed_unique_key($item);
                            if (qzone_has_seen_feed('zfss', $qid, $feedKey)) continue;

                            $result = QzoneService::pczhuanfa($uin, $skey, $pskey, (string)($qq['zfss_content'] ?? ''), $item['touin'], $item['ssid']);
                            $status = strpos($result, '成功') !== false ? 1 : 0;
                            qzone_log_to_db($qid, 'zfss', $result, $status, $feedKey);
                            $forwardCount++;
                            qzone_cron_log("QQ {$uin} {$result}");

                            if (strpos($result, '失效') !== false) {
                                qzone_update_qq_status($qid, 1);
                                break;
                            }
                            usleep(300000);
                        }
                        if ($forwardCount == 0) qzone_cron_log("没有需要转发的说说");
                    }
                }
            }
        }

        if ($qq['sign_switch'] == 1) {
            qzone_cron_log("执行空间签到...");

            // 签到周期：优先用户设置，否则默认一天一次
            if (isset($qq['sign_cycle']) && intval($qq['sign_cycle']) > 0) {
                $signCycleMinutes = intval($qq['sign_cycle']);
            } elseif (isset($qq['sign_exec_cycle']) && intval($qq['sign_exec_cycle']) > 0) {
                $signCycleMinutes = max(1, intval(intval($qq['sign_exec_cycle']) / 60));
            } else {
                $signCycleMinutes = 1440; // 默认一天一次
            }
            $signCycleSeconds = $signCycleMinutes * 60;

            $logMeta = getLogMeta();
            $lastSignTime = false;
            if ($logMeta['ok']) {
                $where = "qid='{$qid}' AND type='sign'";
                if ($logMeta['status_col'] !== '') {
                    $where .= " AND `{$logMeta['status_col']}`='1'";
                }
                $lastSignTime = $DB->getColumn("SELECT `{$logMeta['time_col']}` FROM `{$logMeta['table']}` WHERE {$where} ORDER BY id DESC LIMIT 1");
            } else {
                $lastSignTime = $DB->getColumn("SELECT create_time FROM " . DBQZ . "qzone_log WHERE qid='{$qid}' AND type='sign' ORDER BY id DESC LIMIT 1");
            }
            $elapsed = $lastSignTime ? (time() - strtotime($lastSignTime)) : 0;
            // 允许1秒误差
            if ($lastSignTime && $elapsed < $signCycleSeconds - 1) {
                qzone_cron_log("未到签到周期，跳过");
            } else {
                $signContent = $qq['sign_content'] ?? '';
                if ($signContent) {
                    $contents = explode(',', $signContent);
                    $signContent = trim($contents[array_rand($contents)]);
                } else {
                    $signContent = '签到成功';
                }
                $signContent = QzoneHelper::parseContent($signContent);
                $signContent = replace_text_variable($signContent);

                $result = QzoneService::cpqiandao($uin, $skey, $pskey, $qzonetoken, $gtk, $signContent);
                $status = $result['code'] == 200 ? 1 : 0;
                qzone_log_to_db($qid, 'sign', $result['msg'], $status);
                qzone_cron_log("QQ {$uin} {$result['msg']}");
            }
        }

        if ($clearSsEnabled) {
            qzone_cron_log("执行清空说说...");

            // 固定每10分钟清10条
            $clearCycle = 600; // 10分钟
            $lastTime = $DB->getColumn("SELECT create_time FROM " . DBQZ . "qzone_log WHERE qid='{$qid}' AND type='clear_ss' ORDER BY id DESC LIMIT 1");
            $elapsed = $lastTime ? (time() - strtotime($lastTime)) : $clearCycle;
            if ($elapsed < $clearCycle - 1) {
                qzone_cron_log("未到清空周期({$clearCycle}秒)，跳过");
            } else {
                $myNews = QzoneService::getMyNews($uin, $skey, $pskey, $qzonetoken, $gtk);
                if ($myNews['code'] == 200 && !empty($myNews['data'])) {
                    $clearCount = 0;
                    foreach ($myNews['data'] as $shuo) {
                        if ($clearCount >= 10) break;
                        $cellid = $shuo['id']['cellid'] ?? '';
                        if ($cellid) {
                            $result = QzoneService::delete_shuo_h5($uin, $skey, $pskey, $gtk, $qzonetoken, $cellid);
                            if ($result['code'] == 200) $clearCount++;
                            usleep(200000);
                        }
                    }
                    $msg = "清空了 {$clearCount} 条说说";
                    qzone_log_to_db($qid, 'clear_ss', $msg, 1);
                    qzone_cron_log("QQ {$uin} {$msg}");
                } else {
                    qzone_cron_log("QQ {$uin} 获取说说列表失败或为空");
                }
            }
        } elseif (intval($qq['clear_ss_switch'] ?? 0) === 1 && $clearSsVipOnly && !$isVip) {
            qzone_cron_log("QQ {$uin} 清空说说：未满足VIP权限，已跳过");
        }

        if ($clearLyEnabled) {
            qzone_cron_log("执行清空留言...");

            // 固定每10分钟清10条
            $clearCycle = 600; // 10分钟
            $lastTime = $DB->getColumn("SELECT create_time FROM " . DBQZ . "qzone_log WHERE qid='{$qid}' AND type='clear_ly' ORDER BY id DESC LIMIT 1");
            $elapsed = $lastTime ? (time() - strtotime($lastTime)) : $clearCycle;
            if ($elapsed < $clearCycle - 1) {
                qzone_cron_log("未到清空周期({$clearCycle}秒)，跳过");
            } else {
                $lyResult = QzoneService::getliuyan($uin, $skey, $pskey);
                if ($lyResult['code'] == 200 && !empty($lyResult['data'])) {
                    $idArray = [];
                    $uinArray = [];
                    $count = 0;
                    foreach ($lyResult['data'] as $row) {
                        if ($count >= 10) break;
                        $idArray[] = $row['id'];
                        $uinArray[] = $row['uin'];
                        $count++;
                    }
                    if (!empty($idArray)) {
                        $idList = implode(',', $idArray);
                        $uinList = implode(',', $uinArray);
                        $delResult = QzoneService::deleteliuyan($uin, $skey, $pskey, $idList, $uinList);
                        $status = $delResult['code'] == 200 ? 1 : 0;
                        qzone_log_to_db($qid, 'clear_ly', $delResult['msg'] . " ({$count}条)", $status);
                        qzone_cron_log("QQ {$uin} {$delResult['msg']} ({$count}条)");
                    }
                } else {
                    qzone_cron_log("QQ {$uin} 获取留言列表失败或为空");
                }
            }
        } elseif (intval($qq['clear_ly_switch'] ?? 0) === 1 && $clearLyVipOnly && !$isVip) {
            qzone_cron_log("QQ {$uin} 清空留言：未满足VIP权限，已跳过");
        }

        usleep(500000);
        qzone_cron_log("QQ {$uin} 任务执行完成");
    }

    qzone_cron_log("========== 所有任务执行完成 ==========");

    if ($multithread && $threadCount > 1 && isset($workerId) && $workerId > 0) {
        exit(0);
    }
    if (!empty($forkedPids)) {
        foreach ($forkedPids as $pid) {
            if ($pid > 0) @pcntl_waitpid($pid, $status);
        }
    }

} catch (Exception $e) {
    qzone_cron_log("执行出错: " . $e->getMessage());
    if (php_sapi_name() !== 'cli') {
        echo '执行出错：' . $e->getMessage();
    }
} catch (Throwable $e) {
    qzone_cron_log("执行出错(Throwable): " . $e->getMessage());
    if (php_sapi_name() !== 'cli') {
        echo '执行出错：' . $e->getMessage();
    }
}

if (php_sapi_name() !== 'cli') {
    echo '执行完成';
}
