<?php
/**
 * 自动更新核心程序（静默版 + flock 文件锁 + 自动标志写入修复）
 * PHP 5.6 兼容版（去除 ?? 操作符）
 * Version: 2025.10 Final Fixed Edition (php56)
 */

ignore_user_abort(true);
set_time_limit(0);
ob_start();
date_default_timezone_set('PRC');

$log_dir  = __DIR__ . '/tmp';
$log_file = $log_dir . '/update.log';
if (!is_dir($log_dir)) { mkdir($log_dir, 0777, true); }

// ---------- flock 文件锁 ----------
$lock_file = __DIR__ . '/update.lock';
$fp = fopen($lock_file, 'c+');
if (!$fp) {
    file_put_contents($log_file, "[错误] 无法创建锁文件：$lock_file\n", FILE_APPEND);
    exit;
}
if (!flock($fp, LOCK_EX | LOCK_NB)) {
    file_put_contents($log_file, "[警告] 已有更新任务在执行中，退出。\n", FILE_APPEND);
    fclose($fp);
    exit;
}
// ----------------------------------

file_put_contents($log_file, "=== ppqCMS 自动更新开始 " . date('Y-m-d H:i:s') . " ===\n", FILE_APPEND);

// ---------- 1. 读取 API.KEY（兼容旧逻辑，仅用于解码兜底） ----------
$jurl_encoded = @file_get_contents(__DIR__ . '/API.KEY');
if (!$jurl_encoded) {
    file_put_contents($log_file, "[错误] 未找到 API.KEY\n", FILE_APPEND);
    flock($fp, LOCK_UN); fclose($fp);
    exit;
}

$jurl = $jurl_encoded;
for ($i = 1; $i <= 9; $i++) {
    $jurl = base64_decode($jurl);
    if (strpos($jurl, 'http') === 0) break;
}
if (!$jurl || stripos($jurl, 'http') === false) {
    file_put_contents($log_file, "[错误] API.KEY 无效\n", FILE_APPEND);
    flock($fp, LOCK_UN); fclose($fp);
    exit;
}

// 实际采集地址以 collect_lib 的 get_collection_api() 为准（优先后台 CollectionDomain）
require_once __DIR__ . '/collect_lib.php';

// ---------- 访问门槛 ----------
// API.php 是公开地址，任何人访问都能触发一次采集。这里只挡"明显来自站外"的直接访问。
// 判断逻辑见 collect_lib.php 的 ppq_update_gate_allowed()。
if (!function_exists('ppq_update_gate_allowed') || !ppq_update_gate_allowed()) {
    file_put_contents($log_file, "[拒绝] 非法来源访问：" . (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '无 referer') . "\n", FILE_APPEND);
    http_response_code(403);
    exit('forbidden');
}

$real_api = get_collection_api();
if (!$real_api) {
    file_put_contents($log_file, "[错误] 未配置采集点地址（请在系统设置填写采集点域名）\n", FILE_APPEND);
    flock($fp, LOCK_UN); fclose($fp);
    exit;
}

// Return the browser response before the potentially long update work begins.
// PHP-FPM otherwise terminates this request at its pool timeout while the
// collector is still working, causing the front end to loop on the update page.
if (function_exists('fastcgi_finish_request')) {
    echo 'update-started';
    if (ob_get_level()) { @ob_end_flush(); }
    @fastcgi_finish_request();
}

function check_url_status($url) {
    $ch = curl_init($url);
    curl_setopt_array($ch, array(
        CURLOPT_NOBODY         => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 8,
        CURLOPT_USERAGENT      => 'Mozilla/5.0 (compatible; PPQCMS/1.0)',
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_SSL_VERIFYHOST => false,
    ));
    curl_exec($ch);
    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    return $code;
}

// 用实际采集地址做可达性验证（注意：API 端点可能返回非 200 但数据正常，
// 因此仅当完全无法连接（0 / timeout）时才跳过）
$probe = check_url_status($real_api . '/?ac=list&pg=1&limit=1');
if ($probe == 0) {
    $flag_file = __DIR__ . '/../PPQSQL.PPQSQL';
    if (!is_dir(dirname($flag_file))) { mkdir(dirname($flag_file), 0777, true); }
    file_put_contents($flag_file, date('Ymd'));
    file_put_contents($log_file, "[警告] 采集点不可访问（连接失败），已直接标记为已更新。\n", FILE_APPEND);
    flock($fp, LOCK_UN); fclose($fp);
    exit;
}

// ---------- 4. 加载采集共享库（替代原下载模块 JURL.php） ----------
require_once __DIR__ . '/collect_lib.php';

// ---------- 5. Bind before collection ----------
// The previous order collected with old category IDs and only then replaced type.php.
// Binding first keeps the active category registry, Home files and templates in sync.
$r = bind_categories();
if (empty($r['ok'])) {
    file_put_contents($log_file, "[错误] 分类同步失败：" . (isset($r['msg']) ? $r['msg'] : '未知错误') . "\n", FILE_APPEND);
    flock($fp, LOCK_UN); fclose($fp);
    exit;
}
file_put_contents($log_file, "[信息] 分类已同步：" . $r['msg'] . "\n", FILE_APPEND);
// bind_categories() 内部在"换资源点"或"分类结构变化"时已经清理过旧站视频，
// 这里不再重复清理，否则会把刚采到的内容一起删掉。

// 每日更新 = 纯增量：只把资源点当天新出的内容追加进来，
// 不设每类目标、不补齐缺口、不主动裁剪，站上的视频随时间一直累积。
// 唯一的例外是单个分类涨到 33000 条封顶时，才会覆盖最旧的（见 collect_lib.php）。
// 后台"每类采集多少条"那个数字只用于手动采集，跟每日更新无关。
file_put_contents($log_file, "[信息] 启动每日增量采集：同步资源点当日新增内容...\n", FILE_APPEND);
incremental_collect(0, true, 0);
file_put_contents($log_file, "[完成] 每日增量采集结束。\n", FILE_APPEND);

// ---------- 9. 写入更新状态 ----------
// 原文此处有一行 file_put_contents(__DIR__ . '/Home/API.CEY', $json);
// 但 $json 在本文件中从未定义，每次都会写入空文件并产生一条 PHP Notice。
// Php/Home/Ad.php 读取该文件时已自带兜底（空内容按默认值处理），故直接移除。
if (!is_dir(__DIR__ . '/Home')) { mkdir(__DIR__ . '/Home', 0777, true); }

// realpath 返回 false 时使用右侧路径（?: 在 PHP 5.3+ 可用）
$flag_file = realpath(__DIR__ . '/../PPQSQL.PPQSQL');
$flag_file = $flag_file ? $flag_file : (__DIR__ . '/../PPQSQL.PPQSQL');

if (!is_dir(dirname($flag_file))) { mkdir(dirname($flag_file), 0777, true); }
if (file_put_contents($flag_file, date('Ymd')) === false) {
    file_put_contents($log_file, "[错误] 无法写入标志文件：$flag_file\n", FILE_APPEND);
} else {
    file_put_contents($log_file, "[完成] 已更新标志文件日期为 " . date('Ymd') . "\n", FILE_APPEND);
}

// ---------- 9. 释放文件锁 ----------
flock($fp, LOCK_UN);
fclose($fp);

file_put_contents($log_file, "[完成] 更新完成于 " . date('H:i:s') . "\n", FILE_APPEND);
exit;
?>
