Show sourcecode
The following files exists in this folder. Click to view.
webbsrvprg/exercises/slutprojekt/
actions.php
administer_users.php
create_code.php
database_include.php
dbconnection.php
index.php
login copy.php
login.php
main.php
password_renewals.php
play copy.php
play.php
setup.php
sign_up.php
statistics.php
verification.php
verify_mail.php
actions.php
434 lines UTF-8 Windows (CRLF)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
<?php
// Denna sida anropas av de andra för att kontakta databasen $_GET["action"] beskriver vad som ska utföras
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
session_start(["gc_maxlifetime" => 86400]);
?>
<?php
if (!isset($_GET["action"])) {
exit(); // Om den inte är satt finns ingenting att göra
}
function getTime()
{
// php's time är två timmar bakom Sverige så justerar
return (time() + 2 * 3600);
}
function generatePlacements(): string
{
$GAMEWIDTH = 5; // Måste också justeras i play.php
$GAMEHEIGHT = 5;
$SHIPCOUNT = 5; // En-pixels-skepp
$placings = [];
while (count($placings) < $SHIPCOUNT) {
$x = rand(0, $GAMEWIDTH - 1);
$y = rand(0, $GAMEHEIGHT - 1);
$coord = "$x,$y";
if (!isset($placings[$coord])) {
$placings[$coord] = [$x, $y];
}
}
$json = json_encode($placings); // Gör om till sträng som sen kan sparas i tabellen och tolkas överallt
return ($json);
}
$action = $_GET["action"]; // Används för att ta reda på vad som ska göras
$user_id = $_SESSION["user_id"];
try {
include("dbconnection.php");
/** @var PDO $dbconn */
// Skapar variabeln $user_id i nästan varje men kan inte göra det utanför för då blir check_username paj
if ($action == "CHECKIN") {
$sql = "UPDATE bs_users SET last_checkin = NOW() WHERE id = ?";
$stmt = $dbconn->prepare($sql);
$data = [$user_id];
$stmt->execute($data);
} else if ($action == "EXIT_QUE") {
$sql = "DELETE FROM bs_que WHERE user_id = ?";
$stmt = $dbconn->prepare($sql);
$data = [$user_id];
$stmt->execute($data);
} else if ($action == "ENTER_QUE") {
// Börjar med att plocka bort que-entries där användaren inte checkat in på 12s plus ens egna gamla.
$sql = 'DELETE FROM bs_que
WHERE user_id = ? OR last_checkin < (NOW() - INTERVAL 12 SECOND)';
$stmt = $dbconn->prepare($sql);
$data = [$user_id];
$stmt->execute($data);
// Scope bör vara satt men säkerhet
if (isset($_GET["scope"])) {
$scope = $_GET["scope"];
} else {
$scope = "ALL";
}
if ($scope == "ALL") {
// Alla som söker till "ALL" eller är vän med dig. Plockar bara första posten.
$sql = 'SELECT *
FROM bs_que
WHERE scope="ALL"
OR EXISTS (
SELECT 1
FROM bs_relations
WHERE bs_relations.id_1 = bs_que.user_id
AND bs_relations.id_2 = ?)
ORDER BY bs_que.id ASC
LIMIT 1';
} else { // $scope == "FRIENDS"
// Tar bara de där den som söker är vän med en. Plockar bara första posten.
$sql = 'SELECT *
FROM bs_que
WHERE EXISTS (
SELECT 1
FROM bs_relations
WHERE bs_relations.id_1 = bs_que.user_id
AND bs_relations.id_2 = ?)
ORDER BY bs_que.id ASC
LIMIT 1';
}
$data = [$user_id];
$stmt = $dbconn->prepare($sql);
$stmt->execute($data);
$game = $stmt->fetch(PDO::FETCH_ASSOC);
if ($game) { // Om en match hittades
// Tar bort den matchen ur que'n
$sql = 'DELETE FROM bs_que WHERE id = ?';
$stmt = $dbconn->prepare($sql);
$data = [$game["id"]];
$stmt->execute($data);
$user_1_placements = generatePlacements();
$user_2_placements = generatePlacements();
$user_1_id = $_SESSION["user_id"];
$user_2_id = $game["user_id"];
// Slumpar vem som startar
if (rand(0, 1) === 0) {
$turn = $user_1_id;
} else {
$turn = $user_2_id;
}
$sql = 'INSERT INTO bs_ongoing (user_1_id, user_2_id, user_1_placements, user_2_placements, turn) VALUES (?,?,?,?,?)';
$stmt = $dbconn->prepare($sql);
$data = [$user_1_id, $user_2_id, $user_1_placements, $user_2_placements, $turn];
$stmt->execute($data);
} else {
// Ställer sig i kön om man inte redan är i en match för säkerhet
// Udda INSERT-kommando men SELECT plockar fram de värden man vill ha om den inte finns i current_games
$sql = "
INSERT INTO bs_que (user_id, scope)
SELECT ?, ?
WHERE NOT EXISTS (
SELECT 1
FROM bs_ongoing
WHERE user_1_id = ? OR user_2_id = ?
)";
$stmt = $dbconn->prepare($sql);
$data = [$user_id, $scope, $user_id, $user_id];
$stmt->execute($data);
}
} else if ($action == "GET_FRIENDS") {
// Tar fram de som är online (checkat in mindre än en minut sen)
// Tar även de friend requests man fått.
$sql = "SELECT * FROM bs_relations JOIN bs_users ON bs_relations.id_2 = bs_users.id WHERE bs_relations.id_1=? AND bs_users.last_checkin > NOW() - INTERVAL 1 MINUTE";
$stmt = $dbconn->prepare($sql);
$data = [$user_id];
$stmt->execute($data);
$online = [];
while ($online_friend = $stmt->fetch(PDO::FETCH_ASSOC)) {
$online[] = $online_friend["username"];
}
// Tar fram de som inte är online (checkat in längre än en minut sen)
$sql = "SELECT * FROM bs_relations JOIN bs_users ON bs_relations.id_2 = bs_users.id WHERE bs_relations.id_1=? AND bs_users.last_checkin <= NOW() - INTERVAL 1 MINUTE";
$stmt = $dbconn->prepare($sql);
$data = [$user_id];
$stmt->execute($data);
$offline = [];
while ($offline_friend = $stmt->fetch(PDO::FETCH_ASSOC)) {
$offline[] = $offline_friend["username"];
}
// Tar fram de vänförfrågningar man har
$sql = "SELECT bs_users.id, bs_users.username FROM bs_friend_requests JOIN bs_users ON bs_friend_requests.user_1_id = bs_users.id WHERE bs_friend_requests.user_2_id=?";
$stmt = $dbconn->prepare($sql);
$data = [$user_id];
$stmt->execute($data);
$pending = [];
while ($request = $stmt->fetch(PDO::FETCH_ASSOC)) {
$pending[] = [$request["id"], $request["username"]];
}
// Vet inte riktigt hur detta fungerar men då kan jag tolka det som en array
header('Content-Type: application/json; charset=utf-8');
echo json_encode([
"online" => $online,
"offline" => $offline,
"pending" => $pending
]);
} else if ($action == "CHECK_USERNAME") {
// Kollar om ett användarnamn är upptaget samt städar i tabellen.
// Tar bort gamla overifierade konton så att de inte tar onödig plats och tar upp användarnamn
$sql = "DELETE FROM bs_users WHERE verified = 0 AND last_checkin < NOW() - INTERVAL 15 MINUTE";
$dbconn->exec($sql);
// Kollar om användarnamnet är upptaget
$username = $_GET["username"]; // Man behöver ha angett ett username
$sql = "SELECT 1 FROM bs_users WHERE username = ?";
$stmt = $dbconn->prepare($sql);
$data = [$username];
$stmt->execute($data);
if ($stmt->fetchColumn()) {
echo ("taken");
} else {
echo ("free");
}
} else if ($action == "UPDATE_QUE_STATUS") {
// Förnyar ens eventuella last_checkin
$sql = "UPDATE bs_que SET last_checkin = NOW() WHERE user_id = ?";
$stmt = $dbconn->prepare($sql);
$data = [$user_id];
$stmt->execute($data);
// Kollar om man är i kö, vad man är i för kö och ifall man är i en match
$sql = "SELECT scope FROM bs_que WHERE user_id = ? LIMIT 1";
$stmt = $dbconn->prepare($sql);
$data = [$user_id];
$stmt->execute($data);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row) {
// Om man är i kön så får man sitt scope
echo ($row["scope"]);
} else {
$sql = "SELECT id FROM bs_ongoing WHERE user_1_id = ? OR user_2_id = ? LIMIT 1";
$stmt = $dbconn->prepare($sql);
$data = [$user_id, $user_id];
$stmt->execute($data);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row) {
// Om man är i en match
echo ($row["id"]);
}
}
// Om man inte är i varken kön eller en match returneras ingenting.
} else if ($action == "SHOOT") {
// Gjord av AI men kontrollerad, justerad och kommenterad
$game_id = $_GET["game_id"];
$x = $_GET["x"];
$y = $_GET["y"];
$coord = "$x,$y"; // !!STRÄNG!!
$stmt = $dbconn->prepare("SELECT * FROM bs_ongoing WHERE id=?");
$data = [$game_id];
$stmt->execute($data);
$game = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$game) {
exit;
} // Om den matchen inte finns
if ($game["turn"] != $user_id) {
exit;
} // Om det inte är ens tur (sorterar bort försök att försöka skjuta i andras matcher också)
// Blockera dubbelskott
$stmt = $dbconn->prepare("SELECT 1 FROM bs_moves WHERE game_id=? AND target=? AND user_id=?");
$data = [$game_id, $coord, $user_id];
$stmt->execute($data);
if ($stmt->fetch()) {
exit;
}
// Hitta fiende och dess placements
if ($user_id == $game["user_1_id"]) {
$enemy_id = $game["user_2_id"];
$placements = json_decode($game["user_2_placements"], true); // En array (tror jag det heter i php) med coords som keys
} else {
$enemy_id = $game["user_1_id"];
$placements = json_decode($game["user_1_placements"], true);
}
$hit = isset($placements[$coord]) ? 1 : 0;
$stmt = $dbconn->prepare("INSERT INTO bs_moves (game_id,user_id,target,hit)
VALUES (?,?,?,?)");
$data = [$game_id, $user_id, $coord, $hit];
$stmt->execute($data);
// Kollar om man vunnit
$stmt = $dbconn->prepare("SELECT COUNT(*) FROM bs_moves
WHERE game_id=? AND user_id=? AND hit=1"); // Kollar hur många träffar man har
$data = [$game_id, $user_id];
$stmt->execute($data);
if ($stmt->fetchColumn() >= 5) {
$sql = "INSERT INTO bs_logs
(user_1_id, user_2_id, winner, user_1_placements, user_2_placements, game_id)
VALUES (?,?,?,?,?,?)";
$stmt = $dbconn->prepare($sql);
$data = [
$game["user_1_id"],
$game["user_2_id"],
$user_id,
$game["user_1_placements"],
$game["user_2_placements"],
$game_id
];
$stmt->execute($data);
$sql = "DELETE FROM bs_ongoing WHERE id=?";
$stmt = $dbconn->prepare($sql);
$data = [$game_id];
$stmt->execute($data);
// exit;
}
// Byt tur
$next = ($user_id == $game["user_1_id"])
? $game["user_2_id"]
: $game["user_1_id"];
$stmt = $dbconn->prepare("UPDATE bs_ongoing SET turn=? WHERE id=?");
$data = [$next, $game_id];
$stmt->execute($data);
} else if ($action == "GET_GAME") {
// AI-gjord men kontrollerad, justerad och kommenterad
$game_id = $_GET["game_id"];
$stmt = $dbconn->prepare("SELECT * FROM bs_ongoing WHERE id=?");
$data = [$game_id];
$stmt->execute([$game_id]);
$game = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$game) {
$sql = "SELECT winner FROM bs_logs WHERE game_id=?";
$stmt = $dbconn->prepare($sql);
$stmt->execute($data); // data nyss satt rätt
$row = $stmt->fetch(PDO::FETCH_ASSOC); // Borde kanske ha fetchColumn
$winner = $row ? $row["winner"] : null;
// Om matchen inte finns är den slut
echo json_encode([ // Fattar inte riktigt hur json fungerar men smidigt
"game_over" => true,
"winner" => $winner, // Hämtat ur loggen
"reason" => "win" // Till skillnad från timeout
]);
exit;
}
// Timeout. Man förlorar om man inte gjort ett drag på 20s
$sql = "SELECT created FROM bs_moves WHERE game_id=? ORDER BY created DESC LIMIT 1";
$stmt = $dbconn->prepare($sql);
$data = [$game_id];
$stmt->execute($data);
$last = $stmt->fetchColumn(); // Sista draget som gjorts
$sql = "SELECT started FROM bs_ongoing WHERE id=?";
$stmt = $dbconn->prepare($sql);
// $data = [$game_id]; // Redan satt
$stmt->execute($data);
$started = $stmt->fetchColumn();
if (($last && strtotime($last) < getTime() - 20) || (!$last && strtotime($started) < getTime() - 30)) {
// Om det funnits tidigare drag och det är längre än 20s sen dessa eller om det inte funnits tidigare och mer än 30s från start.
$loser = $game["turn"];
$winner = ($loser == $game["user_1_id"])
? $game["user_2_id"]
: $game["user_1_id"];
$sql = "INSERT INTO bs_logs
(user_1_id, user_2_id ,winner, user_1_placements, user_2_placements, game_id)
VALUES (?,?,?,?,?,?)";
$stmt = $dbconn->prepare($sql);
$data = [
$game["user_1_id"],
$game["user_2_id"],
$winner,
$game["user_1_placements"],
$game["user_2_placements"],
$game_id
];
$stmt->execute($data);
$sql = "DELETE FROM bs_ongoing WHERE id=?";
$stmt = $dbconn->prepare($sql);
$data = [$game_id];
$stmt->execute($data);
echo json_encode([
"game_over" => true,
"winner" => $winner,
"reason" => "timeout",
]);
exit;
}
// Moves
$stmt = $dbconn->prepare("SELECT * FROM bs_moves WHERE game_id=?");
$data = [$game_id];
$stmt->execute($data);
$moves = [];
while ($move = $stmt->fetch(PDO::FETCH_ASSOC)) {
list($x, $y) = explode(",", $move["target"]);
$moves[] = [
"x" => $x,
"y" => $y,
"hit" => $move["hit"],
"user_id" => $move["user_id"]
];
}
header('Content-Type: application/json');
echo json_encode([
"turn" => $game["turn"],
"moves" => $moves,
"user_1_id" => $game["user_1_id"],
"user_1_placements" => $game["user_1_placements"],
"user_2_placements" => $game["user_2_placements"],
"game_over" => false
]);
} else if ($action == "ANSWER_FRIEND_REQUEST") {
$id = $_GET["id"]; // id't på användaren som skickade requesten.
$answer = $_GET["answer"];
// $user_id är ens EGNA id.
// Tar bort requesten (Alla likadana om man har skickat dubletter)
$sql = "DELETE FROM bs_friend_requests WHERE user_1_id = ? AND user_2_id = ?";
$stmt = $dbconn->prepare($sql);
$data = [$id, $user_id];
$stmt->execute($data);
if($answer == 1){
// Skapar två speglade relationer om man tackar ja och om relationen inte redan finns
$sql = "INSERT IGNORE INTO bs_relations (id_1, id_2) VALUES (?, ?)";
$stmt = $dbconn->prepare($sql);
$stmt->execute([$user_id, $id]);
$sql = "INSERT IGNORE INTO bs_relations (id_1, id_2) VALUES (?, ?)";
$stmt = $dbconn->prepare($sql);
$stmt->execute([$id, $user_id]);
}
}
} catch (PDOException $e) {
echo($e->getMessage());
}
?>