SWIFT-PHP-MYSQL-使用者登入

這篇的實作會以這個範例PHP檔案做延續

系統

macOS Monterey 12.6
XAMPP 8.1.6
XCode 14

PHP程式碼-用戶驗證

首先要利用資料庫做用戶驗證並登入

以下程式碼寫到 include 的DbOperation.php檔案中的 Constructor 方法之後:


//登入2
    // 這個方法會幫我們取得用戶和密碼並在資料庫驗證它
    public function userLogin($username, $pass)
    {
        $password = md5($pass);
        $stmt = $this->conn->prepare("SELECT id FROM users WHERE username = ? AND password = ?");
        $stmt->bind_param("ss", $username, $password);
        $stmt->execute();
        $stmt->store_result();
        return $stmt->num_rows > 0;
    }

    //取得用戶名2
    // 如果登入成功,會以array型式回傳用戶資料
    public function getUserByUsername($username)
    {
        $stmt = $this->conn->prepare("SELECT id, username, email, phone FROM users WHERE username = ?");
        $stmt->bind_param("s", $username);
        $stmt->execute();
        $stmt->bind_result($id, $uname, $email, $phone);
        $stmt->fetch();
        $user = array();
        $user['id'] = $id;
        $user['username'] = $uname;
        $user['email'] = $email;
        $user['phone'] = $phone;
        return $user;
    }

接著到 v1 資料夾底下新增一個檔案: login.php


require_once '../includes/DbOperation.php';

$response = array();

if ($_SERVER['REQUEST_METHOD'] == 'POST') {

    if (isset($_POST['username']) && isset($_POST['password'])) {

        $db = new DbOperation();

        if ($db->userLogin($_POST['username'], $_POST['password'])) {
            $response['error'] = false;
            $response['user'] = $db->getUserByUsername($_POST['username']);
        } else {
            $response['error'] = true;
            $response['message'] = 'Invalid username or password';
        }

    } else {
        $response['error'] = true;
        $response['message'] = 'Parameters are missing';
    }

} else {
    $response['error'] = true;
    $response['message'] = "Request not allowed";
}

echo json_encode($response);

API測試 - POSTMAN

XCode 登入畫面

新增一個XCode專案,並將 alamofire 加入

製作畫面

拉元件

然後將元件跟程式碼繫結起來
名稱:

import UIKit
import Alamofire

class ViewController: UIViewController {
    
    @IBOutlet weak var labelMessage: UILabel!
    @IBOutlet weak var textFieldUserName: UITextField!
    @IBOutlet weak var textFieldPassword: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    @IBAction func buttonLogin(_ sender: Any) {
    }
    
}

Storyboard ID

並給個ID
這邊取為:ViewController

把這個頁面設成 Navigation Controller

結果:

跳轉頁面

再來拉一個 View Controller

並加上三個元件

登入程式碼 View Controller.swift的程式碼

URL_USER_LOGIN要跟剛剛postman輸入的一樣,但是localhost必需是數字,如我的就是127.0.0.1,如果不知道可以用ifconfig查詢。

//
//  ViewController.swift
//  1011LoginDemo
//
//  Created by 黃筱珮 on 2022/10/11.
//

import UIKit
import Alamofire

class ViewController: UIViewController {
    // 這裡的網址要跟剛剛在postman的測試網址一樣
    let URL_USER_LOGIN = "http://127.0.0.1:8080/LoginDemo/v1%20/login.php"
    
    // 儲存用戶資料
    let defaultValues = UserDefaults.standard
    
    // 元件繫結
    @IBOutlet weak var labelMessage: UILabel!
    @IBOutlet weak var textFieldUserName: UITextField!
    @IBOutlet weak var textFieldPassword: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 隱藏navigationController
        let backButton = UIBarButtonItem(title: "", style: UIBarButtonItem.Style.plain, target: navigationController, action: nil)
        navigationItem.leftBarButtonItem = backButton
        
        
        
        //如果用戶已經登入就切換到灰色畫面
        if defaultValues.string(forKey: "username") != nil{
            let profileViewController = self.storyboard?.instantiateViewController(withIdentifier: "ProfileViewcontroller") as! ProfileViewController
            self.navigationController?.pushViewController(profileViewController, animated: true)
            
        }
    }
    
    
    
    // 元件繫結
    @IBAction func buttonLogin(_ sender: Any) {
        
        // 取得 username and password
        let parameters: Parameters=[
            "username":textFieldUserName.text!,
            "password":textFieldPassword.text!
        ]
        
        // 發出post請求
        Alamofire.request(URL_USER_LOGIN, method: .post, parameters: parameters ).responseJSON{
            response in
            
            print(response)
            
            // 從web server 獲取json值
            if let result = response.result.value {
                let jsonData = result as! NSDictionary
                
                // 如果沒有錯誤
                if(!(jsonData.value(forKey: "error") as! Bool)){
                    
                    // 取得用戶
                    let user = jsonData.value(forKey: "user") as! NSDictionary
                    
                    // 取得用戶資料
                    let userId = user.value(forKey: "id") as! Int
                    let userName = user.value(forKey: "username") as! String
                    let userEmail = user.value(forKey: "email") as! String
                    let userPhone = user.value(forKey: "phone") as! String
                    
                    // 儲存用戶資料
                    self.defaultValues.set(userId, forKey: "userid")
                    self.defaultValues.set(userName, forKey: "username")
                    self.defaultValues.set(userEmail, forKey: "useremail")
                    self.defaultValues.set(userPhone, forKey: "userphone")
                    
                    // 跳頁
                    let profileViewController = self.storyboard?.instantiateViewController(withIdentifier: "ProfileViewcontroller") as! ProfileViewController
                    self.navigationController?.pushViewController(profileViewController, animated: true)
                    
                    self.dismiss(animated: false, completion: nil)
                }else{
                    // 取得無效的錯誤訊息
                    self.labelMessage.text = "Invalid username or password"
                }
            }
        }
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // 處理所有可以重新創建的資源。
    }
    
}

創一個類別

不要忘了,灰色頁面還沒有類別

這個類別取名:ProfileViewController.swift

並在裡面加入一段程式碼:

override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // 處理所有可以重新創建的資源。
    }

ProfileViewController的程式碼

//
//  ProfileViewController.swift
//  1008LoginDemo
//
//  Created by 黃筱珮 on 2022/10/9.
//

import UIKit

class ProfileViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // 處理所有可以重新創建的資源。
    }
    
}

並把它們做繫結

Storyboard ID設定

ProfileViewcontroller

跳頁程式 ProfileViewController.swift

//
//  ProfileViewController.swift
//  1011LoginDemo
//
//  Created by 黃筱珮 on 2022/10/11.
//

import UIKit

class ProfileViewController: UIViewController {

    @IBOutlet weak var labelUserName: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        //隱藏navigation的返回按鈕
        let backButton = UIBarButtonItem(title: "", style: UIBarButtonItem.Style.plain, target: navigationController, action: nil)
        navigationItem.leftBarButtonItem = backButton
        
        //從默認值中獲取使用者資料
        let defaultValues = UserDefaults.standard
        if let name = defaultValues.string(forKey: "username"){
            
            labelUserName.text = name
        }else{
            //send back to login view controller
        }
        
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // 處理所有可以重新創建的資源。
    }
    
    @IBAction func buttonLogout(_ sender: Any) {
        //刪除默認值
        UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)
        UserDefaults.standard.synchronize()
        
        //切換到登入頁面
        let loginViewController = self.storyboard?.instantiateViewController(withIdentifier: "ViewController") as! ViewController
        self.navigationController?.pushViewController(loginViewController, animated: true)
        self.dismiss(animated: false, completion: nil)
    }
}

測試

如果剛剛在postman可以,到這邊應該是沒問題。

https://youtube.com/shorts/n7ryquRRPWo