$a) { $t = $a; $a = $b; $b = $t; } return ['题目: ' . $a . ' 减 ' . $b . ' 等于多少?', [(string)($a - $b)]]; } if ($op === 3) { $a = random_int(2, 9); $b = random_int(2, 9); return ['题目: ' . $a . ' 乘以 ' . $b . ' 等于多少?', [(string)($a * $b)]]; } // 先乘后加 $a = random_int(1, 5); $b = random_int(2, 6); $c = random_int(2, 6); return ['题目: ' . $a . ' 加 ' . $b . ' 乘 ' . $c . ' 等于多少?(先乘后加)', [(string)($a + $b * $c)]]; } /** 归一化答案:全角转半角、去空白与常见标点、转小写 */ function fb_captcha_norm($s) { $s = (string)$s; if (function_exists('mb_convert_kana')) { $s = mb_convert_kana($s, 'as', 'UTF-8'); // 全角字母/数字/空格 -> 半角 } $s = str_replace( ['?', '?', '。', '.', '.', ',', ',', '!', '!', '、', ':', ':', ';', ';', '"', "'", '“', '”', '‘', '’', ' ', ' ', "\r", "\n", "\t"], '', $s ); if (function_exists('mb_strtolower')) { $s = mb_strtolower($s, 'UTF-8'); } else { $s = strtolower($s); } return $s; } /** 生成新的验证题,写入 Session,返回题面文本 */ function fb_captcha_new() { if (random_int(1, 100) <= 65) { list($q, $answers) = fb_captcha_arith(); } else { $bank = fb_captcha_bank(); list($q, $answers) = $bank[array_rand($bank)]; } $_SESSION['fb_cap'] = [ 'q' => $q, 'answers'=> $answers, 'ts' => time(), 'tries' => 0, ]; return $q; } /** 取当前题目(不存在则新建) */ function fb_captcha_question() { if (empty($_SESSION['fb_cap']['q']) || !empty($_SESSION['fb_cap']['used'])) { return fb_captcha_new(); } // 超过 30 分钟重新出题 if (time() - (int)$_SESSION['fb_cap']['ts'] > 1800) { return fb_captcha_new(); } return (string)$_SESSION['fb_cap']['q']; } /** 校验用户答案;一次性使用,答错累计,超过 5 次作废需换题 */ function fb_captcha_check($input) { if (empty($_SESSION['fb_cap']['answers'])) { return false; } $cap = $_SESSION['fb_cap']; if (time() - (int)$cap['ts'] > 1800) { unset($_SESSION['fb_cap']); return false; } $n = fb_captcha_norm($input); $ok = false; if ($n !== '') { foreach ((array)$cap['answers'] as $a) { $an = fb_captcha_norm($a); if ($an === '') { continue; } if ($n === $an) { $ok = true; break; } if (is_numeric($n) && is_numeric($an) && (float)$n === (float)$an) { $ok = true; break; } } } $_SESSION['fb_cap']['tries'] = (int)$cap['tries'] + 1; if ($ok) { unset($_SESSION['fb_cap']); // 用后即焚 return true; } if ($_SESSION['fb_cap']['tries'] >= 5) { unset($_SESSION['fb_cap']); // 作废,下次自动换题 } return false; }