Use parse_ini_file instead of custom class.
This commit is contained in:
parent
c8aafe1a07
commit
bce19a2ed6
11 changed files with 161 additions and 477 deletions
|
@ -223,7 +223,7 @@ MIG;
|
|||
|
||||
tpl_add_path(__DIR__ . '/templates');
|
||||
|
||||
if ($app->getConfig()->get('Auth', 'lockdown', 'bool', false)) {
|
||||
if ($app->underLockdown()) {
|
||||
http_response_code(503);
|
||||
echo tpl_render('auth/lockdown');
|
||||
exit;
|
||||
|
|
|
@ -7,8 +7,6 @@ use Misuzu\Users\Session;
|
|||
|
||||
require_once __DIR__ . '/../misuzu.php';
|
||||
|
||||
$config = $app->getConfig();
|
||||
|
||||
$usernameValidationErrors = [
|
||||
'trim' => 'Your username may not start or end with spaces!',
|
||||
'short' => sprintf('Your username is too short, it has to be at least %d characters!', MSZ_USERNAME_MIN_LENGTH),
|
||||
|
@ -18,7 +16,7 @@ $usernameValidationErrors = [
|
|||
];
|
||||
|
||||
$authMode = $_GET['m'] ?? 'login';
|
||||
$preventRegistration = $config->get('Auth', 'prevent_registration', 'bool', false);
|
||||
$preventRegistration = $app->disableRegistration();
|
||||
|
||||
tpl_vars([
|
||||
'prevent_registration' => $preventRegistration,
|
||||
|
@ -203,10 +201,7 @@ If you weren't the person who requested this reset, please send a reply to this
|
|||
MSG;
|
||||
|
||||
$message = (new Swift_Message('Flashii Password Reset'))
|
||||
->setFrom([
|
||||
$config->get('Mail', 'sender_email', 'string', 'sys@misuzu.lh') =>
|
||||
$config->get('Mail', 'sender_name', 'string', 'Misuzu')
|
||||
])
|
||||
->setFrom($app->getMailSender())
|
||||
->setTo([$forgotUser['email'] => $forgotUser['username']])
|
||||
->setBody($messageBody);
|
||||
|
||||
|
|
|
@ -5,17 +5,7 @@ use Misuzu\Database;
|
|||
|
||||
require_once __DIR__ . '/../misuzu.php';
|
||||
|
||||
$config = $app->getConfig();
|
||||
|
||||
if ($config->get('Site', 'embed_linked_data', 'bool', false)) {
|
||||
tpl_vars([
|
||||
'embed_linked_data' => true,
|
||||
'embed_name' => $config->get('Site', 'name'),
|
||||
'embed_url' => $config->get('Site', 'url'),
|
||||
'embed_logo' => $config->get('Site', 'external_logo'),
|
||||
'embed_same_as' => explode(',', $config->get('Site', 'social_media')),
|
||||
]);
|
||||
}
|
||||
tpl_vars($app->getLinkedData());
|
||||
|
||||
$news = Database::query('
|
||||
SELECT
|
||||
|
|
|
@ -9,10 +9,7 @@ $mode = (string)($_GET['m'] ?? 'view');
|
|||
|
||||
switch ($mode) {
|
||||
case 'avatar':
|
||||
$avatar_filename = $app->getPath(
|
||||
$app->getConfig()->get('Avatar', 'default_path', 'string', 'public/images/no-avatar.png')
|
||||
);
|
||||
|
||||
$avatar_filename = $app->getDefaultAvatar();
|
||||
$user_avatar = "{$user_id}.msz";
|
||||
$cropped_avatar = $app->getStore('avatars/200x200')->filename($user_avatar);
|
||||
|
||||
|
|
|
@ -66,11 +66,9 @@ if (!array_key_exists($settingsMode, $settingsModes)) {
|
|||
|
||||
$settingsErrors = [];
|
||||
|
||||
$disableAccountOptions = !$app->inDebugMode() && $app->getConfig()->get('Auth', 'prevent_registration', 'bool', false);
|
||||
$disableAccountOptions = !$app->inDebugMode() && $app->disableRegistration();
|
||||
$avatarFileName = "{$app->getUserId()}.msz";
|
||||
$avatarWidthMax = $app->getConfig()->get('Avatar', 'max_width', 'int', 4000);
|
||||
$avatarHeightMax = $app->getConfig()->get('Avatar', 'max_height', 'int', 4000);
|
||||
$avatarFileSizeMax = $app->getConfig()->get('Avatar', 'max_filesize', 'int', 1000000);
|
||||
$avatarProps = $app->getAvatarProps();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (!tmp_csrf_verify($_POST['csrf'] ?? '')) {
|
||||
|
@ -123,9 +121,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||
$avatarErrorStrings['upload'][$_FILES['avatar']['error']['file']]
|
||||
?? $avatarErrorStrings['upload']['default'],
|
||||
$_FILES['avatar']['error']['file'],
|
||||
byte_symbol($avatarFileSizeMax, true),
|
||||
$avatarWidthMax,
|
||||
$avatarHeightMax
|
||||
byte_symbol($avatarProps['max_filesize'], true),
|
||||
$avatarProps['max_width'],
|
||||
$avatarProps['max_height']
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
@ -140,9 +138,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||
$avatarErrorStrings['set'][$setAvatar]
|
||||
?? $avatarErrorStrings['set']['default'],
|
||||
$setAvatar,
|
||||
byte_symbol($avatarFileSizeMax, true),
|
||||
$avatarWidthMax,
|
||||
$avatarHeightMax
|
||||
byte_symbol($avatarProps['max_filesize'], true),
|
||||
$avatarProps['max_width'],
|
||||
$avatarProps['max_height']
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
@ -309,9 +307,9 @@ switch ($settingsMode) {
|
|||
|
||||
tpl_vars([
|
||||
'avatar_user_id' => $app->getUserId(),
|
||||
'avatar_max_width' => $avatarWidthMax,
|
||||
'avatar_max_height' => $avatarHeightMax,
|
||||
'avatar_max_filesize' => $avatarFileSizeMax,
|
||||
'avatar_max_width' => $avatarProps['max_width'],
|
||||
'avatar_max_height' => $avatarProps['max_height'],
|
||||
'avatar_max_filesize' => $avatarProps['max_filesize'],
|
||||
'user_has_avatar' => $userHasAvatar,
|
||||
'settings_profile_fields' => $profileFields,
|
||||
'settings_profile_values' => $userFields,
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
namespace Misuzu;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Misuzu\Config\ConfigManager;
|
||||
use Misuzu\IO\Directory;
|
||||
use Misuzu\IO\DirectoryDoesNotExistException;
|
||||
use Misuzu\Users\Session;
|
||||
|
@ -12,6 +11,7 @@ use Swift_Mailer;
|
|||
use Swift_NullTransport;
|
||||
use Swift_SmtpTransport;
|
||||
use Swift_SendmailTransport;
|
||||
use GeoIp2\Database\Reader as GeoIP;
|
||||
|
||||
/**
|
||||
* Handles the set up procedures.
|
||||
|
@ -50,11 +50,7 @@ class Application extends ApplicationBase
|
|||
*/
|
||||
private $currentUserId = 0;
|
||||
|
||||
/**
|
||||
* ConfigManager instance.
|
||||
* @var \Misuzu\Config\ConfigManager
|
||||
*/
|
||||
private $configInstance = null;
|
||||
private $config = [];
|
||||
|
||||
/**
|
||||
* TemplatingEngine instance.
|
||||
|
@ -64,6 +60,8 @@ class Application extends ApplicationBase
|
|||
|
||||
private $mailerInstance = null;
|
||||
|
||||
private $geoipInstance = null;
|
||||
|
||||
private $startupTime = 0;
|
||||
|
||||
/**
|
||||
|
@ -76,14 +74,18 @@ class Application extends ApplicationBase
|
|||
$this->startupTime = microtime(true);
|
||||
parent::__construct();
|
||||
$this->debugMode = $debug;
|
||||
$this->configInstance = new ConfigManager($configFile);
|
||||
$this->config = parse_ini_file($configFile, true, INI_SCANNER_TYPED);
|
||||
|
||||
if ($this->config === false) {
|
||||
throw new UnexpectedValueException('Failed to parse configuration.');
|
||||
}
|
||||
|
||||
// only use this error handler in prod mode, dev uses Whoops now
|
||||
if (!$debug) {
|
||||
ExceptionHandler::register(
|
||||
false,
|
||||
$this->configInstance->get('Exceptions', 'report_url', 'string', null),
|
||||
$this->configInstance->get('Exceptions', 'hash_key', 'string', null)
|
||||
$this->config['Exceptions']['report_url'] ?? null,
|
||||
$this->config['Exceptions']['hash_key'] ?? null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -93,21 +95,6 @@ class Application extends ApplicationBase
|
|||
return microtime(true) - $this->startupTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets instance of the config manager.
|
||||
* @return ConfigManager
|
||||
*/
|
||||
public function getConfig(): ConfigManager
|
||||
{
|
||||
if (is_null($this->configInstance)) {
|
||||
throw new UnexpectedValueException(
|
||||
'Internal ConfigManager instance is null, how did you even manage to do this?'
|
||||
);
|
||||
}
|
||||
|
||||
return $this->configInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether we're in debug mode or not.
|
||||
* @return bool
|
||||
|
@ -143,7 +130,7 @@ class Application extends ApplicationBase
|
|||
if (starts_with($append, '/')) {
|
||||
$path = $append;
|
||||
} else {
|
||||
$path = $this->getConfig()->get('Storage', 'path', 'string', __DIR__ . '/../store');
|
||||
$path = $this->config['Storage']['path'] ?? __DIR__ . '/../store';
|
||||
|
||||
if (!empty($append)) {
|
||||
$path .= '/' . $append;
|
||||
|
@ -164,9 +151,9 @@ class Application extends ApplicationBase
|
|||
{
|
||||
$override_key = 'override_' . str_replace('/', '_', $purpose);
|
||||
|
||||
if ($this->configInstance->contains('Storage', $override_key)) {
|
||||
if (array_key_exists('Storage', $this->config)) {
|
||||
try {
|
||||
return new Directory($this->configInstance->get('Storage', $override_key));
|
||||
return new Directory($this->config['Storage'][$override_key]);
|
||||
} catch (DirectoryDoesNotExistException $ex) {
|
||||
// fall through and just get the default path.
|
||||
}
|
||||
|
@ -235,7 +222,13 @@ class Application extends ApplicationBase
|
|||
throw new UnexpectedValueException('Database has already been started.');
|
||||
}
|
||||
|
||||
new Database($this->configInstance, self::DATABASE_CONNECTIONS[0]);
|
||||
$connections = [];
|
||||
|
||||
foreach (self::DATABASE_CONNECTIONS as $name) {
|
||||
$connections[$name] = $this->config["Database.{$name}"] ?? [];
|
||||
}
|
||||
|
||||
new Database($connections, self::DATABASE_CONNECTIONS[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -248,11 +241,11 @@ class Application extends ApplicationBase
|
|||
}
|
||||
|
||||
new Cache(
|
||||
$this->configInstance->get('Cache', 'host', 'string', null),
|
||||
$this->configInstance->get('Cache', 'port', 'int', null),
|
||||
$this->configInstance->get('Cache', 'database', 'int', null),
|
||||
$this->configInstance->get('Cache', 'password', 'string', null),
|
||||
$this->configInstance->get('Cache', 'prefix', 'string', '')
|
||||
$this->config['Cache']['host'] ?? null,
|
||||
$this->config['Cache']['port'] ?? null,
|
||||
$this->config['Cache']['database'] ?? null,
|
||||
$this->config['Cache']['password'] ?? null,
|
||||
$this->config['Cache']['prefix'] ?? ''
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -270,10 +263,10 @@ class Application extends ApplicationBase
|
|||
]);
|
||||
|
||||
tpl_var('globals', [
|
||||
'site_name' => $this->configInstance->get('Site', 'name', 'string', 'Flashii'),
|
||||
'site_description' => $this->configInstance->get('Site', 'description'),
|
||||
'site_twitter' => $this->configInstance->get('Site', 'twitter'),
|
||||
'site_url' => $this->configInstance->get('Site', 'url'),
|
||||
'site_name' => $this->config['Site']['name'] ?? 'Flashii',
|
||||
'site_description' => $this->config['Site']['description'] ?? '',
|
||||
'site_twitter' => $this->config['Site']['twitter'] ?? '',
|
||||
'site_url' => $this->config['Site']['url'] ?? '',
|
||||
]);
|
||||
|
||||
tpl_add_function('json_decode', true);
|
||||
|
@ -309,8 +302,8 @@ class Application extends ApplicationBase
|
|||
return;
|
||||
}
|
||||
|
||||
if ($this->configInstance->contains('Mail')) {
|
||||
$method = mb_strtolower($this->configInstance->get('Mail', 'method'));
|
||||
if (array_key_exists('Mail', $this->config) && array_key_exists('method', $this->config['Mail'])) {
|
||||
$method = mb_strtolower($this->config['Mail']['method'] ?? '');
|
||||
}
|
||||
|
||||
if (empty($method) || !array_key_exists($method, self::MAIL_TRANSPORT)) {
|
||||
|
@ -322,27 +315,25 @@ class Application extends ApplicationBase
|
|||
|
||||
switch ($method) {
|
||||
case 'sendmail':
|
||||
if ($this->configInstance->contains('Mail', 'command')) {
|
||||
$transport->setCommand(
|
||||
$this->configInstance->get('Mail', 'command')
|
||||
);
|
||||
if (array_key_exists('command', $this->config['Mail'])) {
|
||||
$transport->setCommand($this->config['Mail']['command']);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'smtp':
|
||||
$transport->setHost($this->configInstance->get('Mail', 'host'));
|
||||
$transport->setPort($this->configInstance->get('Mail', 'port', 'int', 25));
|
||||
$transport->setHost($this->config['Mail']['host'] ?? '');
|
||||
$transport->setPort(intval($this->config['Mail']['port'] ?? 25));
|
||||
|
||||
if ($this->configInstance->contains('Mail', 'encryption')) {
|
||||
$transport->setEncryption($this->configInstance->get('Mail', 'encryption'));
|
||||
if (array_key_exists('encryption', $this->config['Mail'])) {
|
||||
$transport->setEncryption($this->config['Mail']['encryption']);
|
||||
}
|
||||
|
||||
if ($this->configInstance->contains('Mail', 'username')) {
|
||||
$transport->setUsername($this->configInstance->get('Mail', 'username'));
|
||||
if (array_key_exists('username', $this->config['Mail'])) {
|
||||
$transport->setUsername($this->config['Mail']['username']);
|
||||
}
|
||||
|
||||
if ($this->configInstance->contains('Mail', 'password')) {
|
||||
$transport->setPassword($this->configInstance->get('Mail', 'password'));
|
||||
if (array_key_exists('password', $this->config['Mail'])) {
|
||||
$transport->setPassword($this->config['Mail']['password']);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -363,4 +354,73 @@ class Application extends ApplicationBase
|
|||
{
|
||||
return self::getInstance()->getMailer();
|
||||
}
|
||||
|
||||
public function getMailSender(): array
|
||||
{
|
||||
return [
|
||||
($this->config['Mail']['sender_email'] ?? 'sys@msz.lh') => ($this->config['Mail']['sender_name'] ?? 'Misuzu System')
|
||||
];
|
||||
}
|
||||
|
||||
public function startGeoIP(): void
|
||||
{
|
||||
if (!empty($this->geoipInstance)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->geoipInstance = new GeoIP($this->config['GeoIP']['database_path'] ?? '');
|
||||
}
|
||||
|
||||
public function getGeoIP(): GeoIP
|
||||
{
|
||||
if (empty($this->geoipInstance)) {
|
||||
$this->startGeoIP();
|
||||
}
|
||||
|
||||
return $this->geoipInstance;
|
||||
}
|
||||
|
||||
public static function geoip(): GeoIP
|
||||
{
|
||||
return self::getInstance()->getGeoIP();
|
||||
}
|
||||
|
||||
public function getAvatarProps(): array
|
||||
{
|
||||
return [
|
||||
'max_width' => intval($this->config['Avatar']['max_width'] ?? 4000),
|
||||
'max_height' => intval($this->config['Avatar']['max_height'] ?? 4000),
|
||||
'max_filesize' => intval($this->config['Avatar']['max_filesize'] ?? 1000000),
|
||||
];
|
||||
}
|
||||
|
||||
public function underLockdown(): bool
|
||||
{
|
||||
return boolval($this->config['Auth']['lockdown'] ?? false);
|
||||
}
|
||||
|
||||
public function disableRegistration(): bool
|
||||
{
|
||||
return $this->underLockdown() || boolval($this->config['Auth']['prevent_registration'] ?? false);
|
||||
}
|
||||
|
||||
public function getLinkedData(): array
|
||||
{
|
||||
if (!($this->config['Site']['embed_linked_data'] ?? false)) {
|
||||
return ['embed_linked_data' => false];
|
||||
}
|
||||
|
||||
return [
|
||||
'embed_linked_data' => true,
|
||||
'embed_name' => $this->config['Site']['name'] ?? 'Flashii',
|
||||
'embed_url' => $this->config['Site']['url'] ?? '',
|
||||
'embed_logo' => $this->config['Site']['external_logo'] ?? '',
|
||||
'embed_same_as' => explode(',', $this->config['Site']['social_media'] ?? '')
|
||||
];
|
||||
}
|
||||
|
||||
public function getDefaultAvatar(): string
|
||||
{
|
||||
return $this->getPath($this->config['Avatar']['default_path'] ?? 'public/images/no-avatar.png');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
namespace Misuzu;
|
||||
|
||||
use Misuzu\Config\ConfigManager;
|
||||
use Redis;
|
||||
use InvalidArgumentException;
|
||||
use UnexpectedValueException;
|
||||
|
|
|
@ -1,249 +0,0 @@
|
|||
<?php
|
||||
namespace Misuzu\Config;
|
||||
|
||||
use Misuzu\IO\File;
|
||||
use Misuzu\IO\FileStream;
|
||||
|
||||
/**
|
||||
* Handles parsing, reading and setting configuration files.
|
||||
* @package Aitemu\Config
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class ConfigManager
|
||||
{
|
||||
/**
|
||||
* Holds the key collection pairs for the sections.
|
||||
* @var array
|
||||
*/
|
||||
private $collection = [];
|
||||
|
||||
private $filename = null;
|
||||
|
||||
/**
|
||||
* Creates a file object with the given path and reloads the context.
|
||||
* @param string|null $filename
|
||||
*/
|
||||
public function __construct(?string $filename = null)
|
||||
{
|
||||
if (empty($filename)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->filename = $filename;
|
||||
|
||||
if (File::exists($this->filename)) {
|
||||
$this->load();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a section or key exists in the config.
|
||||
* @param string $section
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public function contains(string $section, ?string $key = null): bool
|
||||
{
|
||||
if ($key !== null) {
|
||||
return $this->contains($section) && array_key_exists($key, $this->collection[$section]);
|
||||
}
|
||||
|
||||
return array_key_exists($section, $this->collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a section or key and saves.
|
||||
* @param string $section
|
||||
* @param string $key
|
||||
*/
|
||||
public function remove(string $section, ?string $key = null): void
|
||||
{
|
||||
if ($key !== null && $this->contains($section, $key)) {
|
||||
if (count($this->collection[$section]) < 2) {
|
||||
$this->remove($section);
|
||||
return;
|
||||
}
|
||||
|
||||
unset($this->collection[$section][$key]);
|
||||
} elseif ($this->contains($section)) {
|
||||
unset($this->collection[$section]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value from a section in the config.
|
||||
* @param string $section
|
||||
* @param string $key
|
||||
* @param string $type
|
||||
* @param string $fallback
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $section, string $key, string $type = 'string', ?string $fallback = null)
|
||||
{
|
||||
$value = null;
|
||||
|
||||
if (!$this->contains($section, $key)) {
|
||||
$this->set($section, $key, $fallback);
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
$raw = $this->collection[$section][$key];
|
||||
|
||||
switch (strtolower($type)) {
|
||||
case "bool":
|
||||
case "boolean":
|
||||
$value = mb_strlen($raw) > 0 && ($raw[0] === '1' || mb_strtolower($raw) === "true");
|
||||
break;
|
||||
|
||||
case "int":
|
||||
case "integer":
|
||||
$value = intval($raw);
|
||||
break;
|
||||
|
||||
case "float":
|
||||
case "double":
|
||||
$value = floatval($raw);
|
||||
break;
|
||||
|
||||
default:
|
||||
$value = $raw;
|
||||
break;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a configuration value and immediately saves it.
|
||||
* @param string $section
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function set(string $section, string $key, $value): void
|
||||
{
|
||||
$type = gettype($value);
|
||||
$store = null;
|
||||
|
||||
switch (mb_strtolower($type)) {
|
||||
case 'boolean':
|
||||
$store = $value ? '1' : '0';
|
||||
break;
|
||||
|
||||
default:
|
||||
$store = (string)$value;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$this->contains($section)) {
|
||||
$this->collection[$section] = [];
|
||||
}
|
||||
|
||||
$this->collection[$section][$key] = $store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the serialised config to file.
|
||||
*/
|
||||
public function save(): void
|
||||
{
|
||||
if (!empty($this->filename)) {
|
||||
static::write($this->filename, $this->collection);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls for a parse of the contents of the config file.
|
||||
*/
|
||||
public function load(): void
|
||||
{
|
||||
if (!empty($this->filename)) {
|
||||
$this->collection = static::read($this->filename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialises the $this->collection array to the human managable config format.
|
||||
* @param string $filename
|
||||
* @param array $collection
|
||||
* @throws \Misuzu\IO\FileDoesNotExistException
|
||||
* @throws \Misuzu\IO\IOException
|
||||
*/
|
||||
public static function write(string $filename, array $collection): void
|
||||
{
|
||||
$file = new FileStream($filename, FileStream::MODE_TRUNCATE, true);
|
||||
$file->write(sprintf('; Saved on %s%s', date('Y-m-d H:i:s e'), PHP_EOL));
|
||||
|
||||
foreach ($collection as $name => $entries) {
|
||||
if (count($entries) < 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$file->write(sprintf('%1$s[%2$s]%1$s', PHP_EOL, $name));
|
||||
|
||||
foreach ($entries as $key => $value) {
|
||||
$file->write(sprintf('%s = %s%s', $key, $value, PHP_EOL));
|
||||
}
|
||||
}
|
||||
|
||||
$file->flush();
|
||||
$file->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the config file.
|
||||
* @param string $filename
|
||||
* @return array
|
||||
* @throws \Misuzu\IO\FileDoesNotExistException
|
||||
* @throws \Misuzu\IO\IOException
|
||||
*/
|
||||
private static function read(string $filename): array
|
||||
{
|
||||
$collection = [];
|
||||
$section = null;
|
||||
$key = null;
|
||||
$value = null;
|
||||
|
||||
$file = new FileStream($filename, FileStream::MODE_READ);
|
||||
$lines = explode("\n", $file->read($file->length));
|
||||
$file->close();
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$line = trim($line, "\r\n");
|
||||
$length = mb_strlen($line);
|
||||
|
||||
if ($length < 1
|
||||
|| starts_with($line, '#')
|
||||
|| starts_with($line, ';')
|
||||
|| starts_with($line, '//')
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (starts_with($line, '[') && ends_with($line, ']')) {
|
||||
$section = rtrim(ltrim($line, '['), ']');
|
||||
|
||||
if (!isset($collection[$section])) {
|
||||
$collection[$section] = [];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mb_strpos($line, '=') !== false) {
|
||||
$split = explode('=', $line, 2);
|
||||
|
||||
if (count($split) < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$key = trim($split[0]);
|
||||
$value = trim($split[1]);
|
||||
|
||||
if (mb_strlen($key) > 0 && mb_strlen($value) > 0) {
|
||||
$collection[$section][$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
namespace Misuzu;
|
||||
|
||||
use Misuzu\Config\ConfigManager;
|
||||
use PDO;
|
||||
use PDOStatement;
|
||||
use InvalidArgumentException;
|
||||
|
@ -37,11 +36,6 @@ final class Database
|
|||
*/
|
||||
private $connections = [];
|
||||
|
||||
/**
|
||||
* @var ConfigManager
|
||||
*/
|
||||
private $configManager;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
|
@ -62,7 +56,7 @@ final class Database
|
|||
}
|
||||
|
||||
public function __construct(
|
||||
ConfigManager $config,
|
||||
array $connections,
|
||||
string $default = 'default'
|
||||
) {
|
||||
if (self::hasInstance()) {
|
||||
|
@ -71,7 +65,10 @@ final class Database
|
|||
|
||||
self::$instance = $this;
|
||||
$this->default = $default;
|
||||
$this->configManager = $config;
|
||||
|
||||
foreach ($connections as $name => $info) {
|
||||
$this->addConnection($info, $name);
|
||||
}
|
||||
}
|
||||
|
||||
public static function connection(?string $name = null): PDO
|
||||
|
@ -110,21 +107,17 @@ final class Database
|
|||
return $this->connections[$name] ?? $this->addConnection($name);
|
||||
}
|
||||
|
||||
public function addConnection(string $name): PDO
|
||||
public function addConnection(array $info, string $name): PDO
|
||||
{
|
||||
$section = "Database.{$name}";
|
||||
|
||||
if (!$this->configManager->contains($section, 'driver')) {
|
||||
if (!array_key_exists('driver', $info)) {
|
||||
throw new InvalidArgumentException('Config section not found!');
|
||||
}
|
||||
|
||||
$driver = $this->configManager->get($section, 'driver');
|
||||
|
||||
if (!in_array($driver, self::SUPPORTED)) {
|
||||
if (!in_array($info['driver'], self::SUPPORTED)) {
|
||||
throw new InvalidArgumentException('Unsupported driver.');
|
||||
}
|
||||
|
||||
$dsn = $driver . ':';
|
||||
$dsn = $info['driver'] . ':';
|
||||
$options = [
|
||||
PDO::ATTR_CASE => PDO::CASE_NATURAL,
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
|
@ -133,40 +126,29 @@ final class Database
|
|||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
];
|
||||
|
||||
switch ($driver) {
|
||||
switch ($info['driver']) {
|
||||
case 'sqlite':
|
||||
if ($this->configManager->get($section, 'memory', 'bool', false)) {
|
||||
if ($info['memory']) {
|
||||
$dsn .= ':memory:';
|
||||
} else {
|
||||
$databasePath = realpath(
|
||||
$this->configManager->get($section, 'database', 'string', __DIR__ . '/../store/misuzu.db')
|
||||
);
|
||||
$databasePath = realpath($info['database'] ?? __DIR__ . '/../store/misuzu.db');
|
||||
|
||||
if ($databasePath === false) {
|
||||
throw new \UnexpectedValueException("Database does not exist.");
|
||||
throw new UnexpectedValueException("Database does not exist.");
|
||||
}
|
||||
|
||||
$dsn .= $databasePath . ';';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'mysql':
|
||||
$is_unix_socket = $this->configManager->contains($section, 'unix_socket');
|
||||
|
||||
if ($is_unix_socket) {
|
||||
$dsn .= 'unix_socket=' . $this->configManager->get($section, 'unix_socket', 'string') . ';';
|
||||
if ($info['unix_socket'] ?? false) {
|
||||
$dsn .= 'unix_socket=' . $info['unix_socket'] . ';';
|
||||
} else {
|
||||
$dsn .= 'host=' . $this->configManager->get($section, 'host', 'string', self::DEFAULT_HOST) . ';';
|
||||
$dsn .= 'port=' . $this->configManager->get($section, 'port', 'int', self::DEFAULT_PORT_MYSQL) . ';';
|
||||
$dsn .= 'host=' . ($info['host'] ?? self::DEFAULT_HOST) . ';';
|
||||
$dsn .= 'port=' . intval($info['port'] ?? self::DEFAULT_PORT_MYSQL) . ';';
|
||||
}
|
||||
|
||||
$dsn .= 'charset=' . (
|
||||
$this->configManager->contains($section, 'charset')
|
||||
? $this->configManager->get($section, 'charset', 'string')
|
||||
: 'utf8mb4'
|
||||
) . ';';
|
||||
|
||||
$dsn .= 'dbname=' . $this->configManager->get($section, 'database', 'string', 'misuzu') . ';';
|
||||
$dsn .= 'charset=' . ($info['charset'] ?? 'utf8mb4') . ';';
|
||||
$dsn .= 'dbname=' . ($info['database'] ?? 'misuzu') . ';';
|
||||
|
||||
$options[PDO::MYSQL_ATTR_INIT_COMMAND] = "
|
||||
SET SESSION
|
||||
|
@ -178,8 +160,8 @@ final class Database
|
|||
|
||||
$connection = new PDO(
|
||||
$dsn,
|
||||
$this->configManager->get($section, 'username', 'string', null),
|
||||
$this->configManager->get($section, 'password', 'string', null),
|
||||
($info['username'] ?? null),
|
||||
($info['password'] ?? null),
|
||||
$options
|
||||
);
|
||||
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
<?php
|
||||
namespace MisuzuTests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Misuzu\Config\ConfigManager;
|
||||
|
||||
define('CONFIG_FILE', sys_get_temp_dir() . '/MisuzuConfigTest' . time() . '.ini');
|
||||
|
||||
class ConfigTest extends TestCase
|
||||
{
|
||||
public function testMemoryConfigManager()
|
||||
{
|
||||
$config = new ConfigManager();
|
||||
$this->assertInstanceOf(ConfigManager::class, $config);
|
||||
|
||||
$config->set('TestCat', 'string_val', 'test', 'string');
|
||||
$config->set('TestCat', 'int_val', 25, 'int');
|
||||
$config->set('TestCat', 'bool_val', true, 'bool');
|
||||
|
||||
$this->assertEquals('test', $config->get('TestCat', 'string_val', 'string'));
|
||||
$this->assertEquals(25, $config->get('TestCat', 'int_val', 'int'));
|
||||
$this->assertEquals(true, $config->get('TestCat', 'bool_val', 'bool'));
|
||||
}
|
||||
|
||||
public function testConfigCreateSet()
|
||||
{
|
||||
$config = new ConfigManager(CONFIG_FILE);
|
||||
$this->assertInstanceOf(ConfigManager::class, $config);
|
||||
|
||||
$config->set('TestCat', 'string_val', 'test', 'string');
|
||||
$config->set('TestCat', 'int_val', 25, 'int');
|
||||
$config->set('TestCat', 'bool_val', true, 'bool');
|
||||
|
||||
$this->assertEquals('test', $config->get('TestCat', 'string_val', 'string'));
|
||||
$this->assertEquals(25, $config->get('TestCat', 'int_val', 'int'));
|
||||
$this->assertEquals(true, $config->get('TestCat', 'bool_val', 'bool'));
|
||||
|
||||
$config->save();
|
||||
}
|
||||
|
||||
public function testConfigReadGet()
|
||||
{
|
||||
$config = new ConfigManager(CONFIG_FILE);
|
||||
$this->assertInstanceOf(ConfigManager::class, $config);
|
||||
|
||||
$this->assertEquals('test', $config->get('TestCat', 'string_val', 'string'));
|
||||
$this->assertEquals(25, $config->get('TestCat', 'int_val', 'int'));
|
||||
$this->assertEquals(true, $config->get('TestCat', 'bool_val', 'bool'));
|
||||
}
|
||||
|
||||
public function testConfigRemove()
|
||||
{
|
||||
$config = new ConfigManager(CONFIG_FILE);
|
||||
$this->assertInstanceOf(ConfigManager::class, $config);
|
||||
|
||||
$this->assertTrue($config->contains('TestCat', 'string_val'));
|
||||
$config->remove('TestCat', 'string_val');
|
||||
|
||||
$config->save();
|
||||
$config->load();
|
||||
|
||||
$this->assertFalse($config->contains('TestCat', 'string_val'));
|
||||
|
||||
// tack this onto here, deletes the entire file because we're done with it
|
||||
\Misuzu\IO\File::delete(CONFIG_FILE);
|
||||
}
|
||||
}
|
47
utility.php
47
utility.php
|
@ -1,12 +1,12 @@
|
|||
<?php
|
||||
function starts_with(string $string, string $text): bool
|
||||
{
|
||||
return substr($string, 0, strlen($text)) === $text;
|
||||
return mb_substr($string, 0, mb_strlen($text)) === $text;
|
||||
}
|
||||
|
||||
function ends_with(string $string, string $text): bool
|
||||
{
|
||||
return substr($string, 0 - strlen($text)) === $text;
|
||||
return mb_substr($string, 0 - mb_strlen($text)) === $text;
|
||||
}
|
||||
|
||||
function array_test(array $array, callable $func): bool
|
||||
|
@ -40,7 +40,7 @@ function password_entropy(string $password): int
|
|||
|
||||
function check_mx_record(string $email): bool
|
||||
{
|
||||
$domain = substr(strstr($email, '@'), 1);
|
||||
$domain = mb_substr(mb_strstr($email, '@'), 1);
|
||||
return checkdnsrr($domain, 'MX') || checkdnsrr($domain, 'A');
|
||||
}
|
||||
|
||||
|
@ -78,29 +78,8 @@ function byte_symbol($bytes, $decimal = false)
|
|||
|
||||
function get_country_code(string $ipAddr, string $fallback = 'XX'): string
|
||||
{
|
||||
global $_msz_geoip;
|
||||
|
||||
try {
|
||||
if (!$_msz_geoip) {
|
||||
$app = \Misuzu\Application::getInstance();
|
||||
$config = $app->getConfig();
|
||||
|
||||
if ($config === null) {
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
$database_path = $config->get('GeoIP', 'database_path');
|
||||
|
||||
if ($database_path === null) {
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
$_msz_geoip = new \GeoIp2\Database\Reader($database_path);
|
||||
}
|
||||
|
||||
$record = $_msz_geoip->country($ipAddr);
|
||||
|
||||
return $record->country->isoCode;
|
||||
return \Misuzu\Application::geoip()->country($ipAddr)->country->isoCode ?? $fallback;
|
||||
} catch (\Exception $e) {
|
||||
// report error?
|
||||
}
|
||||
|
@ -186,7 +165,7 @@ function crop_image_centred(Imagick $image, int $target_width, int $target_heigh
|
|||
|
||||
function running_on_windows(): bool
|
||||
{
|
||||
return starts_with(strtolower(PHP_OS), 'win');
|
||||
return starts_with(mb_strtolower(PHP_OS), 'win');
|
||||
}
|
||||
|
||||
function first_paragraph(string $text, string $delimiter = "\n"): string
|
||||
|
@ -227,7 +206,7 @@ function parse_bbcode(string $text): string
|
|||
|
||||
function is_local_url(string $url): bool
|
||||
{
|
||||
$length = strlen($url);
|
||||
$length = mb_strlen($url);
|
||||
|
||||
if ($length < 1) {
|
||||
return false;
|
||||
|
@ -243,7 +222,7 @@ function is_local_url(string $url): bool
|
|||
|
||||
function parse_text(string $text, string $parser): string
|
||||
{
|
||||
switch (strtolower($parser)) {
|
||||
switch (mb_strtolower($parser)) {
|
||||
case 'md':
|
||||
case 'markdown':
|
||||
return \Misuzu\Parsers\MarkdownParser::instance()->parseText($text);
|
||||
|
@ -259,7 +238,7 @@ function parse_text(string $text, string $parser): string
|
|||
|
||||
function parse_line(string $line, string $parser): string
|
||||
{
|
||||
switch (strtolower($parser)) {
|
||||
switch (mb_strtolower($parser)) {
|
||||
case 'md':
|
||||
case 'markdown':
|
||||
return \Misuzu\Parsers\MarkdownParser::instance()->parseLine($line);
|
||||
|
@ -285,7 +264,7 @@ function render_info(?string $message, int $httpCode, string $template = 'errors
|
|||
try {
|
||||
tpl_var('http_code', $httpCode);
|
||||
|
||||
if (strlen($message)) {
|
||||
if (mb_strlen($message)) {
|
||||
tpl_var('message', $message);
|
||||
}
|
||||
|
||||
|
@ -322,7 +301,7 @@ function html_link(string $url, ?string $content = null, $attributes = []): stri
|
|||
['href' => $url]
|
||||
);
|
||||
|
||||
if (strpos($url, '://') !== false) {
|
||||
if (mb_strpos($url, '://') !== false) {
|
||||
$attributes['target'] = '_blank';
|
||||
$attributes['rel'] = 'noreferrer noopener';
|
||||
}
|
||||
|
@ -362,7 +341,7 @@ function url_construct(string $path, array $query = [], string $host = ''): stri
|
|||
$url = $host . $path;
|
||||
|
||||
if (count($query)) {
|
||||
$url .= strpos($path, '?') !== false ? '&' : '?';
|
||||
$url .= mb_strpos($path, '?') !== false ? '&' : '?';
|
||||
|
||||
foreach ($query as $key => $value) {
|
||||
if ($value) {
|
||||
|
@ -371,12 +350,12 @@ function url_construct(string $path, array $query = [], string $host = ''): stri
|
|||
}
|
||||
}
|
||||
|
||||
return substr($url, 0, -1);
|
||||
return mb_substr($url, 0, -1);
|
||||
}
|
||||
|
||||
function camel_to_snake(string $camel): string
|
||||
{
|
||||
return trim(strtolower(preg_replace('#([A-Z][a-z]+)#', '$1_', $camel)), '_');
|
||||
return trim(mb_strtolower(preg_replace('#([A-Z][a-z]+)#', '$1_', $camel)), '_');
|
||||
}
|
||||
|
||||
function snake_to_camel(string $snake): string
|
||||
|
|
Loading…
Add table
Reference in a new issue