iOS Swift+MySQL登录系统报错「数据格式错误」求助排查
Hey there! Let's break down why you're hitting that "The data couldn't be read because it is in the incorrect format" error and fix it step by step.
First off, your PHP script only runs its login logic if loginbutton exists in the POST request (thanks to if(isset($_POST['loginbutton']))), but neither of your Swift requests sends this parameter. That means when your app calls the endpoint, PHP returns empty data—which Swift can't parse as valid JSON, hence the error.
On top of that:
- Your Swift
formDataRequestsends parameters namedcEmailandcPassword, but your PHP is looking for$_POST["email"]and$_POST["password"]—the names don't match! - Your
jsonRequestsends data as JSON, but PHP's$_POSTdoesn't natively handle JSON payloads. You'd need to read fromphp://inputto access those values, which your current PHP code doesn't do. - Even when PHP does run, it fails to return valid JSON for error cases (like wrong password or missing user), leaving Swift with nothing to parse.
Let's rewrite the PHP to fix these gaps, ensure it always returns valid JSON, and add critical security fixes:
<?php header("Content-type: application/json"); // Initialize a default error response $response = ["erreur" => 1, "message" => "Invalid request"]; // Handle JSON payloads (for Swift's jsonRequest) if($_SERVER['CONTENT_TYPE'] === 'application/json') { $_POST = json_decode(file_get_contents('php://input'), true); } // Check for required parameters (skip loginbutton since Swift doesn't send it) if(isset($_POST['email']) && isset($_POST['password'])) { $conn = new mysqli("123", "123", "123", "123"); if ($conn->connect_error) { $response["message"] = "Connection failed: " . $conn->connect_error; echo json_encode($response); exit; } // Use prepared statements to prevent SQL injection (critical security fix!) $email = $_POST["email"]; $password = $_POST["password"]; $sql = "SELECT * FROM `zusers` WHERE `cEmail` = ?"; $stmt = $conn->prepare($sql); $stmt->bind_param("s", $email); $stmt->execute(); $result = $stmt->get_result(); if($result->num_rows == 1) { $row = $result->fetch_assoc(); if(password_verify($password, $row['cPassword'])) { // Login success: populate response with user data $response["erreur"] = 0; $response["id"] = $row['NumUser']; $response["nom"] = $row['cFirstname']; $response["pseudo"] = $row['cEmail']; $response["message"] = "Login successful"; } else { $response["message"] = "Incorrect password"; } } else { $response["message"] = "User not found"; } $stmt->close(); $conn->close(); } // Always return valid JSON, even on errors echo json_encode($response); ?>
Key fixes here:
- Removed the
loginbuttoncheck and replaced it with checks for the actual required parameters (email/password). - Added support for JSON payloads so both Swift request types work.
- Used prepared statements to eliminate SQL injection risk.
- Ensured every code path returns a valid JSON response (no empty outputs).
Option 1: Fix the Form-URLEncoded Request (Recommended for Login)
Update your formDataRequest to send the correct parameter names, and fix the endpoint URL in your NetworkingService:
// In LoginViewController func formDataRequest(username: String, password: String) { // Match PHP's expected parameter names: "email" and "password" let parameters = ["email": username, "password": password] networkingService.request(endpoint: "/login.php", parameters: parameters) { [weak self] (result) in switch result { case .success(let user): self?.performSegue(withIdentifier: "loginSegue", sender: user) case.failure(let error): guard let alert = self?.alertService.alert(message: error.localizedDescription) else { return } self?.present(alert, animated: true) } } } // In NetworkingService func request(endpoint: String, parameters: [String: Any], completion: @escaping (Result<User, Error>) -> Void) { // Append the endpoint to the base URL (your original code used only baseUrl) guard let url = URL(string: baseUrl + endpoint) else { completion(.failure(NetworkingError.badUrl)) return } // Rest of your code remains the same }
Option 2: Fix the JSON Request
If you prefer using JSON, update your Login struct to match PHP's expected parameter names:
struct Login: Encodable { let email: String let password: String } // In LoginViewController func jsonRequest(email: String, password: String) { let login = Login(email: email, password: password) networkingService.request(endpoint: "/login.php", loginObject: login) { [weak self] (result) in switch result { case .success(let user): self?.performSegue(withIdentifier: "loginSegue", sender: user) case.failure(let error): guard let alert = self?.alertService.alert(message: error.localizedDescription) else { return } self?.present(alert, animated: true) } } }
Your User struct doesn't match the JSON keys returned by PHP. Add coding keys to map the PHP response to your struct (and remove cPassword—never send passwords back to the app!):
struct User: Decodable { let numUser: Int let firstName: String let email: String enum CodingKeys: String, CodingKey { case numUser = "id" case firstName = "nom" case email = "pseudo" } }
Before testing with Swift, use a tool like Postman or curl to send a POST request to your login endpoint. This lets you verify PHP returns valid JSON for all cases (success, wrong password, missing user) before debugging your app.
内容的提问来源于stack exchange,提问作者xcode_beginner

