← 返回列表 baidu_push.php 3.6 KB · 2026-11-06 10:19
<?php
// ===== 源码查看保护 =====
// 本文件同时用于服务器运行(cron)和在线查看源码。
// 通过 Web 直接访问时,仅以纯文本输出自身源码,不执行任何业务逻辑。
// 注意:gk_auto.php 若被 Web 执行会真的触发发文,这层保护是必需的。
if (PHP_SAPI !== 'cli' && basename($_SERVER['SCRIPT_FILENAME'] ?? '') === basename(__FILE__)) {
    header('Content-Type: text/plain; charset=utf-8');
    echo file_get_contents(__FILE__);
    exit;
}
/**
 * baidu_push.php — 新文章发布后立即推送到百度
 *
 * 关键约束(实测结论,2026-10-31 复核):
 *   1. site 参数【必须只写纯域名】,带 https:// 会返回 site init fail。
 *      写接口地址时容易直接把后台给的 http://data.zz.baidu.com/urls?site=https://xxx
 *      整条复制过来,那个 site 值是错的,必须去掉协议。
 *   2. site 值必须是「百度搜索资源平台里验证过的站点」,且
 *      【geekfei.cn 与 www.geekfei.cn 是两个不同站点,配额各自独立】。
 *      实测 site=geekfei.cn 推 https://www.geekfei.cn/xxx 会返回
 *      {"success":0,"not_same_site":[...]},必须让 URL 的 host 与 site 一致。
 *   3. 配额按站点独立:每站约 10 条/天,0 点重置。over quota 次日再推。
 *   4. 只有返回含 success 才算成功。
 */

/**
 * 推送单个 URL 到百度
 * @return array [ok(bool), msg(string)]
 */
function baidu_push_url($site, $token, $url, $timeout = 15) {
    // 参数硬校验,避免把 https:// 带进去白跑一次
    if (strpos($site, '://') !== false) {
        return [false, 'site 参数不能带协议(应为纯域名)'];
    }

    $api = 'http://data.zz.baidu.com/urls?' . http_build_query([
        'site'  => $site,
        'token' => $token,
    ]);

    $body = $url . "\n";   // body 必须 text/plain,一行一个 URL

    $ch = curl_init($api);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => $body,
        CURLOPT_TIMEOUT        => $timeout,
        CURLOPT_CONNECTTIMEOUT => 8,
        CURLOPT_HTTPHEADER     => ['Content-Type: text/plain'],
    ]);
    $resp = curl_exec($ch);
    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $err  = curl_error($ch);
    curl_close($ch);

    if ($resp === false) {
        return [false, "网络错误: $err"];
    }

    $j = json_decode($resp, true);
    if (!is_array($j)) {
        return [false, "返回非 JSON: " . mb_substr($resp, 0, 150)];
    }

    // 成功:{"success":1,"remain":8,"not_same_site":[]}
    if (!empty($j['success'])) {
        $remain = isset($j['remain']) ? $j['remain'] : '?';
        return [true, "推送成功,本日剩余配额 {$remain}"];
    }

    // 配额用尽:次日 0 点重置,不算错误
    if (strpos($resp, 'over quota') !== false) {
        return [false, '今日配额已用尽(次日自动重试)'];
    }

    $msg = $j['message'] ?? mb_substr($resp, 0, 120);
    return [false, "HTTP {$code} 失败: {$msg}"];
}

/**
 * 命令行自测:php baidu_push.php <site> <token> <url>
 * ⚠️ 必须靠 BASENAME 判断:本文件会被 gk_auto.php require_once,
 *    用 isset($argv[1],$argv[2],$argv[3]) 会在被载入时误触发并 exit(),
 *    直接杀死主程序。
 */
if (PHP_SAPI === 'cli' && basename($_SERVER['SCRIPT_FILENAME'] ?? '') === 'baidu_push.php'
    && isset($argv[1], $argv[2], $argv[3])) {
    list($ok, $msg) = baidu_push_url($argv[1], $argv[2], $argv[3]);
    echo ($ok ? "✓ " : "✗ ") . $msg . "\n";
    exit($ok ? 0 : 1);
}