api/
ved/
admin/
modules/
gyar/
admin/
cron/
api/api.php1 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($result, JSON_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 (0 === error_reporting())
return false;
throw new ErrorException($errstr, 0, $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);
}
?>