PHP 및 MySQL을 사용한 Unity 로그인 시스템

이 튜토리얼에서는 PHP와 MySQL을 사용하여 Unity에 로그인 시스템을 만드는 방법을 보여 드리겠습니다.

이 튜토리얼에는 PHP 및 MySQLi(MySQL의 향상된 버전)와 함께 cPanel이 있는 서버가 필요합니다.

부담 없이 저렴한 프리미엄 VPS 호스팅이나 더 저렴한 공유 호스팅 대안을 확인해 보세요.

1단계: MySQL 데이터베이스 설정

  • cPanel에 로그인
  • DATABASES 섹션에서 MySQL 데이터베이스를 클릭하세요.

  • "Create New Database" 섹션 아래에 데이터베이스 이름을 입력한 다음 클릭하세요. "Create Database"

데이터베이스가 생성된 후에는 데이터베이스와 연결될 사용자를 생성해야 합니다.

  • "MySQL Users" 섹션에 사용자 이름을 입력한 다음 비밀번호를 입력하세요(또는 비밀번호 생성기를 사용하여 강력한 비밀번호를 생성하는 것이 좋습니다). 나중에 필요하므로 비밀번호를 어딘가에 저장하는 것을 잊지 마세요.

마지막으로 특정 권한 집합이 있는 데이터베이스에 사용자를 할당해야 합니다.

  • "Add User To Database" 섹션에서 새로 생성된 사용자와 데이터베이스를 선택한 다음 "Add"

"Add"을 클릭하면 권한 목록이 표시됩니다. 앞으로 사용하려는 권한만 선택하세요. 가장 일반적인 것은 DELETE, SELECT, INSERT 및 UPDATE입니다.

  • 완료하려면 "Make Changes"를 클릭하세요.

2단계: MySQL 테이블 생성

MySQL 테이블은 사용자 이름, 이메일, 비밀번호 등과 같이 사용자가 제공한 값을 저장합니다.

  • DATABASES 섹션에서 "phpMyAdmin"를 클릭하세요.

  • 새로 생성된 데이터베이스를 클릭한 후 SQL 탭을 클릭합니다.

  • 아래 코드를 쿼리 편집기에 붙여넣은 다음 "Go"
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";

--
-- Table structure for table `sc_users`
--

CREATE TABLE `sc_users` (
  `user_id` int(11) NOT NULL,
  `username` varchar(20) CHARACTER SET utf8 NOT NULL,
  `email` varchar(254) CHARACTER SET utf8 NOT NULL,
  `password` char(60) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
  `registration_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

--
-- Indexes for table `sc_users`
--
ALTER TABLE `sc_users`
  ADD PRIMARY KEY (`user_id`),
  ADD UNIQUE KEY `username` (`username`),
  ADD UNIQUE KEY `email` (`email`);

--
-- AUTO_INCREMENT for table `sc_users`
--
ALTER TABLE `sc_users`
  MODIFY `user_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;
COMMIT;

위 쿼리는 사용자 데이터를 저장할 새 테이블 'sc_users'을 생성합니다.

3단계: 서버측 로직 프로그래밍

서버 측 로직은 Unity에서 Post 데이터를 수신하고 처리하는 PHP 스크립트로 구성됩니다.

첫 번째 파일은 PHP MySQLi 확장을 사용하여 MySQL 데이터베이스에 연결되는 Database.php입니다.

데이터베이스.php

<?php
	$host = "localhost"; // Host name 
	$db_username = "DATABASE_USER"; // Mysql username 
	$db_password = "USER_PASSWORD"; // Mysql password 
	$db_name = "DATABASE_NAME"; // Database name 

	$mysqli_conection = mysqli_connect($host, $db_username, $db_password, $db_name)or die("cannot connect"); 
?>

DATABASE_USER, USER_PASSWORD,DATABASE_NAME를 원하는 값으로 바꾸세요.

두 번째 파일은 Register.php입니다. 이 파일은 Unity에서 게시 데이터를 수신하고 새 사용자 레코드를 데이터베이스 테이블에 삽입합니다.

레지스터.php

<?php
	if(isset($_POST["email"]) && isset($_POST["username"]) && isset($_POST["password1"]) && isset($_POST["password2"])){
		$errors = array();
		
		$emailMaxLength = 254;
		$usernameMaxLength = 20;
		$usernameMinLength = 3;
		$passwordMaxLength = 19;
		$passwordMinLength = 5;
		
		$email = strtolower($_POST["email"]);
		$username = $_POST["username"];
		$password1 = $_POST["password1"];
		$password2 = $_POST["password2"];
		
		//Validate email
		if(preg_match('/\s/', $email)){
			$errors[] = "Email can't have spaces";
		}else{
			if(!validate_email_address($email)){
				$errors[] = "Invalid email";
			}else{
				if(strlen($email) > $emailMaxLength){
					$errors[] = "Email is too long, must be equal or under " . strval($emailMaxLength) . " characters";
				}
			}
		}
		
		//Validate username
		if(strlen($username) > $usernameMaxLength || strlen($username) < $usernameMinLength){
			$errors[] = "Incorrect username length, must be between " . strval($usernameMinLength) . " and " . strval($usernameMaxLength) . " characters";
		}else{
			if(!ctype_alnum ($username)){
				$errors[] = "Username must be alphanumeric";
			}
		}
		
		//Validate password
		if($password1 != $password2){
			$errors[] = "Passwords do not match";
		}else{
			if(preg_match('/\s/', $password1)){
				$errors[] = "Password can't have spaces";
			}else{
				if(strlen($password1) > $passwordMaxLength || strlen($password1) < $passwordMinLength){
					$errors[] = "Incorrect password length, must be between " . strval($passwordMinLength) . " and " . strval($passwordMaxLength) . " characters";
				}else{
					if(!preg_match('/[A-Za-z]/', $password1) || !preg_match('/[0-9]/', $password1)){
						$errors[] = "Password must contain atleast 1 letter and 1 number";
					}
				}
			}
		}
		
		//Check if there is user already registered with the same email or username
		if(count($errors) == 0){
			//Connect to database
			require dirname(__FILE__) . '/database.php';
			
			if ($stmt = $mysqli_conection->prepare("SELECT username, email FROM sc_users WHERE email = ? OR username = ? LIMIT 1")) {
				
				/* bind parameters for markers */
				$stmt->bind_param('ss', $email, $username);
					
				/* execute query */
				if($stmt->execute()){
					
					/* store result */
					$stmt->store_result();

					if($stmt->num_rows > 0){
					
						/* bind result variables */
						$stmt->bind_result($username_tmp, $email_tmp);

						/* fetch value */
						$stmt->fetch();
						
						if($email_tmp == $email){
							$errors[] = "User with this email already exist.";
						}
						else if($username_tmp == $username){
							$errors[] = "User with this name already exist.";
						}
					}
					
					/* close statement */
					$stmt->close();
					
				}else{
					$errors[] = "Something went wrong, please try again.";
				}
			}else{
				$errors[] = "Something went wrong, please try again.";
			}
		}
		
		//Finalize registration
		if(count($errors) == 0){
			$hashedPassword = password_hash($password1, PASSWORD_BCRYPT);
			if ($stmt = $mysqli_conection->prepare("INSERT INTO sc_users (username, email, password) VALUES(?, ?, ?)")) {
				
				/* bind parameters for markers */
				$stmt->bind_param('sss', $username, $email, $hashedPassword);
					
				/* execute query */
				if($stmt->execute()){
					
					/* close statement */
					$stmt->close();
					
				}else{
					$errors[] = "Something went wrong, please try again.";
				}
			}else{
				$errors[] = "Something went wrong, please try again.";
			}
		}
		
		if(count($errors) > 0){
			echo $errors[0];
		}else{
			echo "Success";
		}
	}else{
		echo "Missing data";
	}
	
	function validate_email_address($email) {
		return preg_match('/^([a-z0-9!#$%&\'*+-\/=?^_`{|}~.]+@[a-z0-9.-]+\.[a-z0-9]+)$/i', $email);
	}
?>

마지막 파일은 자격 증명을 수신하고 sc_users 테이블과 비교하여 확인하는 login.php입니다.

로그인.php

<?php
	if(isset($_POST["email"]) && isset($_POST["password"])){
		$errors = array();
		
		$email = $_POST["email"];
		$password = $_POST["password"];
		
		//Connect to database
		require dirname(__FILE__) . '/database.php';
		
		if ($stmt = $mysqli_conection->prepare("SELECT username, email, password FROM sc_users WHERE email = ? LIMIT 1")) {
			
			/* bind parameters for markers */
			$stmt->bind_param('s', $email);
				
			/* execute query */
			if($stmt->execute()){
				
				/* store result */
				$stmt->store_result();

				if($stmt->num_rows > 0){
					/* bind result variables */
					$stmt->bind_result($username_tmp, $email_tmp, $password_hash);

					/* fetch value */
					$stmt->fetch();
					
					if(password_verify ($password, $password_hash)){
						echo "Success" . "|" . $username_tmp . "|" .  $email_tmp;
						
						return;
					}else{
						$errors[] = "Wrong email or password.";
					}
				}else{
					$errors[] = "Wrong email or password.";
				}
				
				/* close statement */
				$stmt->close();
				
			}else{
				$errors[] = "Something went wrong, please try again.";
			}
		}else{
			$errors[] = "Something went wrong, please try again.";
		}
		
		if(count($errors) > 0){
			echo $errors[0];
		}
	}else{
		echo "Missing data";
	}
?>
  • 3개 파일을 모두 public_html 폴더에 업로드하세요.

4단계: 클라이언트 로직 프로그래밍 Unity

클라이언트 로직은 데이터를 PHP 스크립트에 게시하는 C# 스크립트로 구성됩니다.

  • Unity에 새 스크립트를 만들고 이름을 SC_LoginSystem으로 지정한 다음 그 안에 아래 코드를 붙여넣습니다.

SC_LoginSystem.cs

using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class SC_LoginSystem : MonoBehaviour
{
    public enum CurrentWindow { Login, Register }
    public CurrentWindow currentWindow = CurrentWindow.Login;

    string loginEmail = "";
    string loginPassword = "";
    string registerEmail = "";
    string registerPassword1 = "";
    string registerPassword2 = "";
    string registerUsername = "";
    string errorMessage = "";

    bool isWorking = false;
    bool registrationCompleted = false;
    bool isLoggedIn = false;

    //Logged-in user data
    string userName = "";
    string userEmail = "";

    string rootURL = "http://YOUR_SITE.COM/"; //Path where php files are located

    void OnGUI()
    {
        if (!isLoggedIn)
        {
            if (currentWindow == CurrentWindow.Login)
            {
                GUI.Window(0, new Rect(Screen.width / 2 - 125, Screen.height / 2 - 115, 250, 230), LoginWindow, "Login");
            }
            if (currentWindow == CurrentWindow.Register)
            {
                GUI.Window(0, new Rect(Screen.width / 2 - 125, Screen.height / 2 - 165, 250, 330), RegisterWindow, "Register");
            }
        }

        GUI.Label(new Rect(5, 5, 500, 25), "Status: " + (isLoggedIn ? "Logged-in Username: " + userName + " Email: " + userEmail : "Logged-out"));
        if (isLoggedIn)
        {
            if (GUI.Button(new Rect(5, 30, 100, 25), "Log Out"))
            {
                isLoggedIn = false;
                userName = "";
                userEmail = "";
                currentWindow = CurrentWindow.Login;
            }
        }
    }

    void LoginWindow(int index)
    {
        if (isWorking)
        {
            GUI.enabled = false;
        }

        if (errorMessage != "")
        {
            GUI.color = Color.red;
            GUILayout.Label(errorMessage);
        }
        if (registrationCompleted)
        {
            GUI.color = Color.green;
            GUILayout.Label("Registration Completed!");
        }

        GUI.color = Color.white;
        GUILayout.Label("Email:");
        loginEmail = GUILayout.TextField(loginEmail);
        GUILayout.Label("Password:");
        loginPassword = GUILayout.PasswordField(loginPassword, '*');

        GUILayout.Space(5);

        if (GUILayout.Button("Submit", GUILayout.Width(85)))
        {
            StartCoroutine(LoginEnumerator());
        }

        GUILayout.FlexibleSpace();

        GUILayout.Label("Do not have account?");
        if (GUILayout.Button("Register", GUILayout.Width(125)))
        {
            ResetValues();
            currentWindow = CurrentWindow.Register;
        }
    }

    void RegisterWindow(int index)
    {
        if (isWorking)
        {
            GUI.enabled = false;
        }

        if (errorMessage != "")
        {
            GUI.color = Color.red;
            GUILayout.Label(errorMessage);
        }

        GUI.color = Color.white;
        GUILayout.Label("Email:");
        registerEmail = GUILayout.TextField(registerEmail, 254);
        GUILayout.Label("Username:");
        registerUsername = GUILayout.TextField(registerUsername, 20);
        GUILayout.Label("Password:");
        registerPassword1 = GUILayout.PasswordField(registerPassword1, '*', 19);
        GUILayout.Label("Password Again:");
        registerPassword2 = GUILayout.PasswordField(registerPassword2, '*', 19);

        GUILayout.Space(5);

        if (GUILayout.Button("Submit", GUILayout.Width(85)))
        {
            StartCoroutine(RegisterEnumerator());
        }

        GUILayout.FlexibleSpace();

        GUILayout.Label("Already have an account?");
        if (GUILayout.Button("Login", GUILayout.Width(125)))
        {
            ResetValues();
            currentWindow = CurrentWindow.Login;
        }
    }

    IEnumerator RegisterEnumerator()
    {
        isWorking = true;
        registrationCompleted = false;
        errorMessage = "";

        WWWForm form = new WWWForm();
        form.AddField("email", registerEmail);
        form.AddField("username", registerUsername);
        form.AddField("password1", registerPassword1);
        form.AddField("password2", registerPassword2);

        using (UnityWebRequest www = UnityWebRequest.Post(rootURL + "register.php", form))
        {
            yield return www.SendWebRequest();

            if (www.result != UnityWebRequest.Result.Success)
            {
                errorMessage = www.error;
            }
            else
            {
                string responseText = www.downloadHandler.text;

                if (responseText.StartsWith("Success"))
                {
                    ResetValues();
                    registrationCompleted = true;
                    currentWindow = CurrentWindow.Login;
                }
                else
                {
                    errorMessage = responseText;
                }
            }
        }

        isWorking = false;
    }

    IEnumerator LoginEnumerator()
    {
        isWorking = true;
        registrationCompleted = false;
        errorMessage = "";

        WWWForm form = new WWWForm();
        form.AddField("email", loginEmail);
        form.AddField("password", loginPassword);

        using (UnityWebRequest www = UnityWebRequest.Post(rootURL + "login.php", form))
        {
            yield return www.SendWebRequest();

            if (www.result != UnityWebRequest.Result.Success)
            {
                errorMessage = www.error;
            }
            else
            {
                string responseText = www.downloadHandler.text;

                if (responseText.StartsWith("Success"))
                {
                    string[] dataChunks = responseText.Split('|');
                    userName = dataChunks[1];
                    userEmail = dataChunks[2];
                    isLoggedIn = true;

                    ResetValues();
                }
                else
                {
                    errorMessage = responseText;
                }
            }
        }

        isWorking = false;
    }

    void ResetValues()
    {
        errorMessage = "";
        loginEmail = "";
        loginPassword = "";
        registerEmail = "";
        registerPassword1 = "";
        registerPassword2 = "";
        registerUsername = "";
    }
}

http://YOUR_SITE.COM/를 원하는 값으로 바꿉니다(이 값은 PHP 파일을 업로드한 루트 경로여야 합니다). 또한 서버에 SSL 인증서가 설치되어 있는 경우 HTTPS를 사용해야 합니다.

  • 새로운 GameObject를 생성하고 이름을 지정하세요. "LoginSystem"
  • SC_LoginSystem에 를 LoginSystem 개체에 연결

재생을 누른 다음 등록을 클릭하여 새 계정을 생성하거나 로그인을 위한 자격 증명을 제공합니다.

온라인 리더보드를 만드는 방법에 대한 이 튜토리얼이 계속됩니다.

추천 기사
Unity 온라인 리더보드 튜토리얼
멀티플레이어 데이터 압축 및 비트 조작
Unity의 Photon Fusion 2 소개
Unity에서 멀티플레이어 네트워크 게임 구축
PUN 2로 멀티플레이어 자동차 게임 만들기
PUN 2 지연 보상
Unity, PUN 2 룸에 멀티플레이어 채팅 추가