如何在PHP中检测Firebase Auth已存在邮箱并避免致命错误
我是编程新手,现在要实现用户注册时,同时在Firebase Authentication创建账号并把用户详情存入实时数据库。现有代码能完成正常注册时的双端数据添加,但用户注册已存在的邮箱时会触发致命错误,附上代码和错误栈,请求解决。
<?php session_start(); include('databaseconfig.php'); //this is for add button if (isset($_POST['add'])) { //constraint for password and confirm password (I'm not using firebase authentication in this one) if($password = $_POST['password'] == $cpassword = $_POST['confirmPassword']){ $fName = $_POST['givenName']; $lName = $_POST['lastName']; $bDay = $_POST['birthDate']; $gradeLevel = $_POST['gradeLevel']; $school = $_POST['school']; $email = $_POST['email']; $password = $_POST['password']; $question = $_POST['securityQuestion']; $answer = $_POST['answer']; $userProperties = [ 'email' => $email, 'emailVerified' => false, 'password' => $password, ]; $createdUser = $auth->createUser($userProperties); if ($createdUser) { $postData = [ 'first_name' => $fName, 'last_name' => $lName, 'bithday' => $bDay, 'grade_level' => $gradeLevel, 'school' => $school, 'email_address' => $email, 'password' => $password, 'security_question' => $question, 'answer' => $answer ]; $reference_table = "Profiles"; $postRef = $database->getReference($reference_table)->push($postData); if($postRef){ ?> <script> alert("User Added Successfully"); </script> <?php header('Location:userlist.php'); } else{ ?> <script> alert("User not Added"); </script> <?php } exit(); } else { ?> <script> alert("Email already exists."); </script> <?php } } } ?>
当用户尝试注册Firebase Authentication中已存在的邮箱时,会出现如下致命错误:
Fatal error: Uncaught GuzzleHttp\Exception\ClientException: Client error:
POST https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUserresulted in a400 Bad Requestresponse: { "error": { "code": 400, "message": "EMAIL_EXISTS", "errors": [ { "message": "EMAIL_EXISTS" (truncated...) in C:\xampp\htdocs\maintenanceadmin\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php:113 Stack trace: #0 C:\xampp\htdocs\maintenanceadmin\vendor\guzzlehttp\guzzle\src\Middleware.php(69): GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Psr7\Request), Object(GuzzleHttp\Psr7\Response), NULL, Array, NULL) #1 C:\xampp\htdocs\maintenanceadmin\vendor\guzzlehttp\promises\src\Promise.php(204): GuzzleHttp\Middleware::GuzzleHttp{closure}(Object(GuzzleHttp\Psr7\Response)) #2 C:\xampp\htdocs\maintenanceadmin\vendor\guzzlehttp\promises\src\Promise.php(153): GuzzleHttp\Promise\Promise::callHandler(1, Object(GuzzleHttp\Psr7\Response), NULL) #3 C:\xampp\htdocs\maintenanceadmin\vendor\guzzlehttp\promises\src\TaskQueue.php(48): GuzzleHttp\Promise\Promise::GuzzleHttp\Promise{closure}() #4 C:\xampp\htdocs\maintenanceadmin\vendor\guzzlehttp\promises\src\Promise.php(248): GuzzleHttp\Promise\TaskQueue->run(true) #5 C:\xampp\htdocs\maintenanceadmin\vendor\guzzlehttp\promises\src\Promise.php(224): GuzzleHttp\Promise\Promise->invokeWaitFn() #6 C:\xampp\htdocs\maintenanceadmin\vendor\guzzlehttp\promises\src\Promise.php(269): GuzzleHttp\Promise\Promise->waitIfPending() #7 C:\xampp\htdocs\maintenanceadmin\vendor\guzzlehttp\promises\src\Promise.php(226): GuzzleHttp\Promise\Promise->invokeWaitList() #8 C:\xampp\htdocs\maintenanceadmin\vendor\guzzlehttp\promises\src\Promise.php(62): GuzzleHttp\Promise\Promise->waitIfPending() #9 C:\xampp\htdocs\maintenanceadmin\vendor\guzzlehttp\guzzle\src\Client.php(187): GuzzleHttp\Promise\Promise->wait() #10 C:\xampp\htdocs\maintenanceadmin\vendor\kreait\firebase-php\src\Firebase\Auth\ApiClient.php(227): GuzzleHttp\Client->request('POST', 'signupNewUser', Array) #11 C:\xampp\htdocs\maintenanceadmin\vendor\kreait\firebase-php\src\Firebase\Auth\ApiClient.php(45): Kreait\Firebase\Auth\ApiClient->requestApi('signupNewUser', Array) #12 C:\xampp\htdocs\maintenanceadmin\vendor\kreait\firebase-php\src\Firebase\Auth.php(143): Kreait\Firebase\Auth\ApiClient->createUser(Object(Kreait\Firebase\Request\CreateUser)) #13 C:\xampp\htdocs\maintenanceadmin\addUser.php(29): Kreait\Firebase\Auth->createUser(Array) #14 {main} Next Kreait\Firebase\Exception\Auth\EmailExists: The email address is already in use by another account. in C:\xampp\htdocs\maintenanceadmin\vendor\kreait\firebase-php\src\Firebase\Exception\AuthApiExceptionConverter.php:73 Stack trace: #0 C:\xampp\htdocs\maintenanceadmin\vendor\kreait\firebase-php\src\Firebase\Exception\AuthApiExceptionConverter.php(47): Kreait\Firebase\Exception\AuthApiExceptionConverter->convertGuzzleRequestException(Object(GuzzleHttp\Exception\ClientException)) #1 C:\xampp\htdocs\maintenanceadmin\vendor\kreait\firebase-php\src\Firebase\Auth\ApiClient.php(229): Kreait\Firebase\Exception\AuthApiExceptionConverter->convertException(Object(GuzzleHttp\Exception\ClientException)) #2 C:\xampp\htdocs\maintenanceadmin\vendor\kreait\firebase-php\src\Firebase\Auth\ApiClient.php(45): Kreait\Firebase\Auth\ApiClient->requestApi('signupNewUser', Array) #3 C:\xampp\htdocs\maintenanceadmin\vendor\kreait\firebase-php\src\Firebase\Auth.php(143): Kreait\Firebase\Auth\ApiClient->createUser(Object(Kreait\Firebase\Request\CreateUser)) #4 C:\xampp\htdocs\maintenanceadmin\addUser.php(29): Kreait\Firebase\Auth->createUser(Array) #5 {main} thrown in C:\xampp\htdocs\maintenanceadmin\vendor\kreait\firebase-php\src\Firebase\Exception\AuthApiExceptionConverter.php on line 73
核心问题是$auth->createUser()在邮箱已存在时会抛出异常,而非返回false,所以原代码的if ($createdUser)分支无法捕获该情况,直接触发致命错误。同时原代码还存在密码确认判断的逻辑错误,一并修复:
修复后的完整代码
<?php session_start(); include('databaseconfig.php'); //this is for add button if (isset($_POST['add'])) { // 修复密码确认判断的逻辑错误 if($_POST['password'] === $_POST['confirmPassword']){ $fName = $_POST['givenName']; $lName = $_POST['lastName']; $bDay = $_POST['birthDate']; $gradeLevel = $_POST['gradeLevel']; $school = $_POST['school']; $email = $_POST['email']; $password = $_POST['password']; $question = $_POST['securityQuestion']; $answer = $_POST['answer']; $userProperties = [ 'email' => $email, 'emailVerified' => false, 'password' => $password, ]; try { $createdUser = $auth->createUser($userProperties); // 创建成功后写入实时数据库 $postData = [ 'first_name' => $fName, 'last_name' => $lName, 'bithday' => $bDay, 'grade_level' => $gradeLevel, 'school' => $school, 'email_address' => $email, 'password' => $password, 'security_question' => $question, 'answer' => $answer ]; $reference_table = "Profiles"; $postRef = $database->getReference($reference_table)->push($postData); if($postRef){ ?> <script> alert("User Added Successfully"); </script> <?php header('Location:userlist.php'); } else { ?> <script> alert("User not Added"); </script> <?php } } catch (\Kreait\Firebase\Exception\Auth\EmailExists $e) { // 精准捕获邮箱已存在的异常 ?> <script> alert("Email already exists."); </script> <?php } catch (\Exception $e) { // 捕获其他未知异常,方便调试 ?> <script> alert("An error occurred: <?php echo addslashes($e->getMessage()); ?>"); </script> <?php } exit(); } else { // 密码不匹配的提示 ?> <script> alert("Passwords do not match."); </script> <?php } } ?>
关键修复点
- 异常捕获:用
try-catch块包裹$auth->createUser(),精准捕获EmailExists异常处理重复邮箱场景,同时用通用Exception捕获其他意外错误,避免致命错误。 - 密码确认逻辑:将原错误的赋值+判断语句
$password = $_POST['password'] == $cpassword = $_POST['confirmPassword']改为直接判断$_POST['password'] === $_POST['confirmPassword'],避免逻辑错误。 - XSS防护:输出异常信息时用
addslashes()转义特殊字符,防止跨站脚本攻击。
内容的提问来源于stack exchange,提问作者freyja

