first commit
Some checks failed
CI / build-test (push) Has been cancelled

This commit is contained in:
2025-05-31 18:56:37 +02:00
commit 8c4798a5fd
1240 changed files with 190468 additions and 0 deletions

View File

@@ -0,0 +1,74 @@
<?php defined('BASEPATH') or exit('No direct script access allowed');
/* ----------------------------------------------------------------------------
* Easy!Appointments - Open Source Web Scheduler
*
* @package EasyAppointments
* @author A.Tselegidis <alextselegidis@gmail.com>
* @copyright Copyright (c) 2013 - 2020, Alex Tselegidis
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @link http://easyappointments.org
* @since v1.4.0
* ---------------------------------------------------------------------------- */
if (!function_exists('is_assoc')) {
/**
* Check if an array is an associative array.
*
* @param array $array
*
* @return bool
*/
function is_assoc(array $array): bool
{
if (empty($array)) {
return false;
}
return array_keys($array) !== range(0, count($array) - 1);
}
}
if (!function_exists('array_find')) {
/**
* Find the first array element based on the provided function.
*
* @param array $array
* @param callable $callback
*
* @return mixed
*/
function array_find(array $array, callable $callback): mixed
{
if (empty($array)) {
return null;
}
if (!is_callable($callback)) {
throw new InvalidArgumentException('No filter function provided.');
}
return array_values(array_filter($array, $callback))[0] ?? null;
}
}
if (!function_exists('array_fields')) {
/**
* Keep only the provided fields of an array.
*
* @param array $array
* @param array $fields
*
* @return array
*/
function array_fields(array $array, array $fields): array
{
return array_filter(
$array,
function ($field) use ($fields) {
return in_array($field, $fields);
},
ARRAY_FILTER_USE_KEY,
);
}
}

View File

@@ -0,0 +1,40 @@
<?php defined('BASEPATH') or exit('No direct script access allowed');
/* ----------------------------------------------------------------------------
* Easy!Appointments - Online Appointment Scheduler
*
* @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.3.0
* ---------------------------------------------------------------------------- */
/**
* Assets URL helper function.
*
* This function will create an asset file URL that includes a cache busting parameter in order
* to invalidate the browser cache in case of an update.
*
* @param string $uri Relative URI (just like the one used in the base_url helper).
* @param string|null $protocol Valid URI protocol.
*
* @return string Returns the final asset URL.
*/
function asset_url(string $uri = '', ?string $protocol = null): string
{
$debug = config('debug');
$cache_busting_token = !$debug ? '?' . config('cache_busting_token') : '';
if (str_contains(basename($uri), '.js') && !str_contains(basename($uri), '.min.js') && !$debug) {
$uri = str_replace('.js', '.min.js', $uri);
}
if (str_contains(basename($uri), '.css') && !str_contains(basename($uri), '.min.css') && !$debug) {
$uri = str_replace('.css', '.min.css', $uri);
}
return base_url($uri . $cache_busting_token, $protocol);
}

View File

@@ -0,0 +1,171 @@
<?php defined('BASEPATH') or exit('No direct script access allowed');
/* ----------------------------------------------------------------------------
* Easy!Appointments - Online Appointment Scheduler
*
* @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.3.0
* ---------------------------------------------------------------------------- */
/**
* Get / set the specified config value.
*
* If an array is passed as the key, we will assume you want to set an array of values.
*
* Example "Get":
*
* $version = config('version', '1.0.0');
*
* Example "Set":
*
* config(['version' => '1.0.0']);
*
* @param array|string $key Configuration key.
* @param mixed|null $default Default value in case the requested config has no value.
*
* @return mixed|NULL Returns the requested value or NULL if you assign a new configuration value.
*
* @throws InvalidArgumentException
*/
function config(array|string $key, mixed $default = null): mixed
{
/** @var EA_Controller $CI */
$CI = &get_instance();
if (empty($key)) {
throw new InvalidArgumentException('The $key argument cannot be empty.');
}
if (is_array($key)) {
foreach ($key as $item => $value) {
$CI->config->set_item($item, $value);
}
return null;
}
$value = $CI->config->item($key);
return $value ?? $default;
}
if (!function_exists('script_vars')) {
/**
* Get / set the specified JS config value.
*
* If an array is passed as the key, we will assume you want to set an array of values.
*
* Example "Get":
*
* $version = script_vars('version', '1.0.0');
*
* Example "Set":
*
* script_vars(['version' => '1.0.0']);
*
* @param array|string|null $key Configuration key.
* @param mixed|null $default Default value in case the requested config has no value.
*
* @return mixed|NULL Returns the requested value or NULL if you assign a new configuration value.
*
* @throws InvalidArgumentException
*/
function script_vars(array|string|null $key = null, mixed $default = null): mixed
{
$script_vars = config('script_vars', []);
if (empty($key)) {
return $script_vars;
}
if (is_array($key)) {
foreach ($key as $item => $value) {
$script_vars[$item] = $value;
}
config(['script_vars' => $script_vars]);
return null;
}
$value = $script_vars[$key] ?? null;
return $value ?? $default;
}
}
if (!function_exists('html_vars')) {
/**
* Get / set the specified HTML variable.
*
* If an array is passed as the key, we will assume you want to set an array of values.
*
* Example "Get":
*
* $version = html_vars('title', 'Default Title');
*
* Example "Set":
*
* html_vars(['title' => 'Test Title']);
*
* @param array|string|null $key Variable key.
* @param mixed|null $default Default value in case the requested variable has no value.
*
* @return mixed|NULL Returns the requested value or NULL if you assign a new configuration value.
*
* @throws InvalidArgumentException
*/
function html_vars(array|string|null $key = null, mixed $default = null): mixed
{
$html_vars = config('html_vars', []);
if (empty($key)) {
return $html_vars;
}
if (is_array($key)) {
foreach ($key as $item => $value) {
$html_vars[$item] = $value;
}
config(['html_vars' => $html_vars]);
return null;
}
$value = $html_vars[$key] ?? null;
return $value ?? $default;
}
}
if (!function_exists('vars')) {
/**
* Get / set the specified HTML & JS config value.
*
* If an array is passed as the key, we will assume you want to set an array of values.
*
* Example "Get":
*
* $version = vars('version', '1.0.0');
*
* Example "Set":
*
* vars(['version' => '1.0.0']);
*
* @param array|string|null $key Configuration key.
* @param mixed|null $default Default value in case the requested config has no value.
*
* @return mixed|NULL Returns the requested value or NULL if you assign a new configuration value.
*
* @throws InvalidArgumentException
*/
function vars(array|string|null $key = null, mixed $default = null): mixed
{
return html_vars($key) ?? (script_vars($key) ?? $default);
}
}

View File

@@ -0,0 +1,162 @@
<?php defined('BASEPATH') or exit('No direct script access allowed');
/* ----------------------------------------------------------------------------
* Easy!Appointments - Open Source Web Scheduler
*
* @package EasyAppointments
* @author A.Tselegidis <alextselegidis@gmail.com>
* @copyright Copyright (c) 2013 - 2020, Alex Tselegidis
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @link http://easyappointments.org
* @since v1.4.0
* ---------------------------------------------------------------------------- */
if (!function_exists('get_date_format')) {
/**
* Get the date format based on the current settings.
*
* @return string
*/
function get_date_format(): string
{
$date_format = setting('date_format');
return match ($date_format) {
'DMY' => 'd/m/Y',
'MDY' => 'm/d/Y',
'YMD' => 'Y/m/d',
default => throw new RuntimeException('Invalid date format value: ' . $date_format),
};
}
}
if (!function_exists('get_time_format')) {
/**
* Get the time format based on the current settings.
*
* @return string
*/
function get_time_format(): string
{
$time_format = setting('time_format');
return match ($time_format) {
'military' => 'H:i',
'regular' => 'g:i a',
default => throw new RuntimeException('Invalid time format value: ' . $time_format),
};
}
}
if (!function_exists('get_date_time_format')) {
/**
* Get the date-time format based on the current settings.
*
* @return string
*/
function get_date_time_format(): string
{
return get_date_format() . ' ' . get_time_format();
}
}
if (!function_exists('format_date')) {
/**
* Format a date string based on the current app settings.
*
* @param DateTimeInterface|string $value
*
* @return string
*
* @throws Exception
*/
function format_date(DateTimeInterface|string $value): string
{
try {
$value_date_time = $value;
if (is_string($value_date_time)) {
$value_date_time = new DateTime($value);
}
return $value_date_time->format(get_date_format());
} catch (Exception $e) {
log_message('error', 'Invalid date provided to the "format_date" helper function: ' . $e->getMessage());
return 'Invalid Date';
}
}
}
if (!function_exists('format_time')) {
/**
* Format a time string based on the current app settings.
*
* @param DateTimeInterface|string $value
*
* @return string
*
* @throws Exception
*/
function format_time(DateTimeInterface|string $value): string
{
try {
$value_date_time = $value;
if (is_string($value_date_time)) {
$value_date_time = new DateTime($value);
}
return $value_date_time->format(get_time_format());
} catch (Exception $e) {
log_message('error', 'Invalid date provided to the format_time helper function: ' . $e->getMessage());
return 'Invalid Time';
}
}
}
if (!function_exists('format_date_time')) {
/**
* Format a time string based on the current app settings.
*
* @param DateTimeInterface|string $value
*
* @return string
*/
function format_date_time(DateTimeInterface|string $value): string
{
try {
$value_date_time = $value;
if (is_string($value_date_time)) {
$value_date_time = new DateTime($value);
}
return $value_date_time->format(get_date_time_format());
} catch (Exception $e) {
log_message('error', 'Invalid date provided to the format_date_time helper function: ' . $e->getMessage());
return 'Invalid Date-Time';
}
}
}
if (!function_exists('format_timezone')) {
/**
* Format a timezone string based on the current app settings.
*
* @param string $value
*
* @return string|null
*/
function format_timezone(string $value): ?string
{
/** @var EA_Controller $CI */
$CI = &get_instance();
$CI->load->library('timezones');
return $CI->timezones->get_timezone_name($value);
}
}

View File

@@ -0,0 +1,35 @@
<?php use JetBrains\PhpStorm\NoReturn;
defined('BASEPATH') or exit('No direct script access allowed');
/* ----------------------------------------------------------------------------
* Easy!Appointments - Online Appointment Scheduler
*
* @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
* ---------------------------------------------------------------------------- */
if (!function_exists('dd')) {
/**
* Output the provided variables with "var_dump" and stop the execution.
*
* Example:
*
* dd($appointment, $service, $provider, $customer);
*
* @param mixed ...$vars
*/
#[NoReturn]
function dd(...$vars): void
{
echo is_cli() ? PHP_EOL : '<pre>';
var_dump($vars);
echo is_cli() ? PHP_EOL : '</pre>';
exit(1);
}
}

View File

@@ -0,0 +1,37 @@
<?php defined('BASEPATH') or exit('No direct script access allowed');
/* ----------------------------------------------------------------------------
* Easy!Appointments - Online Appointment Scheduler
*
* @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
* ---------------------------------------------------------------------------- */
if (!function_exists('env')) {
/**
* Gets the value of an environment variable.
*
* Example:
*
* $debug = env('debug', FALSE);
*
* @param string $key Environment key.
* @param mixed|null $default Default value in case the requested variable has no value.
*
* @return mixed
*
* @throws InvalidArgumentException
*/
function env(string $key, mixed $default = null): mixed
{
if (empty($key)) {
throw new InvalidArgumentException('The $key argument cannot be empty.');
}
return $_ENV[$key] ?? $default;
}
}

View File

@@ -0,0 +1,198 @@
<?php defined('BASEPATH') or exit('No direct script access allowed');
/* ----------------------------------------------------------------------------
* Easy!Appointments - Online Appointment Scheduler
*
* @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.4.0
* ---------------------------------------------------------------------------- */
if (!function_exists('e')) {
/**
* HTML escape function for templates.
*
* Use this helper function to easily escape all the outputted HTML markup.
*
* Example:
*
* <?= e($string) ?>
*
* @param mixed $string Provide anything that can be converted to a string.
*/
function e(mixed $string): string
{
return htmlspecialchars((string) $string, ENT_QUOTES, 'UTF-8');
}
}
if (!function_exists('component')) {
/**
* Render a component from the "views/components/*.php" directory.
*
* Use this helper function to easily include components into your HTML markup.
*
* Any loaded template variables will also be available at the component template, but you may also specify
* additional values by adding values to the $params parameter.
*
* Example:
*
* echo component('timezones_dropdown', ['attributes' => 'class"form-control"'], TRUE);
*
* @param string $component Component template file name.
* @param array $vars Additional parameters for the component.
* @param bool $return Whether to return the HTML or echo it directly.
*
* @return string|object Return the HTML if the $return argument is TRUE or NULL.
*/
function component(string $component, array $vars = [], bool $return = false): string|object
{
/** @var EA_Controller $CI */
$CI = get_instance();
return $CI->load->view('components/' . $component, $vars, $return);
}
}
if (!function_exists('extend')) {
/**
* Use this function at the top of view files to mark the layout you are extending from.
*
* @param $layout
*/
function extend($layout): void
{
config([
'layout' => [
'filename' => $layout,
'sections' => [],
'tmp' => [],
],
]);
}
}
if (!function_exists('section')) {
/**
* Use this function in view files to mark the beginning and/or end of a layout section.
*
* Sections will only be used if the view file extends a layout and will be ignored otherwise.
*
* Example:
*
* <?php section('content') ?>
*
* <!-- Section Starts -->
*
* <p>This is the content of the section.</p>
*
* <!-- Section Ends -->
*
* <?php section('content') ?>
*
* @param string $name
*/
function section(string $name): void
{
$layout = config('layout');
if (array_key_exists($name, $layout['tmp'])) {
$layout['sections'][$name][] = ob_get_clean();
unset($layout['tmp'][$name]);
config(['layout' => $layout]);
return;
}
if (empty($layout['sections'][$name])) {
$layout['sections'][$name] = [];
}
$layout['tmp'][$name] = '';
config(['layout' => $layout]);
ob_start();
}
}
if (!function_exists('end_section')) {
/**
* Use this function in view files to mark the end of a layout section.
*
* Sections will only be used if the view file extends a layout and will be ignored otherwise.
*
* Example:
*
* <?php section('content') ?>
*
* <!-- Section Starts -->
*
* <p>This is the content of the section.</p>
*
* <!-- Section Ends -->
*
* <?php end_section('content') ?>
*
* @param string $name
*/
function end_section(string $name): void
{
$layout = config('layout');
if (array_key_exists($name, $layout['tmp'])) {
$layout['sections'][$name][] = ob_get_clean();
unset($layout['tmp'][$name]);
config(['layout' => $layout]);
}
}
}
if (!function_exists('slot')) {
/**
* Use this function in view files to mark a slot that sections can populate from within child templates.
*
* @param string $name
*/
function slot(string $name): void
{
$layout = config('layout');
$section = $layout['sections'][$name] ?? null;
echo '<!-- <SLOT id="' . $layout['filename'] . '/' . $name . '" /> -->' . PHP_EOL;
if (!$section) {
return;
}
foreach ($section as $content) {
echo $content;
}
}
}
if (!function_exists('pure_html')) {
/**
* Use this function in order to render HTML that comes from a text editor or similar, but strip the JS from it.
*
* @param string $markup
*
* @return string
*/
function pure_html(string $markup): string
{
$config = HTMLPurifier_Config::createDefault();
$purifier = new HTMLPurifier($config);
return $purifier->purify($markup);
}
}

View File

@@ -0,0 +1,191 @@
<?php defined('BASEPATH') or exit('No direct script access allowed');
/* ----------------------------------------------------------------------------
* Easy!Appointments - Online Appointment Scheduler
*
* @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
* ---------------------------------------------------------------------------- */
if (!function_exists('request')) {
/**
* Gets the value of a request variable.
*
* Example:
*
* $first_name = request('first_name', 'John');
*
* @param string|null $key Request variable key.
* @param mixed|null $default Default value in case the requested variable has no value.
*
* @return mixed
*
* @throws InvalidArgumentException
*/
function request(?string $key = null, $default = null): mixed
{
/** @var EA_Controller $CI */
$CI = &get_instance();
if (empty($key)) {
$payload = $CI->input->post_get($key);
if (empty($payload)) {
$payload = $CI->input->json($key);
}
return $payload;
}
return $CI->input->post_get($key) ?? ($CI->input->json($key) ?? $default);
}
}
if (!function_exists('response')) {
/**
* Return a new response from the application.
*
* Example:
*
* response('This is the response content', 200, []);
*
* @param string $content
* @param int $status
* @param array $headers
*/
function response(string $content = '', int $status = 200, array $headers = []): void
{
/** @var EA_Controller $CI */
$CI = &get_instance();
foreach ($headers as $header) {
$CI->output->set_header($header);
}
$CI->output->set_status_header($status)->set_output($content);
}
}
if (!function_exists('response')) {
/**
* Return a new response from the application.
*
* @param string $content
* @param int $status
* @param array $headers
*/
function response(string $content = '', int $status = 200, array $headers = []): void
{
/** @var EA_Controller $CI */
$CI = &get_instance();
foreach ($headers as $header) {
$CI->output->set_header($header);
}
$CI->output->set_status_header($status)->set_output($content);
}
}
if (!function_exists('json_response')) {
/**
* Return a new response from the application.
*
* Example:
*
* json_response([
* 'message' => 'This is a JSON property.'
* ]);
*
* @param array $content
* @param int $status
* @param array $headers
*/
function json_response(array $content = [], int $status = 200, array $headers = []): void
{
/** @var EA_Controller $CI */
$CI = &get_instance();
foreach ($headers as $header) {
$CI->output->set_header($header);
}
$CI->output
->set_status_header($status)
->set_content_type('application/json')
->set_output(json_encode($content));
}
}
if (!function_exists('json_exception')) {
/**
* Return a new json exception from the application.
*
* Example:
*
* json_exception($exception); // Add this in a catch block to return the exception information.
*
* @param Throwable $e
*/
function json_exception(Throwable $e): void
{
$response = [
'success' => false,
'message' => $e->getMessage(),
'trace' => trace($e),
];
log_message('error', 'JSON exception: ' . json_encode($response));
unset($response['trace']); // Do not send the trace to the browser as it might contain sensitive info
json_response($response, 500);
}
}
if (!function_exists('abort')) {
/**
* Throw an HttpException with the given data.
*
* Example:
*
* if ($error) abort(500);
*
* @param int $code
* @param string $message
* @param array $headers
*
* @return void
*/
function abort(int $code, string $message = '', array $headers = []): void
{
/** @var EA_Controller $CI */
$CI = &get_instance();
foreach ($headers as $header) {
$CI->output->set_header($header);
}
show_error($message, $code);
}
}
if (!function_exists('trace')) {
/**
* Prepare a well formatted string for an exception
*
* @param Throwable $e
*
* @return string
*/
function trace(Throwable $e): string
{
return get_class($e) .
" '{$e->getMessage()}' in {$e->getFile()}({$e->getLine()})\n" .
"{$e->getTraceAsString()}";
}
}

View File

@@ -0,0 +1,10 @@
<html>
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>

View File

@@ -0,0 +1,29 @@
<?php defined('BASEPATH') or exit('No direct script access allowed');
/* ----------------------------------------------------------------------------
* Easy!Appointments - Online Appointment Scheduler
*
* @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.1.0
* ---------------------------------------------------------------------------- */
/**
* Check if Easy!Appointments is installed.
*
* This function will check some factors to determine if Easy!Appointments is installed or not. It is possible that the
* installation is properly configure without being recognized by this method.
*
* Notice: You can add more checks into this file in order to further check the installation state of the application.
*
* @return bool Returns whether E!A is installed or not.
*/
function is_app_installed(): bool
{
$CI = &get_instance();
return $CI->db->table_exists('users');
}

View File

@@ -0,0 +1,39 @@
<?php defined('BASEPATH') or exit('No direct script access allowed');
/* ----------------------------------------------------------------------------
* Easy!Appointments - Online Appointment Scheduler
*
* @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.1.0
* ---------------------------------------------------------------------------- */
if (!function_exists('lang')) {
/**
* Lang
*
* Fetches a language variable and optionally outputs a form label
*
* @param string $line The language line.
* @param string $for The "for" value (id of the form element).
* @param array $attributes Any additional HTML attributes.
*
* @return string
*/
function lang(string $line, string $for = '', array $attributes = []): string
{
/** @var EA_Controller $CI */
$CI = get_instance();
$result = $CI->lang->line($line);
if ($for !== '') {
$result = '<label for="' . $for . '"' . _stringify_attributes($attributes) . '>' . $result . '</label>';
}
return $result ?: $line;
}
}

View File

@@ -0,0 +1,60 @@
<?php defined('BASEPATH') or exit('No direct script access allowed');
/* ----------------------------------------------------------------------------
* Easy!Appointments - Online Appointment Scheduler
*
* @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.0.0
* ---------------------------------------------------------------------------- */
/**
* Generate a hash of password string.
*
* For user security, all system passwords are stored in hash string into the database. Use this method to produce the
* hashed password.
*
* @param string $salt Salt value for current user. This value is stored on the database and is used when generating
* the password hashes.
* @param string $password Given string password.
*
* @return string Returns the hash string of the given password.
*
* @throws Exception
*/
function hash_password(string $salt, string $password): string
{
if (strlen($password) > MAX_PASSWORD_LENGTH) {
throw new InvalidArgumentException('The provided password is too long, please use a shorter value.');
}
$half = (int) (strlen($salt) / 2);
$hash = hash('sha256', substr($salt, 0, $half) . $password . substr($salt, $half));
for ($i = 0; $i < 100000; $i++) {
$hash = hash('sha256', $hash);
}
return $hash;
}
/**
* Generate a new password salt.
*
* This method will not check if the salt is unique in database. This must be done
* from the calling procedure.
*
* @return string Returns a salt string.
*/
function generate_salt(): string
{
$max_length = 100;
$salt = hash('sha256', uniqid(rand(), true));
return substr($salt, 0, $max_length);
}

View File

@@ -0,0 +1,46 @@
<?php defined('BASEPATH') or exit('No direct script access allowed');
/* ----------------------------------------------------------------------------
* Easy!Appointments - Online Appointment Scheduler
*
* @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
* ---------------------------------------------------------------------------- */
if (!function_exists('storage_path')) {
/**
* Get the path to the storage folder.
*
* Example:
*
* $logs_path = storage_path('logs'); // Returns "/path/to/installation/dir/storage/logs"
*
* @param string $path
*
* @return string
*/
function storage_path(string $path = ''): string
{
return FCPATH . 'storage/' . trim($path);
}
}
if (!function_exists('base_path')) {
/**
* Get the path to the base of the current installation.
*
* $controllers_path = base_path('application/controllers'); // Returns "/path/to/installation/dir/application/controllers"
*
* @param string $path
*
* @return string
*/
function base_path(string $path = ''): string
{
return FCPATH . trim($path);
}
}

View File

@@ -0,0 +1,72 @@
<?php defined('BASEPATH') or exit('No direct script access allowed');
/* ----------------------------------------------------------------------------
* Easy!Appointments - Online Appointment Scheduler
*
* @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
* ---------------------------------------------------------------------------- */
if (!function_exists('can')) {
/**
* Check if the currently logged-in user can perform an action
*
* Example:
*
* if (can('edit', 'appointments') === FALSE) abort(403);
*
* @param string $action
* @param string $resource
* @param int|null $user_id
*
* @return bool
*/
function can(string $action, string $resource, ?int $user_id = null): bool
{
/** @var EA_Controller $CI */
$CI = &get_instance();
$CI->load->model('roles_model');
$CI->load->model('users_model');
if (empty($user_id)) {
$role_slug = session('role_slug');
} else {
$user = $CI->users_model->find($user_id);
$role_slug = $CI->roles_model->value($user['id_roles'], 'slug');
}
if (empty($role_slug)) {
return false;
}
$permissions = $CI->roles_model->get_permissions_by_slug($role_slug);
return $permissions[$resource][$action] ?? false;
}
}
if (!function_exists('cannot')) {
/**
* Check if the currently logged-in user can perform an action
*
* Example:
*
* if (cannot('edit', 'appointments')) abort(403);
*
* @param string $action
* @param string $resource
* @param int|null $user_id
*
* @return bool
*/
function cannot(string $action, string $resource, ?int $user_id = null): bool
{
return !can($action, $resource, $user_id);
}
}

View File

@@ -0,0 +1,79 @@
<?php defined('BASEPATH') or exit('No direct script access allowed');
/* ----------------------------------------------------------------------------
* Easy!Appointments - Open Source Web Scheduler
*
* @package EasyAppointments
* @author A.Tselegidis <alextselegidis@gmail.com>
* @copyright Copyright (c) 2013 - 2020, Alex Tselegidis
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @link http://easyappointments.org
* @since v1.1.0
* ---------------------------------------------------------------------------- */
if (!function_exists('rate_limit')) {
/**
* Rate-limit the application requests.
*
* Example:
*
* rate_limit($CI->input->ip_address(), 100, 300);
*
* @link https://github.com/alexandrugaidei-atomate/ratelimit-codeigniter-filebased
*
* @param string $ip Client IP address.
* @param int $max_requests Number of allowed requests, defaults to 100.
* @param int $duration In seconds, defaults to 2 minutes.
*/
function rate_limit(string $ip, int $max_requests = 100, int $duration = 120): void
{
/** @var EA_Controller $CI */
$CI = &get_instance();
$rate_limiting = $CI->config->item('rate_limiting');
if (!$rate_limiting || is_cli()) {
return;
}
$CI->load->driver('cache', ['adapter' => 'file']);
$cache_key = str_replace(':', '', 'rate_limit_key_' . $ip);
$cache_remain_time_key = str_replace(':', '', 'rate_limit_tmp_' . $ip);
$current_time = date('Y-m-d H:i:s');
if ($CI->cache->get($cache_key) === false) {
// First request
$current_time_plus = date('Y-m-d H:i:s', strtotime('+' . $duration . ' seconds'));
$CI->cache->save($cache_key, 1, $duration);
$CI->cache->save($cache_remain_time_key, $current_time_plus, $duration * 2);
}
// Consequent request
else {
$requests = $CI->cache->get($cache_key);
$time_lost = $CI->cache->get($cache_remain_time_key);
if ($current_time > $time_lost) {
$current_time_plus = date('Y-m-d H:i:s', strtotime('+' . $duration . ' seconds'));
$CI->cache->save($cache_key, 1, $duration);
$CI->cache->save($cache_remain_time_key, $current_time_plus, $duration * 2);
} else {
$CI->cache->save($cache_key, $requests + 1, $duration);
}
$requests = $CI->cache->get($cache_key);
if ($requests > $max_requests) {
header('HTTP/1.0 429 Too Many Requests');
exit();
}
}
}
}

View File

@@ -0,0 +1,48 @@
<?php defined('BASEPATH') or exit('No direct script access allowed');
/* ----------------------------------------------------------------------------
* Easy!Appointments - Online Appointment Scheduler
*
* @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.3.0
* ---------------------------------------------------------------------------- */
if (!function_exists('route_api_resource')) {
/**
* Define a route for an API resource (includes index, store, update and delete callbacks).
*
* @param array $route Route config.
* @param string $resource Resource name.
* @param string $prefix URL prefix (e.g. api/v1/).
*/
function route_api_resource(array &$route, string $resource, string $prefix = ''): void
{
$route[$prefix . $resource]['post'] = 'api/v1/' . $resource . '_api_v1/store';
$route[$prefix . $resource . '/(:num)']['put'] = 'api/v1/' . $resource . '_api_v1/update/$1';
$route[$prefix . $resource . '/(:num)']['delete'] = 'api/v1/' . $resource . '_api_v1/destroy/$1';
$route[$prefix . $resource]['get'] = 'api/v1/' . $resource . '_api_v1/index';
$route[$prefix . $resource . '/(:num)']['get'] = 'api/v1/' . $resource . '_api_v1/show/$1';
}
}
if (!function_exists('is_callback')) {
/**
* Check whether the current request matches the provided controller/method callback.
*
* @param string $class Controller class name.
* @param string $method Controller method name.
*
* @return bool
*/
function is_callback(string $class, string $method): bool
{
/** @var EA_Controller $CI */
$CI = &get_instance();
return $CI->router->class === $class && $CI->router->method === $method;
}
}

View File

@@ -0,0 +1,56 @@
<?php defined('BASEPATH') or exit('No direct script access allowed');
/* ----------------------------------------------------------------------------
* Easy!Appointments - Online Appointment Scheduler
*
* @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
* ---------------------------------------------------------------------------- */
if (!function_exists('session')) {
/**
* Get / set the specified session value.
*
* If an array is passed as the key, we will assume you want to set an array of values.
*
* Example "Get":
*
* $logged_in = session('logged_in', FALSE);
*
* Example "Set":
*
* session(['logged_in' => FALSE]);
*
* @param array|string|null $key Session item key.
* @param mixed|null $default Default value in case the requested session item has no value.
*
* @return mixed|NULL Returns the requested value or NULL if you assign a new session value.
*
* @throws InvalidArgumentException
*/
function session(array|string|null $key = null, mixed $default = null): mixed
{
/** @var EA_Controller $CI */
$CI = &get_instance();
if (empty($key)) {
throw new InvalidArgumentException('The $key argument cannot be empty.');
}
if (is_array($key)) {
foreach ($key as $item => $value) {
$CI->session->set_userdata($item, $value);
}
return null;
}
$value = $CI->session->userdata($key);
return $value ?? $default;
}
}

View File

@@ -0,0 +1,76 @@
<?php defined('BASEPATH') or exit('No direct script access allowed');
/* ----------------------------------------------------------------------------
* Easy!Appointments - Online Appointment Scheduler
*
* @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
* ---------------------------------------------------------------------------- */
if (!function_exists('setting')) {
/**
* Get / set the specified setting value.
*
* If an array is passed as the key, we will assume you want to set an array of values.
*
* Example "Get":
*
* $company_name = session('company_name', FALSE);
*
* Example "Set":
*
* setting(['company_name' => 'ACME Inc']);
*
* @param array|string|null $key Setting key.
* @param mixed|null $default Default value in case the requested setting has no value.
*
* @return mixed|NULL Returns the requested value or NULL if you assign a new setting value.
*
* @throws InvalidArgumentException
*/
function setting(array|string|null $key = null, mixed $default = null): mixed
{
/** @var EA_Controller $CI */
$CI = &get_instance();
$CI->load->model('settings_model');
if (empty($key)) {
throw new InvalidArgumentException('The $key argument cannot be empty.');
}
if (is_array($key)) {
foreach ($key as $name => $value) {
$setting = $CI->settings_model
->query()
->where('name', $name)
->get()
->row_array();
if (empty($setting)) {
$setting = [
'name' => $name,
];
}
$setting['value'] = $value;
$CI->settings_model->save($setting);
}
return null;
}
$setting = $CI->settings_model
->query()
->where('name', $key)
->get()
->row_array();
return $setting['value'] ?? $default;
}
}

View File

@@ -0,0 +1,26 @@
<?php defined('BASEPATH') or exit('No direct script access allowed');
/* ----------------------------------------------------------------------------
* Easy!Appointments - Online Appointment Scheduler
*
* @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.0.0
* ---------------------------------------------------------------------------- */
/**
* Validate a date time value.
*
* @param string $value Validation value.
*
* @return bool Returns the validation result.
*/
function validate_datetime(string $value): bool
{
$date_time = DateTime::createFromFormat('Y-m-d H:i:s', $value);
return (bool) $date_time;
}