Capacitor 4中Apple Sign In对接PHP接口出现500错误求助
Capacitor 4中Apple Sign In接口500错误排查
问题现象
- Apple ID密码弹窗可正常弹出,但调用PHP接口时出现卡顿
- 其他PHP接口均可正常工作,仅Apple Sign In接口返回500错误
后端返回500错误详情
Failed to load resource: the server responded with a status of 500 () ERROR HttpErrorResponse error: null headers: HttpHeaders lazyInit: function() arguments: TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context. caller: TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context. length: 0 name: "" Function Prototype lazyUpdate: null normalizedNames: Map {} (0) HttpHeaders Prototype message: "Http failure response for https://project.com/project_api/api/sign_in_with_apple: 500 OK" name: "HttpErrorResponse" ok: false status: 500 statusText: "OK" url: "https://project.com/project_api/api/sign_in_with_apple"
网络请求详情
Summary URL: https://project.com/project_api/api/sign_in_with_apple Status: 500 Source: Network Address: 185.35.33.55:553 Initiator: zone.js:3454 Request :method: POST :scheme: https :authority: project.com :path: /project_api/api/sign_in_with_apple Accept: application/json, text/plain, */* Content-Type: application/x-www-form-urlencoded Origin: capacitor://localhost Accept-Encoding: gzip, deflate, br Host: rovespier.com User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 16_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Content-Length: 1074 Accept-Language: el-GR,el;q=0.9 Connection: keep-alive Response :status: 500 Content-Type: text/html; charset=UTF-8 Pragma: no-cache Set-Cookie: PHPSESSID=9ca0e5311a0376ade70056525d9a765f; path=/ X-Content-Type-Options: nosniff, nosniff Access-Control-Allow-Origin: * Date: Mon, 30 Jan 2023 09:20:35 GMT X-XSS-Protection: 1; mode=block Content-Length: 0 Cache-Control: no-store, no-cache, must-revalidate Expires: Thu, 19 Nov 1981 08:52:00 GMT Server: nginx Request Data MIME Type: application/x-www-form-urlencoded login_data[response][identityToken]: eyJraWQiOiJmaDZCczhDIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoiY29tLnJvdmVzcGllci5tb2JpbGUiLCJleHAiOjE2NzUxNTY4MzQsImlhdCI6MTY3NTA3MDQzNCwic3ViIjoiMDAwNjc0LjZiMDUzYzSI6Im5vbmNlIiwiY19oYXNoIjoiZUY2WEdNRDhtYzViT3o0U0JVQnF5QSIsImVtYWlsIjoic2ltb25pb2FubmlkZXNAaG90bWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJhdXRoX3RpbWUiOjE2NzUwNzA0MzQsIm5vbmNlX3N1cHBvcnRlZCI6dHJ1ZX0.bvXBlch8O-H690PsIFNZpJqauCcdozuZggt0I1nGY0PHQ075OSHKYlUXvsY_aOTIEzxyHnrygOAtuk_OkzqmwPplQGfOKZPyGFWBo2xHPChysVX-VmRk81s3Qkza76Ty-tmVymcdTQ-59Eumq0bn7BH_X8mWEdr6NLGP5JOw7kjAGKBVJbHZ9fgUd72KDgFWiHOF-brEkXABL4IgeDqOhAuDP30bAyRFbtDWme5GPcnZU3t13qLDLEDPSK1jrl3X-OU8d2WOALBrnaJhmPw8z7H20Nx61vuio7KoCRPqD_3HT_Plga7dHT43DkQ login_data[response][authorizationCode]: cf7d3de8d4c7f4277a128d2453423235.0.swxu.KmQXI352ayadDUh3cBGCjA login_data[response][user]: 000674.6b053c49f8cc45b1bce5623f23343.1836 app_version: 1.0.1 timezone_offset: 120
前端代码
login.ts
async checkApple(login_data) { const loader = await this.loadingCtrl.create({ spinner: 'bubbles', }); loader.present(); this.userData.appleLogin(login_data).pipe( map((data: any) => { loader.dismiss(); if (data.success) { this.userData.setSession('HAS_LOGGED_IN', true); this.userData.setUserData(data.userData); this.router.navigate(["app/tablinks/home"]); } else { } }, err => { loader.dismiss(); }) ).subscribe() } loginApple() { let options: SignInWithAppleOptions = { clientId: 'com.projectr.mobile', redirectURI: 'https://www.project.com/', scopes: 'email name', state: '12345', nonce: 'nonce', }; SignInWithApple.authorize(options) .then((result: SignInWithAppleResponse) => { console.log(result); this.checkApple(result); }) .catch(error => { // Handle error }); (<any>window).cordova.plugins.SignInWithApple.signin( { requestedScopes: [0, 1] }, (succ) => { console.log('APPLE', JSON.stringify(succ)); this.checkApple(succ); }, (err) => { console.error(err) console.log(JSON.stringify(err)) } ) }
user-data.ts
appleLogin(login_data) { let device = {}; if (this.platform.is('cordova')) { /*device = { platform: this.device.platform, uuid: this.device.uuid, cordova: this.device.cordova, model: this.device.model, manufacturer: this.device.manufacturer, version: this.device.version, };*/ } var timezone_offset = new Date().getTimezoneOffset(); timezone_offset = timezone_offset == 0 ? 0 : -timezone_offset; const url = this.appData.getApiUrl() + 'sign_in_with_apple'; const data = this.jsonToURLEncoded({ login_data: login_data, device: device, app_version: this.appData.APP_VERSION, timezone_offset: timezone_offset }); return this.http.post(url, data, { headers: this.options }); };
后端PHP代码
function sign_in_with_apple() { $request = \Slim\Slim::getInstance()->request(); $data = json_decode($request->getBody()); $response['success'] = false; $loginData = $_POST['login_data']; $identityToken = $loginData['identityToken']; $clientUser = $loginData['user']; $clientAuthorizationCode = $loginData['authorizationCode']; $appleSignInPayload = ASDecoder::getAppleSignInPayload($identityToken); $email = $appleSignInPayload->getEmail(); $user = $appleSignInPayload->getUser(); $isValid = $appleSignInPayload->verifyUser($clientUser); if ($isValid) { try { $username = strstr($email, '@', true); $db = getDB(); $sql = "SELECT uid,notification_created,username,name,profile_pic,tour,email, api_signature,first_name,last_name, artisticBehaviour,location,bio,friend_count FROM users WHERE (username=:username or email=:email) AND status='1' "; $stmt = $db->prepare($sql); $stmt->bindParam("username", $username, PDO::PARAM_STR); $stmt->bindParam("email", $email, PDO::PARAM_STR); $stmt->execute(); $mainCount = $stmt->rowCount(); $userData = $stmt->fetch(PDO::FETCH_OBJ); $created = time(); if ($mainCount == 0) { $api_signature = md5(time() . $username . rand(1, 1000)); $status = '1'; if (SMTP_CONNECTION > 0) { $status = '0'; } $email_active_code = $email . time(); $sql1 = "INSERT INTO users(username,password,email,last_login,email_activation,status, api_signature)VALUES(:username,:password,:email,:created,:email_activation,:status,:api_signature)"; $stmt1 = $db->prepare($sql1); $stmt1->bindParam("username", $username, PDO::PARAM_STR); $password = hash('sha256', $signupData['password']); $stmt1->bindParam("password", $password, PDO::PARAM_STR); $stmt1->bindParam("email", $email, PDO::PARAM_STR); $stmt1->bindParam("created", $created); $stmt1->bindParam("status", $status); $stmt1->bindParam("api_signature", $api_signature); $stmt1->bindParam("email_activation", $email_active_code); $stmt1->execute(); $stmt2 = $db->prepare("SELECT uid,notification_created,username,name,first_name,last_name, profile_pic,tour,email,friend_count FROM users WHERE username=:username"); $stmt2->bindParam("username", $data->username, PDO::PARAM_STR); $stmt2->execute(); $userData = $stmt2->fetchAll(PDO::FETCH_OBJ); $uid = $userData[0]->uid; $stmt3->bindParam("created", $time, PDO::PARAM_STR); $me = 'me'; $stmt3->bindParam("me", $me, PDO::PARAM_STR); $stmt3->execute(); $userData = internalUserDetails($email); $response['success'] = true; $response['userData'] = $userData; } else { $photos_query = $db->query("SELECT id FROM user_uploads WHERE uid_fk='$uid' and group_id_fk='0'"); $photos_count = $photos_query->rowCount(); $updates_query = $db->query("SELECT msg_id FROM messages WHERE uid_fk='$uid' and group_id_fk='0'"); $updates_count = $updates_query->rowCount(); $time = time(); $updates_query = $db->query("UPDATE users SET last_login='$time',photos_count='$photos_count',updates_count='$updates_count' WHERE uid='$uid'"); $userData->profile_pic = profilePic($userData->profile_pic); $userData->configurations = configurations(); $response['success'] = true; $response['userData'] = $userData; } } catch (PDOException $e) { echo '{"error":{"text35":' . $e->getMessage() . '}}'; } } else { $response['error'] = 'Please allow access to your email'; } echo json_encode($response); }
错误原因分析
- 参数路径不匹配:前端传递的
login_data嵌套在response对象中,但后端直接取$loginData['identityToken'],导致Undefined索引错误 - 未定义变量引用:
- 注册分支中使用未定义的
$signupData['password'] - 未初始化
$stmt3就调用bindParam和execute - 登录分支中使用未赋值的
$uid
- 注册分支中使用未定义的
- SQL注入风险+变量未定义:登录分支直接用
$uid拼接SQL,且$uid仅在注册分支赋值,登录时会报错 - 错误处理不完整:仅捕获PDOException,其他致命错误(如Undefined变量)无法被捕获,直接返回500;错误输出的JSON格式易被破坏
解决方法
1. 修正参数获取路径
$loginData = $_POST['login_data']; $identityToken = $loginData['response']['identityToken']; $clientUser = $loginData['response']['user']; $clientAuthorizationCode = $loginData['response']['authorizationCode'];
2. 处理未定义变量
- 注册分支中替换未定义的密码生成逻辑:
$password = hash('sha256', uniqid()); // 生成随机密码 - 删除未初始化的
$stmt3相关代码,或补充完整其初始化逻辑 - 登录分支中从
$userData获取uid:$uid = $userData->uid;
3. 修复SQL注入问题
将登录分支的查询改为预处理语句:
// 照片数量查询 $photos_stmt = $db->prepare("SELECT id FROM user_uploads WHERE uid_fk=:uid AND group_id_fk='0'"); $photos_stmt->bindParam(":uid", $uid, PDO::PARAM_INT); $photos_stmt->execute(); $photos_count = $photos_stmt->rowCount(); // 更新数量查询 $updates_stmt = $db->prepare("SELECT msg_id FROM messages WHERE uid_fk=:uid AND group_id_fk='0'"); $updates_stmt->bindParam(":uid", $uid, PDO::PARAM_INT); $updates_stmt->execute(); $updates_count = $updates_stmt->rowCount(); // 更新用户登录信息 $update_stmt = $db->prepare("UPDATE users SET last_login=:time, photos_count=:photos_count, updates_count=:updates_count WHERE uid=:uid"); $update_stmt->bindParam(":time", $time, PDO::PARAM_INT); $update_stmt->bindParam(":photos_count", $photos_count, PDO::PARAM_INT); $update_stmt->bindParam(":updates_count", $updates_count, PDO::PARAM_INT); $update_stmt->bindParam(":uid", $uid, PDO::PARAM_INT); $update_stmt->execute();
4. 完善错误处理
catch (PDOException $e) { $response['success'] = false; $response['error'] = $e->getMessage(); echo json_encode($response); exit; } // 开启PHP错误日志,方便排查致命错误 // php.ini中设置:log_errors = On; error_log = /path/to/error.log
5. 清理前端冗余代码
loginApple函数同时调用了Capacitor和Cordova的Apple登录接口,保留其中一种即可,避免重复请求冲突。
内容的提问来源于stack exchange,提问作者SimonIoa
相关产品推荐
相关产品推荐

