freescout/freescout-dist/app/Option.php

306 lines
8.3 KiB
PHP
Raw Permalink Normal View History

2023-12-22 19:40:32 +00:00
<?php
/**
* todo: implement caching by saving all options in one cache variable on register_shutdown_function.
*/
namespace App;
use Illuminate\Database\Eloquent\Model;
class Option extends Model
{
// Value returned when cache contains default value.
const CACHE_DEFAULT_VALUE = 'CACHE_DEFAULT_VALUE';
// todo: cache like in WordPress (fetch all options from DB each time)
public static $cache = [];
public $timestamps = false;
/**
* The attributes that are not mass assignable.
*
* @var array
*/
protected $guarded = ['id'];
/**
* Set an option.
*
* @param string $name
* @param string $value
*
* @return bool
*/
public static function set($name, $value)
{
$name = trim($name);
if (empty($name)) {
return false;
}
// Sanitize option
if (is_null($value)) {
$value = '';
}
if (is_object($value)) {
$value = clone $value;
}
$serialized_value = self::maybeSerialize($value);
$option = self::firstOrCreate(
['name' => $name], ['value' => $serialized_value]
);
$old_value = $option['value'];
if ($value === $old_value || self::maybeSerialize($value) === self::maybeSerialize($old_value)) {
return false;
}
$option->value = $serialized_value;
$option->save();
}
/**
* Get option.
*
* @param string $name
*
* @return string
*/
public static function get($name, $default = false, $decode = true, $use_cache = true)
{
// If not passed, get default value from config
if (func_num_args() == 1) {
$default = self::getDefault($name, $default);
}
if ($use_cache && isset(self::$cache[$name])) {
if (self::$cache[$name] == self::CACHE_DEFAULT_VALUE) {
return $default;
} else {
return self::$cache[$name];
}
}
$option = self::where('name', (string) $name)->first();
if ($option) {
if ($decode) {
$value = self::maybeUnserialize($option->value);
} else {
$value = $option->value;
}
self::$cache[$name] = $value;
} else {
$value = $default;
self::$cache[$name] = self::CACHE_DEFAULT_VALUE;
}
return $value;
}
public static function getDefault($option_name, $default = false)
{
$options = \Config::get('app.options');
if (isset($options[$option_name]) && isset($options[$option_name]['default'])) {
return $options[$option_name]['default'];
} else {
// Try to get default option value from module's config.
preg_match("/^([a-z_]+)\.(.*)/", $option_name, $m);
if (!empty($m[1]) && !empty($m[2])) {
$module_alias = $m[1];
$modle_option_name = $m[2];
$module_options = \Config::get($module_alias.'.options');
if (isset($module_options[$modle_option_name]) && isset($module_options[$modle_option_name]['default'])) {
return $module_options[$modle_option_name]['default'];
}
}
return $default;
}
}
public static function isDefaultSet($option_name)
{
$options = \Config::get('app.options');
return isset($options[$option_name]) && isset($options[$option_name]['default']);
}
/**
* Get multiple options.
*
* @param [type] $name [description]
* @param bool $default [description]
* @param bool $decode [description]
*
* @return [type] [description]
*/
public static function getOptions($options, $defaults = [], $decode = [])
{
$values = [];
// Check in cache first
// Return if we can get all options from cache
foreach ($options as $name) {
if (isset(self::$cache[$name])) {
if (self::$cache[$name] == self::CACHE_DEFAULT_VALUE) {
if (!isset($defaults[$name])) {
$default = self::getDefault($name);
} else {
$default = $defaults[$name];
}
$values[$name] = $default;
} else {
$values[$name] = self::$cache[$name];
}
}
}
if (count($values) == count($options)) {
return $values;
} else {
$values = [];
}
$db_options = self::whereIn('name', $options)->get();
foreach ($options as $name) {
// If not passed, get default value from config
if (!isset($defaults[$name])) {
$default = self::getDefault($name);
} else {
$default = $defaults[$name];
}
$db_option = $db_options->where('name', $name)->first();
if ($db_option) {
// todo: decode
if (1 || $decode) {
$value = self::maybeUnserialize($db_option->value);
} else {
$value = $db_option->value;
}
self::$cache[$name] = $value;
} else {
$value = $default;
self::$cache[$name] = self::CACHE_DEFAULT_VALUE;
}
$values[$name] = $value;
}
return $values;
}
public static function remove($name)
{
self::where('name', (string) $name)->delete();
}
/**
* Serialize data, if needed.
*/
public static function maybeSerialize($data)
{
if (is_array($data) || is_object($data)) {
return serialize($data);
}
return $data;
}
/**
* Unserialize data.
*/
public static function maybeUnserialize($original)
{
if (self::isSerialized($original)) {
try {
$original = unserialize($original);
} catch (\Exception $e) {
// Do nothing
}
return $original;
}
return $original;
}
/**
* Check value to find if it was serialized.
* Serialized data is always a string.
*/
public static function isSerialized($data, $strict = true)
{
// if it isn't a string, it isn't serialized.
if (!is_string($data)) {
return false;
}
$data = trim($data);
if ('N;' == $data) {
return true;
}
if (strlen($data) < 4) {
return false;
}
if (':' !== $data[1]) {
return false;
}
if ($strict) {
$lastc = substr($data, -1);
if (';' !== $lastc && '}' !== $lastc) {
return false;
}
} else {
$semicolon = strpos($data, ';');
$brace = strpos($data, '}');
// Either ; or } must exist.
if (false === $semicolon && false === $brace) {
return false;
}
// But neither must be in the first X characters.
if (false !== $semicolon && $semicolon < 3) {
return false;
}
if (false !== $brace && $brace < 4) {
return false;
}
}
$token = $data[0];
switch ($token) {
case 's':
if ($strict) {
if ('"' !== substr($data, -2, 1)) {
return false;
}
} elseif (false === strpos($data, '"')) {
return false;
}
// or else fall through
case 'a':
case 'O':
return (bool) preg_match("/^{$token}:[0-9]+:/s", $data);
case 'b':
case 'i':
case 'd':
$end = $strict ? '$' : '';
return (bool) preg_match("/^{$token}:[0-9.E-]+;$end/", $data);
}
return false;
}
/**
* Get company name.
*/
public static function getCompanyName()
{
return self::get('company_name', \Config::get('app.name'));
}
}