*/ protected $callbacks = []; /** * Try and detect if we recognize the environment the library is running * in and adjust our implementations accordingly. * * Basically, if we see the LARAVEL_START constant we assume Laravel and * use Laravel facades, otherwise we use native php implementations. * */ protected function __construct() { if (defined('LARAVEL_START')) { $this->initializeLaravel(); } else { $this->initializeNative(); } } /** * Retrieve the instance of Authkit2 class * * @return Authkit2 */ public static function get(): Authkit2 { static $authkit2; if (!isset($authkit2)) { $authkit2 = new Authkit2(); } return $authkit2; } /** * Override any of the function implementations * * Name is the same as the callable function name, e.g., * Authkit2::cache_set() can be overriden with Authkit2->cache_set = function(...) {} * * @param string $name * @param callable $value * @return void */ public function __set(string $name, $value): void { if (!array_key_exists($name, $this->callbacks)) { trigger_error('Undefined property: '.__CLASS__.'::$'.$name, E_USER_WARNING); return; } if (!is_callable($value)) { throw new \Exception('Authkit2::'.$name.' value must be callable'); } $this->callbacks[$name] = $value; } /** * Call any of the provided methods * * @param string $name * @param mixed[] $arguments * @return mixed */ public static function __callStatic(string $name, array $arguments) { $authkit2 = static::get(); if (!isset($authkit2->callbacks[$name])) { trigger_error('Call to undefined method '.__CLASS__.'::'.$name.'()', E_USER_ERROR); } return call_user_func_array($authkit2->callbacks[$name], $arguments); } /** * Helper method for getting cache values, and generating and setting if * they do not exist. * * @param string $key cache key * @param callable $generator method that returns the value if we do not have it cached * @return mixed */ protected function cache_helper(string $key, callable $generator) { $value = static::cache_get($key, null); if (!isset($value)) { $value = $generator(); static::cache_set($key, $value); } return $value; } /** * Initialize the class by binding all the PHP native implementations of * functions * * @return void */ protected function initializeNative(): void { $this->callbacks = [ 'session_get' => [$this, 'native_session_get'], 'session_set' => [$this, 'native_session_set'], 'cache_get' => [$this, 'native_cache_get'], 'cache_set' => [$this, 'native_cache_set'], 'cache' => [$this, 'cache_helper'] ]; } /** * Initialize the class by binding Laravel adapters as the implementation * of all functions * * @return void */ protected function initializeLaravel(): void { $this->callbacks = [ 'session_get' => function(string $key) { return \Session::get($key); }, 'session_set' => function(string $key, $value) { \Session::put($key, $value); }, 'cache_get' => function(string $key) { return \Cache::get($key); }, 'cache_set' => function(string $key, $value) { \Cache::set($key, $value); }, 'cache' => [$this, 'cache_helper'] ]; } /** * Retrieve a property out of the $_SESSION variable; null if the * property doesn't exist. * * @param string $key * @return mixed */ protected function native_session_get(string $key) { $this->native_session_check(); return $_SESSION[static::LIB_PREFIX.$key] ?? null; } /** * Set a value in the $_SESSION variable * * @param string $key * @param mixed $value * @return void */ protected function native_session_set(string $key, $value): void { $this->native_session_check(); $_SESSION[static::LIB_PREFIX.$key] = $value; } /** * Check whether a PHP session exists, and if not try and start one * * @internal * @return void */ protected function native_session_check(): void { if (session_status() == \PHP_SESSION_NONE) session_start(); else if (session_status() == \PHP_SESSION_DISABLED) throw new \Exception("Authkit2 requires PHP sessions are enabled"); } /** * Dummy cache implementation to avoid errors; always returns default * * @todo Check if apcu is available and use if so? Fall back to temp files? * @param string $key cache key to retrieve * @param mixed $default value to return if the specified key is not found * @return mixed */ protected function native_cache_get(string $key, $default = null) { return $default; } /** * Dummy cache implementation * * @param string $key cache key to set * @param mixed $value value to cache * @return void */ protected function native_cache_set(string $key, $value): void { } }