<?php

declare(strict_types=1);

/**
 * 前台搜尋：機器人／SQL 探測字判斷（不寫入紀錄；命中時應跳過 LIKE 查詢）。
 * 實際 SQL 仍須全程 PDO 參數綁定；此模組僅降低無效查詢與掃描噪音。
 */

function fate_search_is_robot_probe(?string $keyword): bool
{
    if ($keyword === null) {
        return true;
    }
    $k = trim($keyword);
    if ($k === '') {
        return true;
    }
    if (mb_strlen($k, 'UTF-8') > 120) {
        return true;
    }
    if (preg_match('/[\x00-\x08\x0B\x0C\x0E-\x1F]/u', $k)) {
        return true;
    }
    $sqlProbe = '/(\bunion\b|\bselect\b|\binsert\b|\bupdate\b|\bdelete\b|\bdrop\b|\btruncate\b|\balter\b|\bexec\b|\bexecute\b|\bscript\b|\bwaitfor\b|\bdelay\b|\bbenchmark\b|\bsleep\s*\(|\bpg_sleep\s*\(|\bsysdate\s*\(|\bnow\s*\(|information_schema|xp_cmdshell|sp_executesql|sysobjects|@@version|@@\w+|\bchar\s*\(|concat\s*\(|0x[0-9a-f]{10,}|\bnull\b\s*,\s*null|;--|\/\*|\*\/)/iu';
    if (preg_match($sqlProbe, $k)) {
        return true;
    }
    if (preg_match("/''|'\s+or\s+|\"\s+or\s+|1\s*=\s*1|1\s*=\s*2|--\s*$/i", $k)) {
        return true;
    }
    if (preg_match('/-?\d+\s+(?:OR|AND)\s+/i', $k)) {
        return true;
    }
    if (preg_match('/\bif\s*\([^)]*,\s*(?:sleep|benchmark|pg_sleep)\s*\(/i', $k)) {
        return true;
    }
    if (preg_match('/\b\d{3}-\d{2}-\d{4}\b/', $k)) {
        return true;
    }
    if (preg_match('#https?://#i', $k)) {
        return true;
    }

    return false;
}

/**
 * 前台公開搜尋 q：長度限制；探測字視為空字串（不觸發搜尋 SQL）。
 */
function fate_search_normalize_public_query(string $q, int $maxLen = 120): string
{
    $q = trim($q);
    if ($q === '') {
        return '';
    }
    if (strlen($q) > $maxLen) {
        $q = substr($q, 0, $maxLen);
    }
    if (fate_search_is_robot_probe($q)) {
        return '';
    }

    return $q;
}
