サンプルのソースコードはgithubにあります。
概要
過去に制作したゲームの一部に上位3位までを表示するランキング機能を実装してみました。↓のゲームは3秒間にクリックした回数を競うゲームです。 3位までに入るとランキングに登録することが出来ます。クリックするとゲームが開始されます。
ランキング機能実装した過去のゲーム↓
Visual Studio Codeの拡張機能SQliteを使用してデータベースを作成する
データベースの作成にはVisual Studio Codeの拡張機能SQliteを使用しました。
テーブル名はtestにしました。テーブルの中には二つのカラムがあり、一つ目のnameカラムには名前を保持して二つ目のscoreカラムには得点や記録などを保持します。テーブルには最下位になるデータを一件追加しています。
1 2 3 |
CREATE TABLE test(name, score); INSERT INTO test VALUES('名無しさん', '0'); |
PHPのPDOを使ってデータベースに接続してデータを取得する
PDOクラスをインスタンス化する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function getPdoInstance() { try{ $pdo = new PDO('sqlite:./test.db'); // PDOの引数に(sqlite:データベースのパス)で指定する $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // エラーが起きた時例外を投げる $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ); // 連想配列形式でデータを取得する $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); // 指定した型に合わせる return $pdo; }catch(PDOException $e){ //echo $e->getMessage(); exit('エラーが発生しました'); } } $pdo = getPdoInstance(); |
PDOクラスの引数にデータベースファイルが置いてあるパスを指定します。これでデータベースの接続は完了です。必要に応じてsetAttributeメソッドで属性をセットします。今回は3つ属性をセットしました。
queryメソッドを使用して必要なデータを取得する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
function getDb($pdo) { $stmt = $pdo->query("SELECT i1.name ,i1.score ,(SELECT count(i2.score) FROM test i2 WHERE i1.score < i2.score) + 1 AS rank FROM test i1 WHERE rank <= 3 ORDER BY rank"); $stmts = $stmt->fetchAll(); return $stmts; } $json = getDb($pdo); $data=json_encode($json); echo $data; |
相関サブクエリを使い順位を付けて並べ替え上位3位までをfetchAllメソッドでデータを取得しています。取得したデータはjson_encodeメソッドでjson形式にエンコードしています。
JavaScriptのFetch APIを使ってサーバーにリクエストする
先ほどPHPで作成したjsonをJavaScriptのFetchAPIを使用して取得します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
let lastScore; // 3位のスコアを保持する変数 function fetchRanking() { return fetch("./ranking.php") .then((response) => response.json()) .then((data) => { if (Object.keys(data).length === 0) { lastScore = 0; } else { lastScore = data[Object.keys(data).sort().pop()].score; } return data; }) .catch((error) => { console.log(error); return; }); } |
変数lastScoreに取得した上位3位までのデータ中一番低いスコアを保持して、ゲーム終了時のスコア比較に使用します。
ランキング入賞時の処理
スコアを比較して上位3位に入っていた時のみサーバーへリクエストするようにしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
function sendRanking(score) { if(isNaN(score)) return; if (score <= lastScore) { const fd = new FormData(); const name = prompt( "おめでとうございます!TOP3にランクインしました!", "名前を入力してください(8文字以内・省略可)" ); if (!name) return; fd.append("name", name); fd.append("score", score); fetch("./ranking.php", { method: "POST", body: fd, }).catch((error) => { console.log(error); }); } } |
PHPのPDOを使ってデータを追加する
JavaScriptからリクエストされたデータをprepareメソッドを使いクエリを送信して追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
if($_SERVER['REQUEST_METHOD'] === 'POST') { $score = filter_input(INPUT_POST, 'score'); $name = trim(filter_input(INPUT_POST, 'name')); if($name === '' || $name === 'null' || mb_strlen($name) > 8){ $name = '名無しさん'; } $stmt = $pdo->prepare("INSERT INTO test (name, score) VALUES (:name, :score)"); $stmt->bindValue('name', $name, PDO::PARAM_STR); $stmt->bindValue('score', $score, PDO::PARAM_STR); $stmt->execute(); exit; } |
クライアント側でスコアを保持している為の不具合
この記事のランキング実装方法ではブラウザの開発者ツール等を使いランキングに入賞できてしまうことが解かりました。続きは↓の記事になります。
最後までお読みいただきありがとうございました。
サンプルのソースコードはgithubにあります。