前記事の「Unityで作ったゲームからMySQLに接続」のやり方で、Unityエディタから接続できることを確認。しかし、ビルドしたファイルをローカルサーバーに置いてブラウザで動作確認したところ、エラーが出て接続できないことがわかりました。
そのため、サーバー側にPHPをWebAPIとして置いて、WebGLから呼び出す形に変更。その際のやり方をメモ程度に残しておきます。細かい所をわかってない可能性が高いので、詳細を知りたい方は調べてください。
接続方法を変更
WebGLから直接MySQLに接続することは難しいと考え、PHPをWebAPIとして介して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エラー」が発生していました。
エラー文は以下の通りです。
(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に接続する方法を紹介しました。あんまり人に見せられるような綺麗なソースでもないため、参考程度に見て頂けると幸いです。
間違えていた場合、修正します!長くなりましたが、最後まで読んで頂きありがとうございました!
コメント