'null', 'sms_number_limit_ch' => true]; } /** * Phone-number validation follows the selected domestic/international mode. */ public static function is_phonenumber(string $phone, ?bool $domestic_only = null): bool { if ($domestic_only === null) { $config = self::get_instance()->get_provider_config(); $domestic_only = !empty($config['sms_number_limit_ch']); } if ($domestic_only) { return (bool) preg_match('/^1[3-9]\d{9}$/', $phone); } return (bool) preg_match('/^(?:\d{5,}|\+\d{6,}|\+?\d{2,}[-\s]\d{2,}[0-9\-\s]{0,15})$/', $phone); } /** * Send a six-digit verification code. The caller stores it after success. * * @return array{success: bool, message: string, remaining_time?: int} */ public function send_code(string $phone, string $code): array { $config = $this->get_provider_config(); $sdk = sanitize_key((string) ($config['sms_sdk'] ?? 'null')); if ($sdk === '' || $sdk === 'null') { return ['success' => false, 'message' => __('短信接口未启用', 'aksrt')]; } if (!self::is_phonenumber($phone, !empty($config['sms_number_limit_ch']))) { return ['success' => false, 'message' => __('手机号码格式有误', 'aksrt')]; } $provider = SMSProviderFactory::get($sdk); if ($provider === null) { return ['success' => false, 'message' => __('暂无短信接口,请检查短信服务商设置', 'aksrt')]; } $missing = $provider->validate_config($config); if ($missing) { return ['success' => false, 'message' => sprintf(__('短信接口缺少配置:%s', 'aksrt'), implode(', ', $missing))]; } // [防刷机制]验证码发送限制(后台「扩展&增强 → 网站安全」)。 $limit = \AKSRT\Extensions\SendLimit::check($phone); if (empty($limit['ok'])) { return [ 'success' => false, 'message' => (string) $limit['message'], 'remaining_time' => (int) $limit['remaining'], ]; } $result = $provider->send_code($phone, $code, $config); if (empty($result['success'])) { return ['success' => false, 'message' => (string) ($result['message'] ?? __('验证码发送失败,请稍后重试', 'aksrt'))]; } $cooldown = \AKSRT\Extensions\SendLimit::record($phone); return [ 'success' => true, 'message' => __('验证码短信已发送', 'aksrt'), 'remaining_time' => $cooldown > 0 ? $cooldown : 60, ]; } public function get_provider_status(): array { $config = $this->get_provider_config(); $key = sanitize_key((string) ($config['sms_sdk'] ?? 'null')); $enabled = $key !== '' && $key !== 'null'; $provider = SMSProviderFactory::get($key); $status = [ 'enabled' => $enabled, 'provider' => $enabled ? $key : 'none', 'configured' => false, 'available' => false, 'verified' => false, 'transport' => '', 'missing_fields' => [], ]; if ($provider !== null) { $status = array_merge($status, $provider->get_status($config)); } return $status; } /** Send the reference theme's fixed 888888 test message without storing a code. */ public function test_send(string $phone): array { $config = $this->get_provider_config(); $sdk = sanitize_key((string) ($config['sms_sdk'] ?? 'null')); if ($sdk === '' || $sdk === 'null') { return ['success' => false, 'message' => __('短信接口未启用', 'aksrt')]; } if (!self::is_phonenumber($phone, !empty($config['sms_number_limit_ch']))) { return ['success' => false, 'message' => __('手机号码格式有误', 'aksrt')]; } $provider = SMSProviderFactory::get($sdk); if ($provider === null) { return ['success' => false, 'message' => __('暂无短信接口,请检查短信服务商设置', 'aksrt')]; } $missing = $provider->validate_config($config); if ($missing) { return ['success' => false, 'message' => sprintf(__('短信接口缺少配置:%s', 'aksrt'), implode(', ', $missing))]; } return $provider->send_code($phone, '888888', $config); } }