Sixtens hemsida Uppgifter Blogg Om

VED House bokningssystem

Gå till sida

Källkod

api/

database.php

api.php

ved/

monthBookingData.php

openingHoursException.php

bookingData.php

dayTimeframes.php

bookings.php

admin/

revokeToken.php

authorization.php

login.php

modules/

vedDatabase.php

utility.php

gyar/

log.php

auth/

revokeToken.php

authorization.php

login.php

station/

settings.php

log.php

modules/

gyarDatabase.php

databaseConnection.php

database.php

utility.php

credentials.json

weather/

latest.php

old.php

admin/

index.html

changeTimetable.html

login.html

js/

login.js

modules.js

admin.js

header.js

changeTimetable.js

cron/

vedClearExpiredTokens.php

api/api.php

1 lines
<?php
# api.php
# Fil som sköter alla request till APIn.
# Leds hit av routerkod ifall sökvägen börjar med https://als070804sn.hemsida.eu/api

# Klass som definierar en API endpoint. Varje API PHP fil har en APIEndpoint som returnas.
class APIEndpoint
{
    public 
$apiMethods = array();
    
# Kopplar en APIMethod till APIEndpoint.
    
public function addMethod($apiMethod)
    {
        
$methodName strtoupper($apiMethod->method);
        if (isset(
$this->apiMethods[$methodName]))
            throw new 
APIError(500"Multiple functions for {$methodName} method.");
        
$this->apiMethods[$methodName] = $apiMethod;
    }

    
# Kör själva API endpointen.
    
public function run()
    {
        
$methodName strtoupper($_SERVER["REQUEST_METHOD"]);
        if (!isset(
$this->apiMethods[$methodName])) {
            throw new 
APIError(405"{$methodName} method is not allowed.");
        }
        
$this->apiMethods[$methodName]->run();
    }
}

# Klass som definierar en metod för en APIEndpoint.
# Syftar på HTTP methods (GET, POST, etc.)
class APIMethod
{
    public 
$method# String, vilket slags HTTP method.
    
public $apiFunction# Själva funktionen som ska köras.

    
private $requiredGETParameters# Bestämmer nödvändiga _GET parametrar.
    
private $requiredBodyParameters# Bestämmer nödvändiga _POST parametrar.
    
private $authorizationFunction# Valfri funktion som kollar Authorization headern.

    
public function __construct($method$apiFunction)
    {
        
$this->method $method;
        
$this->apiFunction $apiFunction;
    }

    public function 
setRequiredGETParameters($parameters)
    {
        
$this->requiredGETParameters $parameters;
    }

    public function 
setRequiredBodyParameters($parameters)
    {
        
$this->requiredBodyParameters $parameters;
    }

    
# DEPRECATED
    
public function setAuthorization($authorizationFunction)
    {
        
$this->authorizationFunction $authorizationFunction;
    }

    
# Privat funktion, körs när APIMethod->run körs.
    # Kontrollerar ifall nödvändiga parametrar finns med.
    
private function checkParameters($requiredParameters$parameters$parametersName)
    {
        
# $requiredParameters är APIMethod->$requiredGETParameters eller APIMethod->$requiredBodyParameters.
        # $parameters är $_GET eller $_POST.
        # $parametersName är gruppnamnet för parametrarna, "get" eller "body".
        
if (!isset($requiredParameters))
            return;
        
$missingParameters = array();
        foreach (
$requiredParameters as $parameter) {
            if (!isset(
$parameters[$parameter]))
                
array_push($missingParameters$parameter);
        }
        if (
sizeof($missingParameters) > 0) {
            throw new 
APIParameterError(400$missingParameters"Missing required {$parametersName} parameters.");
        }
    }

    
# Privat funktion som kontrollerar authorization header.
    # DEPRECATED
    
private function checkAuthorization()
    {
        if (!isset(
$this->authorizationFunction)) # Kollar ifall API metoden kräven en auth-funktion.
            
return;
        
$headers getallheaders();
        if (!isset(
$headers["Authorization"]))
            throw new 
APIError(401"Invalid authorization.");
        
$authData explode(" "$headers["Authorization"]);
        if (
sizeof($authData) != 2)
            throw new 
APIError(401"Invalid authorization.");
        
$authType $authData[0];
        
$authToken $authData[1];
        (
$this->authorizationFunction)($authType$authToken); # Här körs själva funktionen.
    
}

    
# Kör API metoden. Orsakas av APIEndpoint->run
    
public function run()
    {
        
$this->checkAuthorization(); # Kontrollerar authorization.

        
$_POST json_decode(file_get_contents("php://input"), true); # Krävs om inte formulär används för att skicka body data.
        # Här kontrolleras eventuella parametrar.
        
$this->checkParameters($this->requiredGETParameters$_GET"GET");
        
$this->checkParameters($this->requiredBodyParameters$_POST"body");

        if (!isset(
$this->apiFunction)) { # Kontrollerar och kör huvudfunktionen för API metoden.
            
echo "{}";
            return;
        }
        
$result = ($this->apiFunction)();

        
ini_set('serialize_precision', -1);
        echo 
json_encode($resultJSON_UNESCAPED_UNICODE);
    }
}

# En slags exception som har med sig en HTTP error code och ett meddelande.
class APIError extends Exception
{
    public 
$errorCode;
    public 
$errorMessage;
    public function 
__construct($code$errorMessage)
    {
        
$this->errorCode $code;
        
$this->errorMessage $errorMessage;
    }
}

# Utökning av APIError, fast tar med en eller flera parametrar.
# Använd om en parameter är felformulerad eller på annat vis ogiltig.
class APIParameterError extends APIError
{
    public 
$parameter;
    public function 
__construct($code$parameter$errorMessage "Invalid parameter.")
    {
        
$this->errorCode $code;
        
$this->parameter $parameter;
        
$this->errorMessage $errorMessage;
    }
}

header("Content-Type: application/json; charset=utf-8"); # Ser till att klienten förstår vad för slags data det är.
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type");

# Kodbit jag hittade online för att se till att alla varningar blir exceptions.
# Används eftersom PHP skriver annars ut varningar, vilket inte funkar när man vill att output ska vara i json-format.
set_error_handler(function ($errno$errstr$errfile$errline) {
    
// error was suppressed with the @-operator
    
if (=== error_reporting())
        return 
false;
    throw new 
ErrorException($errstr0$errno$errfile$errline);
});

# Hämtar filsökvägen till php-filen
function get_api_path()
{
    
$pathString parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
    
$pathArray explode("/"$pathString);
    
$pathArray array_filter($pathArray, function ($value) {
        return 
$value !== "";
    });
    
array_shift($pathArray); # Tar bort "api/" i början.
    
return implode("/"$pathArray) . ".php";
}

try {
    
$path get_api_path();
    if (!
file_exists("{$path}"))
        throw new 
APIError(404"API endpoint not found.");
    
$endpoint = require $path# Hämtar eventuell APIEndpoint instans från filen.
    
if ($endpoint::class != "APIEndpoint")
        throw new 
APIError(404"API endpoint not found.");

    
$endpoint->run(); # Kör API endpointen
    # Praktiskt sätt hela filen körs inom en try för att undvika att PHP skriver ut något slags felmeddelande.
} catch (APIParameterError $ex) {
    
# Först fångas en APIParameterError
    
http_response_code($ex->errorCode);

    
$response = [];
    
$parameter $ex->parameter;
    if (
gettype($parameter) == "array")
        
$parameter implode(","$parameter);
    
$response["parameter"] = $parameter;
    
$response["error"] = $ex->errorMessage;
    echo 
json_encode($response);
} catch (
APIError $ex) {
    
# Sedan generella APIErrors
    
http_response_code($ex->errorCode);
    
$response = [];
    
$response["error"] = $ex->errorMessage;
    echo 
json_encode($response);
} catch (
Exception Error $ex) {
    
# Till sist om något oförväntat gick fel skrivs en 500 Internal Server Error ut.
    
http_response_code(500);
    
$response = [];

    
$debug true;
    if (
$debug)
        
$response["error"] = "Internal server error: {$ex->getMessage()} - {$ex->getFile()}{$ex->getLine()}";
    else
        
$response["error"] = "Internal server error.";
    echo 
json_encode($response);
}

?>