federator/php/api.php
2024-07-17 21:37:02 +02:00

271 lines
7.2 KiB
PHP

<?php
/**
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
* SPDX-License-Identifier: GPL-3.0-or-later
*
* @author Sascha Nitsch (grumpydeveloper)
**/
namespace Federator;
/**
* main API class
*/
class Api extends Main
{
/**
* called path
*
* @var string $path
*/
private $path;
/**
* path elements for the API call
*
* @var array<string> $paths
* */
private $paths;
/**
* current user
*
* @var Data\User|false $user
* */
private $user;
/**
* cache time default to 0
*
* @var int $cacheTime
*/
private $cacheTime = 0;
/**
* constructor
*/
public function __construct()
{
$this->smarty = null;
$this->contentType = "application/json";
Main::__construct();
}
/**
* set path
*
* @param string $call
* path of called function
* @return void
*/
public function setPath($call)
{
$this->path = $call;
while ($this->path[0] === '/') {
$this->path = substr($this->path, 1);
}
$this->paths = explode("/", $this->path);
}
/**
* main API function
*/
public function run() : void
{
$this->setPath((string)$_REQUEST['_call']);
$this->openDatabase();
$this->loadPlugins();
$retval = "";
$handler = null;
if (!array_key_exists('HTTP_X_SESSION', $_SERVER) || !array_key_exists('HTTP_X_PROFILE', $_SERVER)) {
http_response_code(403);
return;
}
if ($this->connector === null) {
http_response_code(500);
return;
}
$this->user = DIO\User::getUserBySession(
$this->dbh,
$_SERVER['HTTP_X_SESSION'],
$_SERVER['HTTP_X_PROFILE'],
$this->connector,
$this->cache
);
if ($this->user === false) {
http_response_code(403);
return;
}
switch ($this->path[0]) {
case 'v':
if ($this->paths[0] === "v1") {
switch ($this->paths[1]) {
case 'dummy':
$handler = new Api\V1\Dummy($this);
break;
}
}
break;
}
$printresponse = true;
if ($handler !== null) {
try {
$printresponse = $handler->exec($this->paths);
if ($printresponse) {
$retval = $handler->toJson();
}
} catch (Exceptions\Exception $e) {
$this->setResponseCode($e->getRetCode());
$retval = json_encode(array(
"error" => $e->getMessage()
));
}
} else {
$this->responseCode = 404;
}
if (sizeof($this->headers) != 0) {
foreach ($this->headers as $name => $value) {
header($name . ': ' . $value);
}
}
if ($printresponse) {
if ($this->redirect !== null) {
header("Location: $this->redirect");
}
// @phan-suppress-next-line PhanSuspiciousValueComparison
if ($this->responseCode != 200) {
http_response_code($this->responseCode);
}
if ($this->responseCode != 404) {
header("Content-type: " . $this->contentType);
header("Access-Control-Allow-Origin: *");
}
if ($this->cacheTime == 0) {
header("Cache-Control: no-cache, no-store, must-revalidate");
header("Pragma: no-cache");
header("Expires: 0");
} else {
$ts = gmdate("D, d M Y H:i:s", time() + $this->cacheTime) . " GMT";
header("Expires: $ts");
header("Pragma: cache");
header("Cache-Control: max-age=" . $this->cacheTime);
}
echo $retval;
} else {
if (!headers_sent()) {
header("Content-type: " . $this->contentType);
}
}
}
/**
* check if the current user has the given permission
*
* @param string|string[] $permission
* permission(s) to check for
* @param string $exception Exception Type
* @param string $message optional message
* @throws Exceptions\PermissionDenied
*/
public function checkPermission($permission, $exception = "\Exceptions\PermissionDenied", $message = null) : void
{
// generic check first
if ($this->user === false) {
throw new Exceptions\PermissionDenied();
}
if ($this->user->id == 0) {
throw new Exceptions\PermissionDenied();
}
if (!is_array($permission)) {
$permission = array(
$permission
);
}
// LoggedIn is handled above
foreach ($permission as $p) {
if ($this->user->hasPermission($p)) {
return;
}
}
throw new $exception($message);
}
/**
* remove unwanted elements from html input
*
* @param string $_input
* input to strip
* @return string stripped input
*/
public static function stripHTML(string $_input) : string
{
$out = preg_replace('/<(script[^>]*)>/i', '&lt;${1}&gt;', $_input);
$out = preg_replace('/<\/(script)>/i', '&lt;/${1};&gt;', $out);
return $out;
}
/**
* is given parameter in POST data
*
* @param string $_key
* parameter to check
* @return bool true if in
*/
public static function hasPost(string $_key) : bool
{
return array_key_exists($_key, $_POST);
}
/**
* SQL escape given POST parameter
*
* @param string $key
* key to escape
* @param boolean $int
* is parameter an int
* @return int|string
*/
public function escapePost(string $key, $int = false)
{
if (! array_key_exists($key, $_POST)) {
return $int ? 0 : "";
}
if ($int === true) {
return intval($_POST[$key]);
}
$ret = $this->dbh->escape_string($this->stripHTML((string)$_POST[$key]));
return $ret;
}
/**
* update $data with POST info using optional alias $altName
*
* @param string $name
* parameter name
* @param array<string, mixed> $data
* array to update
* @param bool $int
* is data an integer
* @param string $altName
* optional alternative name in POST
* @return void
*/
public function updateString($name, &$data, $int = false, $altName = "")
{
if ($this->hasPost($altName ?: $name)) {
$content = $this->escapePost($altName ?: $name, $int);
$data[$name] = $content;
}
}
/**
* set cache time
*
* @param int $time time in seconds
* @return void
*/
public function setCacheTime($time)
{
$this->cacheTime = $time;
}
}