diff --git a/app/Http/Controllers/Mobile/CommonController.php b/app/Http/Controllers/Mobile/CommonController.php index d44f0a9..2b5f9c7 100644 --- a/app/Http/Controllers/Mobile/CommonController.php +++ b/app/Http/Controllers/Mobile/CommonController.php @@ -27,4 +27,116 @@ class CommonController extends Controller return $this->guard()->id(); } + /** + * @OA\Post( + * path="/api/mobile/validate-idcard", + * summary="验证身份证号码", + * description="验证身份证号码是否合法正规", + * tags={"移动端-通用接口"}, + * @OA\RequestBody( + * required=true, + * @OA\JsonContent( + * @OA\Property(property="idcard", type="string", description="身份证号码", example="110101199003071234") + * ) + * ), + * @OA\Response( + * response=200, + * description="验证成功", + * @OA\JsonContent( + * @OA\Property(property="code", type="integer", example=0), + * @OA\Property(property="message", type="string", example="success"), + * @OA\Property(property="data", type="boolean", description="身份证号码是否有效", example=true) + * ) + * ), + * @OA\Response( + * response=422, + * description="参数错误", + * @OA\JsonContent( + * @OA\Property(property="code", type="integer", example=1001), + * @OA\Property(property="message", type="string", example="身份证号码必填") + * ) + * ) + * ) + */ + public function validateIdcard() + { + $all = request()->all(); + $messages = [ + 'idcard.required' => '身份证号码必填' + ]; + $validator = Validator::make($all, [ + 'idcard' => 'required' + ], $messages); + + if ($validator->fails()) { + return response()->json([ + 'code' => ResponseCode::ERROR_PARAMETER, + 'message' => implode(',', $validator->errors()->all()), + 'data' => null + ], 422); + } + + $idcard = $all['idcard']; + $isValid = $this->isValidIdcard($idcard); + + return $this->success($isValid); + } + + /** + * 验证身份证号码是否有效 + */ + private function isValidIdcard($idcard) + { + // 基础格式验证 + if (!preg_match('/^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/', $idcard)) { + return false; + } + + // 长度验证 + if (strlen($idcard) != 18) { + return false; + } + + // 转化为大写 + $idcard = strtoupper($idcard); + + // 加权因子 + $wi = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]; + $ai = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']; + + // 校验码验证 + $sigma = 0; + for ($i = 0; $i < 17; $i++) { + $b = (int)$idcard[$i]; + $w = $wi[$i]; + $sigma += $b * $w; + } + + $sidcard = $sigma % 11; + $check_idcard = $ai[$sidcard]; + + if ($idcard[17] != $check_idcard) { + return false; + } + + // 日期验证 + $year = substr($idcard, 6, 4); + $month = substr($idcard, 10, 2); + $day = substr($idcard, 12, 2); + + if (!checkdate($month, $day, $year)) { + return false; + } + + // 年龄合理性验证 + $birthDate = $year . '-' . $month . '-' . $day; + $age = \Carbon\Carbon::parse($birthDate)->age; + + if ($age < 0 || $age > 150) { + return false; + } + + return true; + } + } diff --git a/routes/api.php b/routes/api.php index 20e4575..b5c1783 100644 --- a/routes/api.php +++ b/routes/api.php @@ -89,6 +89,9 @@ Route::group(["namespace" => "Admin", "prefix" => "admin", "middleware" => "sanc // 前台 Route::get('mobile/user/login', [\App\Http\Controllers\Mobile\UserController::class, 'login']); Route::get('mobile/user/config', [\App\Http\Controllers\Mobile\UserController::class, 'config']); +// 身份证验证接口(无需认证) +Route::post('mobile/validate-idcard', [\App\Http\Controllers\Mobile\CommonController::class, 'validateIdcard']); + Route::group(["namespace" => "Mobile", "prefix" => "mobile", "middleware" => "sanctum.jwt:mobile"], function () { Route::post('user/save', [\App\Http\Controllers\Mobile\UserController::class, 'save']); Route::get('user/mobile', [\App\Http\Controllers\Mobile\UserController::class, 'mobile']);