MaketRandevu/application/libraries/Api.php

261 lines
6.3 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php use JetBrains\PhpStorm\NoReturn;
defined('BASEPATH') or exit('No direct script access allowed');
/* ----------------------------------------------------------------------------
* MaketRandevu - MAKET Randevu Portalı
*
* @package EasyAppointments
* @author A.Tselegidis <alextselegidis@gmail.com>
* @copyright Copyright (c) Alex Tselegidis
* @license https://opensource.org/licenses/GPL-3.0 - GPLv3
* @link https://easyappointments.org
* @since v1.5.0
* ---------------------------------------------------------------------------- */
/**
* Api library.
*
* Handles API related functionality.
*
* @package Libraries
*/
class Api
{
/**
* @var EA_Controller|CI_Controller
*/
protected EA_Controller|CI_Controller $CI;
/**
* @var int
*/
protected int $default_length = 20;
/**
* @var EA_Model
*/
protected EA_Model $model;
/**
* Api constructor.
*/
public function __construct()
{
$this->CI = &get_instance();
$this->CI->load->library('accounts');
}
/**
* Load and use the provided model class.
*
* @param string $model
*/
public function model(string $model): void
{
$this->CI->load->model($model);
$this->model = $this->CI->{$model};
}
/**
* Authorize the API request (Basic Auth or Bearer Token supported).
*/
public function auth(): void
{
try {
// Bearer token.
$api_token = setting('api_token');
if (!empty($api_token) && $api_token === $this->get_bearer_token()) {
return;
}
// Basic auth.
$username = $_SERVER['PHP_AUTH_USER'] ?? null;
$password = $_SERVER['PHP_AUTH_PW'] ?? null;
$user_data = $this->CI->accounts->check_login($username, $password);
if (empty($user_data['role_slug']) || $user_data['role_slug'] !== DB_SLUG_ADMIN) {
throw new RuntimeException(
'The provided credentials do not match any admin user!',
401,
'Unauthorized',
);
}
} catch (Throwable) {
$this->request_authentication();
}
}
/**
* Returns the bearer token value.
*
* @return string|null
*/
protected function get_bearer_token(): ?string
{
$headers = $this->get_authorization_header();
// HEADER: Get the access token from the header
if (!empty($headers)) {
if (preg_match('/Bearer\s(\S+)/', $headers, $matches)) {
return $matches[1];
}
}
return null;
}
/**
* Returns the authorization header.
*
* @return string|null
*/
protected function get_authorization_header(): ?string
{
$headers = null;
if (isset($_SERVER['Authorization'])) {
$headers = trim($_SERVER['Authorization']);
} else {
if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
// Nginx or fast CGI
$headers = trim($_SERVER['HTTP_AUTHORIZATION']);
} elseif (function_exists('apache_request_headers')) {
$requestHeaders = apache_request_headers();
// Server-side fix for bug in old Android versions (a nice side effect of this fix means we don't care
// about capitalization for Authorization).
$requestHeaders = array_combine(
array_map('ucwords', array_keys($requestHeaders)),
array_values($requestHeaders),
);
if (isset($requestHeaders['Authorization'])) {
$headers = trim($requestHeaders['Authorization']);
}
}
}
return $headers;
}
/**
* Sets request authentication headers.
*/
#[NoReturn]
public function request_authentication(): void
{
header('WWW-Authenticate: Basic realm="Easy!Appointments"');
header('HTTP/1.0 401 Unauthorized');
exit('You are not authorized to use the API.');
}
/**
* Get the search keyword value of the current request.
*
* @return string|null
*/
public function request_keyword(): ?string
{
return request('q');
}
/**
* Get the limit value of the current request.
*
* @return int|null
*/
public function request_limit(): ?int
{
return request('length', $this->default_length);
}
/**
* Get the limit value of the current request.
*
* @return int|null
*/
public function request_offset(): ?int
{
$page = request('page', 1);
$length = request('length', $this->default_length);
return ($page - 1) * $length;
}
/**
* Get the order by value of the current request.
*
* @return string|null
*/
public function request_order_by(): ?string
{
$sort = request('sort');
if (!$sort) {
return null;
}
$sort_tokens = array_map('trim', explode(',', $sort));
$order_by = [];
foreach ($sort_tokens as $sort_token) {
$api_field = substr($sort_token, 1);
$direction_operator = substr($sort_token, 0, 1);
if (!in_array($direction_operator, ['-', '+'])) {
$direction_operator = '+';
$api_field = $sort_token;
}
$db_field = $this->model->db_field($api_field);
$direction = $direction_operator === '-' ? 'DESC' : 'ASC';
$order_by[] = $db_field . ' ' . $direction;
}
return implode(', ', $order_by);
}
/**
* Get the chosen "fields" array of the current request.
*
* @return array|null
*/
public function request_fields(): ?array
{
$fields = request('fields');
if (!$fields) {
return null;
}
return array_map('trim', explode(',', $fields));
}
/**
* Get the provided "with" array of the current request.
*
* @return array|null
*/
public function request_with(): ?array
{
$with = request('with');
if (!$with) {
return null;
}
return array_map('trim', explode(',', $with));
}
}