Система входа Unity с PHP и MySQL

В этом уроке я покажу, как создать систему входа в Unity с использованием PHP и MySQL.

Для этого руководства требуется сервер с cPanel, а также PHP и MySQLi (улучшенная версия MySQL).

Не стесняйтесь проверить доступный хостинг премиум-класса VPS или более дешевую альтернативу Shared Hosting.

Шаг 1. Настройка базы данных MySQL

  • Войдите в cPanel
  • Нажмите «Базы данных MySQL» в разделе «БАЗЫ ДАННЫХ».

  • В разделе "Create New Database" введите имя вашей базы данных и нажмите "Create Database"

После создания базы данных нам нужно создать пользователя, который будет с ней связан:

  • Введите имя пользователя в разделе "MySQL Users", затем введите пароль (или предпочтительно используйте генератор паролей для создания надежного пароля). Не забудьте сохранить где-нибудь пароль, он понадобится позже.

Наконец, нам нужно назначить пользователя базе данных с определенным набором разрешений.

  • В разделе "Add User To Database" выберите вновь созданного пользователя и базу данных, затем нажмите "Add"

После нажатия "Add" вам будет представлен список привилегий. Выбирайте только те привилегии, которые вы планируете использовать в будущем. Наиболее распространенными являются DELETE, SELECT, INSERT и UPDATE:

  • Нажмите "Make Changes", чтобы завершить

Шаг 2. Создайте таблицу MySQL

Таблица MySQL будет хранить значения, предоставленные пользователями, такие как имя пользователя, адрес электронной почты, пароль и т. д.

  • Нажмите "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. Программирование серверной логики

Серверная логика будет состоять из PHP-скриптов, которые будут получать и обрабатывать данные Post из Unity.

Первый файл — data.php, который будет подключаться к базе данных MySQL с использованием расширения PHP MySQLi.

база данных.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);
	}
?>

И последний файл — login.php, который получит учетные данные и сверит их с таблицей sc_users.

логин.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

Клиентская логика будет состоять из сценария C#, который будет отправлять данные в сценарий PHP.

  • Создайте новый скрипт в 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). Кроме того, обязательно используйте HTTPS, если на вашем сервере установлен сертификат SSL.

  • Создайте новый GameObject и назовите его. "LoginSystem"
  • Прикрепите к SC_LoginSystem к объекту LoginSystem

Нажмите «Воспроизвести», затем нажмите «Зарегистрироваться», чтобы создать новую учетную запись или предоставить учетные данные для входа в систему.

У нас есть продолжение этого урока о том, как создать онлайн-таблицу лидеров.

Рекомендуемые статьи
Учебное пособие по онлайн-таблице лидеров Unity
Введение в Photon Fusion 2 в Unity
Создание многопользовательских сетевых игр в Unity
Многопользовательское сжатие данных и битовая манипуляция
Создайте многопользовательскую автомобильную игру с помощью PUN 2
PUN 2 Компенсация задержки
Unity добавляет многопользовательский чат в комнаты PUN 2