Unityで作成したWebGLゲームをブラウザからMySQLに接続した時のメモ

技術情報

前記事の「Unityで作ったゲームからMySQLに接続」のやり方で、Unityエディタから接続できることを確認。しかし、ビルドしたファイルをローカルサーバーに置いてブラウザで動作確認したところ、エラーが出て接続できないことがわかりました。

そのため、サーバー側にPHPをWebAPIとして置いて、WebGLから呼び出す形に変更。その際のやり方をメモ程度に残しておきます。細かい所をわかってない可能性が高いので、詳細を知りたい方は調べてください。

接続方法を変更

WebGLから直接MySQLに接続することは難しいと考え、PHPをWebAPIとして介してMySQLに接続するよう変更した。

× WebGL(C#) → MySQL

○ WebGL(C#) → PHP → MySQL

ソースコード

MySQLに接続するためのPHPとC#のUnity Scriptを紹介します。PHPでデータベースにアクセスし、JSONで返す形で作っています。ソースの書き方は下手だと思うのでお許しください。

PHP(WebAPI)を準備

PHPは、SELECT用とINSERT用ふたつを用意しました。それぞれ参考にして頂けたらと思います。また、JSONで返却するためのデータクラスを用意しています。

返却用データクラス

<?php

// 返却用クラス
class JsonReturnData
{
    // エラーコード
    public $error_code;

    // エラーメッセージ
    public $error_msg;

    // Selectデータリスト
    public $result_list;

    // コンストラクタ
    public function __construct()
    {
        $this->error_code = 0;
        $this->error_msg = "";
        $this->result_list = array();
    }
}
?>

 

SELECT用PHP

<?php

require "./DataClass/JsonReturnData.php";

$servername = “サーバー名”;
$dbname = "データベース名";
$username = "ユーザー名";
$password = "パスワード";
$port = "ポート番号";

// 返却用
$return_data = new JsonReturnData;

try {
    // データベースに接続
    $conn = new PDO("mysql:host=$servername;dbname=$dbname;port=$port;", $username, $password);
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // SQLクエリを実行
    $sql = "SELECT * FROM テーブル名;";
    $stmt = $conn->query($sql);

    if ($stmt->rowCount() > 0) {
        // 結果をループ
        while ($row = $stmt->fetchObject()) {
            // 返却用リストに格納
            array_push($return_data->result_list,$row);
        }
    }

    // 接続を閉じる
    $conn = null;

    //jsonとして出力
    header('Content-type: application/json');
    echo json_encode($return_data);

} catch (PDOException $e) {

    // エラーコード設定
    $return_data->error_code = 1;
    $return_data->error_msg = $e->getMessage();

    //jsonとして出力
    header('Content-type: application/json');
    echo json_encode($return_data);

    exit();
}

?>

 

INSERT用PHP

<?php

// 返却用クラスファイル読み込み
require "./DataClass/JsonReturnData.php";

// ローカルテスト用
$servername = "サーバー名";
$dbname = "データベース名";
$username = "ユーザー名";
$password = "パスワード";
$port = "ポート番号";

// 返却用クラス定義
$return_data = new JsonReturnData;

try {
    // データベースに接続
    $conn = new PDO("mysql:host=$servername;dbname=$dbname;port=$port;", $username, $password);
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // SQL
    $sql = "INSERT INTO テーブル名 (name, create_time) VALUES (:name, now());";

    // SQL実行の準備をする
    $stmt = $conn->prepare($sql);

    // 挿入する値を配列に格納する
    $stmt -> bindValue(':name', $_POST['name']);

    // 挿入する値が入った変数をexecuteにセットしてSQLを実行
    $flag = $stmt->execute();

    // falseで実行失敗
    if(!$flag){
        // 実行失敗している時
        $return_data->error_code = 1;
        $return_data->error_msg = 'クエリの実行に失敗しました。';
    }

    // 接続を閉じる
    $conn = null;

    //jsonとして出力
    header('Content-type: application/json');
    echo json_encode($return_data);

} catch (PDOException $e) {
    // エラーコード設定
    $return_data->error_code = 1;
    $return_data->error_msg = $e->getMessage();

    // jsonとして出力
    header('Content-type: application/json');
    echo json_encode($return_data);

    $conn = null
    exit();
}

?>

 

呼び出し元C#ソース(Unity Script)

Unity側のC#ソースサンプルを紹介します。

データクラスはJSONデータをJsonUtility.FromJsonでオブジェクト化した時の格納用クラスです。データクラス内に別のクラスを定義する入れ子の場合、クラス名の前に[System.Serializable]を追加しないと読み込まないので注意してください。基本的にpublic変数では必要ありませんが、カプセル化しているクラスの場合private変数を定義する上に[System.Serializable]を追加することで読み込むようになります。

Json返却用データクラス

public class JsonData
{
    public int error_code;
    public string error_msg;
    public List<Ranking> result_list;
}

 

テーブルデータ格納用クラス

[System.Serializable]
public class Ranking
{
    public string name;
    public string create_time;
}

 

SELECT用WebAPI(PHP)呼び出し処理

// 返却用
JsonData resultJsonData;

// リクエスト
using (UnityWebRequest request = UnityWebRequest.Get("置いてあるPHPのURL入力"))
{
    // リクエスト送信し結果を待つ
    await request.SendWebRequest();

    // レスポンスの結果が成功以外はエラー
    if (request.result != UnityWebRequest.Result.Success)
    {
        // エラーが発生した場合の処理
        Debug.LogError("WebAPI Error: " + request.error);
        return rankingList;
    }

    // レスポンスJSONデータを取得
    resultJsonData = JsonUtility.FromJson<JsonData> (request.downloadHandler.text);

    // エラーコードの場合
    if (resultJsonData.error_code == 1)
    {
        Debug.LogError(resultJsonData.error_msg);
        return rankingList;
    }
}

// 取得したJSONデータを返却
return resultJsonData;

 

INSERT用WebAPI(PHP)呼び出し処理

// postデータ設定
WWWForm form = new WWWForm();
form.AddField("name", name);

// リクエスト
using (UnityWebRequest request = UnityWebRequest.Post(Common.CUD_DbPhpPath_Release, form))
{
    // リクエスト送信し結果を待つ
    await request.SendWebRequest();

    // レスポンスの結果が成功以外はエラー
    if (request.result != UnityWebRequest.Result.Success)
    {
        // エラーが発生した場合の処理
        Debug.LogError("WebAPI Error: " + request.error);

        return false;
    }

    // JSONデータを取得
    JsonData responseData = JsonUtility.FromJson<JsonData>(request.downloadHandler.text);

    // エラーコードの場合
    if (responseData.error_code == 1)
    {
        Debug.LogError(responseData.error_msg);
        return false;
    }
}

 

ローカル環境にPHPを配置

ローカル環境のpublic以下に作成したPHPを配置します。これでローカル環境で問題なく動くことを確認してください。

動作確認をしたい場合は、実際にローカル環境にUnityで作成したWebGLを配置してブラウザ上で確認する方法と、Google Chromeの拡張機能にある「talend API Tester」を使用すると良いです。

本番環境でファイルを配置して実施

ローカル環境で問題なく動くことを確認したので、本番環境に配置しました。

利用サーバーによっては403エラーが発生する

本番環境にPHPで作ったWebAPIやWebGLを配置して、ブラウザ上で確認したところ「403エラー」が発生。原因は、本番環境で使用している「さくらのレンタルサーバー」の推奨設定「WAF」によってブロックされていたことがわかりました。

対処するには「WAFを使用しないサブドメインを新規作成し、そこにWebAPIを置く」という方法です。これにより「talend API Tester」で問題なくデータが返却されたことを確認できました。

本番環境でWebGLからWebAPIにアクセスできなかった

WAFを使用していないサブドメインにPHPで作ったWebAPIを配置しても、ブラウザからWebGLによってデータ登録・参照できるか確認したところ「CORSエラー」が発生していました。

エラー文は以下の通りです。

has been blocked by CORS policy:No ‘Access-Control-Allow-Origin’ header is present on the requested resource
(CORS ポリシーによってブロックされました:要求されたリソースに「Access-Control-Allow-Origin」ヘッダーが存在しません)

解決方法は、WebAPIのPHPソースで以下の内容を追加します。
これにより「Access-Control-Allow-Origin」ヘッダーが追加され、アクセスが可能になります。

header("Access-Control-Allow-Origin: *");

 

ソースコードの例

私の場合、requireでファイル読み込みを行った後に上記ソースを記載しています。

<?php

require "./DataClass/JsonReturnData.php";

// CORSエラー対策
header("Access-Control-Allow-Origin: *");

$servername = “サーバー名”;
$dbname = "データベース名";
$username = "ユーザー名";
$password = "パスワード";
$port = "ポート番号";

// 返却用
$return_data = new JsonReturnData;

…省略

 

さいごに

Unityで作成したWebGLゲームをブラウザから呼び出し、PHPでMySQLに接続する方法を紹介しました。あんまり人に見せられるような綺麗なソースでもないため、参考程度に見て頂けると幸いです。

間違えていた場合、修正します!長くなりましたが、最後まで読んで頂きありがとうございました!

コメント

タイトルとURLをコピーしました