Webbserverprogrammering 1

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)
<?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());
}
?>