サンプルのソースコードはgithubにあります。
概要
過去に制作したゲームの一部に上位3位までを表示するランキング機能を実装してみました。↓のゲームは3秒間にクリックした回数を競うゲームです。 3位までに入るとランキングに登録することが出来ます。クリックするとゲームが開始されます。
ランキング機能実装した過去のゲーム↓
Visual Studio Codeの拡張機能SQliteを使用してデータベースを作成する
データベースの作成にはVisual Studio Codeの拡張機能SQliteを使用しました。

テーブル名はtestにしました。テーブルの中には二つのカラムがあり、一つ目のnameカラムには名前を保持して二つ目のscoreカラムには得点や記録などを保持します。テーブルには最下位になるデータを一件追加しています。
CREATE TABLE test(name, score);
INSERT INTO test VALUES('名無しさん', '0');PHPのPDOを使ってデータベースに接続してデータを取得する
PDOクラスをインスタンス化する。
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メソッドを使用して必要なデータを取得する。
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を使用して取得します。
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位に入っていた時のみサーバーへリクエストするようにしました。
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メソッドを使いクエリを送信して追加します。
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にあります。




