Skip to main content

ログイン

PHPでAPIを作成(固定結果)

まず、Unityから接続できるようにしたいので、サーバーでログイン API の機能を追加しましょう。データベースがまだ作成していないため、ひとまず固定の結果を返しましょう。

C:\xmpp\htdocs\api フォルダを作成しましょう。この中に本ゲームのオンライン機能を実装していくフォルダにする。その中にlogin.php というからのテキストファイルを作成してください。単純に、成功したかどうかを固定数値として返しましょう:

<?php
	// JSONを返すべき
	header("Content-Type: application/json; charset=utf-8");

	// 成功したかどうかを返す
	$json['success'] = true;
	
	// 返す
	print(json_encode($json));
?>

まだPOSTデータが要らないので、ブラウザーで確認できる:

image.png

Unityを使い、APIとの接続

仮で作ったログインAPIを試すため、UnityでAPI管理クラスを作ってみましょう。まず、単純に:

// サーバーに依頼するメソッドの一覧
public static class APIRequest 
{
    // サーバーのAPIのURL
    private const string ServerAPI = "http://localhost/api";
    
    // ログイン
    public static async Awaitable LoginAsync()
    {
        // ログインAPIのURLへリクエストを送信
        const string url = ServerAPI + "/login.php";
        var webRequest = UnityWebRequest.Get(url);
        
        // 返事を待機する
        await webRequest.SendWebRequest();

        // 返事の文字列を取得
        var webResponse = webRequest.downloadHandler.text;
        
        // デバッグ用
        Debug.Log(webResponse); 
    }
}

試すには、トップメニュー画面で、ログイン画面で、「ログイン」ボタンを押したら、上記のメソッドを使用しましょう:

// ログイン処理する
public class LoginController : MonoBehaviour
{
    // ログインボタン
    [SerializeField] private Button sendButton;

    // ログインボタンを押したとき
    private async void OnSendClicked()
    {
        // リクエストを送信し、待機する
        var request =await APIRequest.LoginAsync();
        await request;
    }

    // 有効になった時
    private void OnEnable()
    {
        sendButton.onClick.AddListener(OnSendClicked);
    }

    // 無効になった時
    private void OnDisable()
    {
        sendButton.onClick.RemoveAllListeners();
    }
}

Unityでログインコントローラーを追加し、ボタンを設定する:

image.png

実行すると:

image.png

サーバーの返事を確認できた!

ポップアップを表示

次、Webサーバーから戻るJSONを変換し、結果により、ポップアップを表示しましょう。そのために、まず、APIRequest を編集し、成功したかどうかを返しましょう。先頭に、新しいデータの構造体を作成.。これは JSON をUnityで使えるデータに変換しないければならない。そのため、Unity は便利な機能があるの形式に合わせる:

JsonUtility.ToJson

// C#ログインの結果
のオブジェクトをJSONの文字列にする。
string json = JsonUtility.ToJson(なにかのオブジェクト);

これで、あるクラス、または構造体から作ったインスタンスをJSON形式の文字列を作成する。ただし:

    公開されている(public)変数か配列 floatintboolstring 型の変数か配列

    のみ変換できます。例えば:

    public classstruct DataLoginResponse
    {
        // 経験値成功したか?
        public intbool XP = 1000;
        
        // 名前
        public string HeroName = "ヒーロー";
        
        // private なので、JSONにできない
        private float HitPower = 12.25f;
    }
    
    private void Start()
    {
        // インスタンスを作成
        Data data = new Data();
        
        // JSON文字列にする
        string json = JsonUtility.ToJson(data);
        
        // 表示
        Debug.Log(json);success;
    }

    以下のを表示される:

    image.pngそして、今度は LoginResponse を返すので、メソッドが少し変わる:

    もちろん、逆のもできる:

    JsonUtility.FromJson

    // JSONの文字列からあるクラス(または構造体)のインスタンスを作成前:
    データ型public オブジェクト名static =async JsonUtility.FromJsonAwaitable LoginAsync()
    
    // 後:
    public static async Awaitable<データ型LoginResponse>(string json);LoginAsync()

    これで、ToJson() の逆処理ができる。ここで「データ型」は変換したいクラス名(または構造体名)である。例えば、

    private void Start()
    {
        // インスタンスを作成
        Data data = new Data();
        
        // 元のデータ
        Debug.Log($"前 >> 名前:{data.HeroName}, 経験値:{data.XP}");
        
        // JSONデータ
        string json = "{\"XP\":5000, \"HeroName\":\"アンパンマン\" }";
    
        // JSONからオブジェクトにする
        data = JsonUtility.FromJson<Data>(json);
        
        // 変わった後
        Debug.Log($"後 >> 名前:{data.HeroName}, 経験値:{data.XP}");
    }

    image.png

     

    まず、APIRequest を編集し、成功したかどうかを返しましょう:

    すべて組みあわえると:

    // ログインの結果
    public struct LoginResponse
    {
        // 成功したか?
        public bool success;
    }
    
    // サーバーに依頼するメソッドの一覧
    public static class APIRequest
    {
        // サーバーのAPIのURL
        private const string ServerAPI = "http://localhost/api";
    
        // 非同期処理:ログイン
        // 戻り値:LoginResponse:ログインの結果
        public static async Awaitable<LoginResponse> LoginAsync()
        {
            // ログインAPIのURLへリクエストを送信
            const string url = ServerAPI + "/login.php";
            var webRequest = UnityWebRequest.Get(url);
    
            // 返事を待機する
            await webRequest.SendWebRequest();
    
            // 返事の文字列を取得
            var webResponse = webRequest.downloadHandler.text;
    
            // デバッグ用
            Debug.Log(webResponse);
            
            // JSONからLoginResponseへ変換
            LoginResponse response = JsonUtility.FromJson<LoginResponse>(webResponse);
    
            // 返す
            return response;
        }
    }

    そして、LoginController で結果を確認し、ポップアップを表示しましょう:

    // ログインボタンを押したとき
    private async void OnSendClicked()
    {
        // リクエストを送信し、待機する
        LoginResponse result = await APIRequest.LoginAsync();
        
        if (result.success)
        {
            PopupController.Show("成功!", "ログインできました!");
        }
        else
        {
            PopupController.Show("エラー", "ログインできませんでした。");
        }
    }

    「ログイン」ボタンを押すと

    image.png

    login.php で true / false を変えて、Unityで確かめてください。

    PHPでAPIを作成(ifで分岐)

    現在、login.php で成功するかどうかは固定しているので、if で分岐しましょう。ユーザー名とパスワードは "test" だったら、ログインは成功し、そうではない場合は失敗しましょう:

    <?php
    	// JSONを返すべき
    	header("Content-Type: application/json; charset=utf-8");
    
    	// 失敗を想定する
    	$json['success'] = false;
    
        // ユーザー名とパスワードを確認
        $user = $_POST['user'];
        $pass = $_POST['password'];
        if ($user == "test" && $pass == "test")
        {
            $json['success'] = true;
        }
    	
    	// 返す
    	print(json_encode($json));
    ?>

    このスクリプトは POST でユーザー名とパスワードを期待しているので、Unity から渡しましょう。

    // ログイン
    // user:ユーザー名
    // password:パスワード
    // 戻り値:LoginResponse:ログインの結果
    public static async Awaitable<LoginResponse> LoginAsync(string user, string password)
    {
        // POSTでデータを送るので、フォームを用意する変数を用意する
        // サーバーが期待しているデータに合わせる
        var postData = new WWWForm();
        postData.AddField("user", user);
        postData.AddField("pass"password", password);
        
        // ログインAPIのURLへリクエストを送信
        const string url = ServerAPI + "/login.php";
        var webRequest = UnityWebRequest.Post(url, postData);
    
        // 返事を待機する
        await webRequest.SendWebRequest();
    
        // 返事の文字列を取得
        var webResponse = webRequest.downloadHandler.text;
    
        // デバッグ用
        // Debug.Log(webResponse);
        
        // JSONから使えるデータにするJSONからLoginResponseへ変換
        returnLoginResponse response = JsonUtility.FromJson<LoginResponse>(webResponse);
    
        }// 返す
        return response;
    }

    最後に、LoginController

    if文で確認

    で画面の入力との連携すれば、出来上がり!
    // ログインを処理する
    public class LoginController : MonoBehaviour
    {
        // ユーザー名
        [SerializeField] private TMP_InputField nameInput;
    
        // パスワード
        [SerializeField] private TMP_InputField passwordInput;
    
        // ログインボタン
        [SerializeField] private Button sendButton;
    
        // ログインボタンを押したとき
        private async void OnSendClicked()
        {
            // リクエストを送信し、待機する
            var name = nameInput.text;
            var pass = passwordInput.text;
            LoginResponse result = await APIRequest.LoginAsync(name, pass);
    
            if (result.success)
            {
                PopupController.Show("成功!", "ログインできました!");
            }
            else
            {
                PopupController.Show("エラー", "ログインできませんでした。");
            }
        }
    
        // (省略)
      }

    image.png

    データベースを作成

    API処理を更新

    まず、カードゲーム専用の「card_game」データベースを作成しましょう:

    image.png

    次に、ユーザーのテーブルを作成しましょう。必要なのは、ユーザーID番号、ユーザー名とパスワードなので、3のカラムで設計:

    image.png

    image.png

    そして、いくつかのユーザーを作成してみてください

    image.png

    注意

    平文(人間が読める)パスワードを保存するのは大変危険であるので、必ずハッシュしてから保存してください。今回の練習のために平文で保存する。

     

    パスワードセキュリティに関して、別の科目のテーマであるが、後で軽く説明する。

    PHPでAPIを作成(DBを使用)

    login.php を編集し、データベースのサポートを追加しましょう。

    <?php
    	// JSONを返すべき
    	header("Content-Type: application/json; charset=utf-8");
    
    	// 接続 
    	$dbh = new PDO('mysql:host=localhost; dbname=card_game', "root", "", [PDO::ATTR_PERSISTENT => true]);
    
    	// 失敗を想定する
    	$json['success'] = false;
    
        // ユーザー名とパスワードを確認
        $user = htmlspecialchars($_POST['user']);
        $pass = htmlspecialchars($_POST['password']);
    
    	// データベース検索
    	$sql = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'", $user, $pass);	
    	$result = $dbh->query($sql);
    
    	// 必ず1個を返さなきゃ
    	if ($result->rowCount() == 1)
    	{
            $json['success'] = true;
    	}
    	
    	// 返す
    	print(json_encode($json));
    ?>

    Unityを使い、確認してみてください。