前記事の「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に接続する方法を紹介しました。あんまり人に見せられるような綺麗なソースでもないため、参考程度に見て頂けると幸いです。
間違えていた場合、修正します!長くなりましたが、最後まで読んで頂きありがとうございました!

コメント