mirror of
https://github.com/vichan-devel/vichan.git
synced 2024-11-28 09:20:58 +01:00
Merge pull request #784 from Zankaria/micro-di
(What should be a) much better Dependency Injection implementation
This commit is contained in:
commit
f3e81c80d9
@ -1,66 +1,58 @@
|
||||
<?php
|
||||
namespace Vichan;
|
||||
|
||||
use RuntimeException;
|
||||
use Vichan\Driver\{HttpDriver, HttpDrivers, Log, LogDrivers};
|
||||
|
||||
defined('TINYBOARD') or exit;
|
||||
|
||||
|
||||
interface DependencyFactory {
|
||||
public function buildLogDriver(): Log;
|
||||
public function buildHttpDriver(): HttpDriver;
|
||||
}
|
||||
|
||||
class WebDependencyFactory implements DependencyFactory {
|
||||
private array $config;
|
||||
|
||||
|
||||
public function __construct(array $config) {
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function buildLogDriver(): Log {
|
||||
$name = $this->config['log_system']['name'];
|
||||
$level = $this->config['debug'] ? Log::DEBUG : Log::NOTICE;
|
||||
$backend = $this->config['log_system']['type'];
|
||||
|
||||
// Check 'syslog' for backwards compatibility.
|
||||
if ((isset($this->config['syslog']) && $this->config['syslog']) || $backend === 'syslog') {
|
||||
return LogDrivers::syslog($name, $level, $this->config['log_system']['syslog_stderr']);
|
||||
} elseif ($backend === 'file') {
|
||||
return LogDrivers::file($name, $level, $this->config['log_system']['file_path']);
|
||||
} elseif ($backend === 'stderr') {
|
||||
return LogDrivers::stderr($name, $level);
|
||||
} elseif ($backend === 'none') {
|
||||
return LogDrivers::none();
|
||||
} else {
|
||||
return LogDrivers::error_log($name, $level);
|
||||
}
|
||||
}
|
||||
|
||||
public function buildHttpDriver(): HttpDriver {
|
||||
return HttpDrivers::getHttpDriver(
|
||||
$this->config['upload_by_url_timeout'],
|
||||
$this->config['max_filesize']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Context {
|
||||
private DependencyFactory $factory;
|
||||
private ?Log $log;
|
||||
private ?HttpDriver $http;
|
||||
private array $definitions;
|
||||
|
||||
|
||||
public function __construct(DependencyFactory $factory) {
|
||||
$this->factory = $factory;
|
||||
public function __construct(array $definitions) {
|
||||
$this->definitions = $definitions;
|
||||
}
|
||||
|
||||
public function getLog(): Log {
|
||||
return $this->log ??= $this->factory->buildLogDriver();
|
||||
}
|
||||
public function get(string $name): mixed {
|
||||
if (!isset($this->definitions[$name])) {
|
||||
throw new RuntimeException("Could not find a dependency named $name");
|
||||
}
|
||||
|
||||
public function getHttpDriver(): HttpDriver {
|
||||
return $this->http ??= $this->factory->buildHttpDriver();
|
||||
$ret = $this->definitions[$name];
|
||||
if (is_callable($ret) && !is_string($ret) && !is_array($ret)) {
|
||||
$ret = $ret($this);
|
||||
$this->definitions[$name] = $ret;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
function build_context(array $config): Context {
|
||||
return new Context([
|
||||
'config' => $config,
|
||||
Log::class => function($c) {
|
||||
$config = $c->get('config');
|
||||
|
||||
$name = $config['log_system']['name'];
|
||||
$level = $config['debug'] ? Log::DEBUG : Log::NOTICE;
|
||||
$backend = $config['log_system']['type'];
|
||||
|
||||
// Check 'syslog' for backwards compatibility.
|
||||
if ((isset($config['syslog']) && $config['syslog']) || $backend === 'syslog') {
|
||||
return LogDrivers::syslog($name, $level, $this->config['log_system']['syslog_stderr']);
|
||||
} elseif ($backend === 'file') {
|
||||
return LogDrivers::file($name, $level, $this->config['log_system']['file_path']);
|
||||
} elseif ($backend === 'stderr') {
|
||||
return LogDrivers::stderr($name, $level);
|
||||
} elseif ($backend === 'none') {
|
||||
return LogDrivers::none();
|
||||
} else {
|
||||
return LogDrivers::error_log($name, $level);
|
||||
}
|
||||
},
|
||||
HttpDriver::class => function($c) {
|
||||
$config = $c->get('config');
|
||||
return HttpDrivers::getHttpDriver($config['upload_by_url_timeout'], $config['max_filesize']);
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
28
post.php
28
post.php
@ -207,7 +207,7 @@ function delete_cyclical_posts(string $boardUri, int $threadId, int $cycleLimit)
|
||||
*/
|
||||
|
||||
$dropped_post = false;
|
||||
$context = new Context(new WebDependencyFactory($config));
|
||||
$context = Vichan\build_context($config);
|
||||
|
||||
// Is it a post coming from NNTP? Let's extract it and pretend it's a normal post.
|
||||
if (isset($_GET['Newsgroups']) && $config['nntpchan']['enabled']) {
|
||||
@ -286,7 +286,7 @@ if (isset($_GET['Newsgroups']) && $config['nntpchan']['enabled']) {
|
||||
$content = file_get_contents("php://input");
|
||||
}
|
||||
elseif ($ct == 'multipart/mixed' || $ct == 'multipart/form-data') {
|
||||
$context->getLog()->log(Log::DEBUG, 'MM: Files: ' . print_r($GLOBALS, true));
|
||||
$context->get(Log::class)->log(Log::DEBUG, 'MM: Files: ' . print_r($GLOBALS, true));
|
||||
|
||||
$content = '';
|
||||
|
||||
@ -454,7 +454,7 @@ if (isset($_POST['delete'])) {
|
||||
modLog("User at $ip deleted their own post #$id");
|
||||
}
|
||||
|
||||
$context->getLog()->log(
|
||||
$context->get(Log::class)->log(
|
||||
Log::INFO,
|
||||
'Deleted post: /' . $board['dir'] . $config['dir']['res'] . link_for($post) . ($post['thread'] ? '#' . $id : '')
|
||||
);
|
||||
@ -517,7 +517,7 @@ if (isset($_POST['delete'])) {
|
||||
|
||||
try {
|
||||
$query = new NativeCaptchaQuery(
|
||||
$context->getHttpDriver(),
|
||||
$context->get(HttpDriver::class),
|
||||
$config['domain'],
|
||||
$config['captcha']['provider_check']
|
||||
);
|
||||
@ -531,7 +531,7 @@ if (isset($_POST['delete'])) {
|
||||
error($config['error']['captcha']);
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
$context->getLog()->log(Log::ERROR, "Native captcha IO exception: {$e->getMessage()}");
|
||||
$context->get(Log::class)->log(Log::ERROR, "Native captcha IO exception: {$e->getMessage()}");
|
||||
error($config['error']['local_io_error']);
|
||||
}
|
||||
}
|
||||
@ -550,7 +550,7 @@ if (isset($_POST['delete'])) {
|
||||
|
||||
$post = $query->fetch(PDO::FETCH_ASSOC);
|
||||
if ($post === false) {
|
||||
$context->getLog()->log(Log::INFO, "Failed to report non-existing post #{$id} in {$board['dir']}");
|
||||
$context->get(Log::class)->log(Log::INFO, "Failed to report non-existing post #{$id} in {$board['dir']}");
|
||||
error($config['error']['nopost']);
|
||||
}
|
||||
|
||||
@ -559,7 +559,7 @@ if (isset($_POST['delete'])) {
|
||||
error($error);
|
||||
}
|
||||
|
||||
$context->getLog()->log(
|
||||
$context->get(Log::class)->log(
|
||||
Log::INFO,
|
||||
'Reported post: /'
|
||||
. $board['dir'] . $config['dir']['res'] . link_for($post) . ($post['thread'] ? '#' . $id : '')
|
||||
@ -631,7 +631,7 @@ if (isset($_POST['delete'])) {
|
||||
try {
|
||||
// With our custom captcha provider
|
||||
if ($config['captcha']['enabled'] || ($post['op'] && $config['new_thread_capt'])) {
|
||||
$query = new NativeCaptchaQuery($context->getHttpDriver(), $config['domain'], $config['captcha']['provider_check']);
|
||||
$query = new NativeCaptchaQuery($context->get(HttpDriver::class), $config['domain'], $config['captcha']['provider_check']);
|
||||
$success = $query->verify($config['captcha']['extra'], $_POST['captcha_text'], $_POST['captcha_cookie']);
|
||||
|
||||
if (!$success) {
|
||||
@ -655,7 +655,7 @@ if (isset($_POST['delete'])) {
|
||||
error($config['error']['bot']);
|
||||
}
|
||||
$response = $_POST['g-recaptcha-response'];
|
||||
$query = RemoteCaptchaQuery::withRecaptcha($context->getHttpDriver(), $config['recaptcha_private']);
|
||||
$query = RemoteCaptchaQuery::withRecaptcha($context->get(HttpDriver::class), $config['recaptcha_private']);
|
||||
}
|
||||
// hCaptcha
|
||||
elseif ($config['hcaptcha']) {
|
||||
@ -663,7 +663,7 @@ if (isset($_POST['delete'])) {
|
||||
error($config['error']['bot']);
|
||||
}
|
||||
$response = $_POST['h-captcha-response'];
|
||||
$query = RemoteCaptchaQuery::withHCaptcha($context->getHttpDriver(), $config['hcaptcha_private']);
|
||||
$query = RemoteCaptchaQuery::withHCaptcha($context->get(HttpDriver::class), $config['hcaptcha_private']);
|
||||
}
|
||||
|
||||
if (isset($query, $response)) {
|
||||
@ -785,7 +785,7 @@ if (isset($_POST['delete'])) {
|
||||
|
||||
try {
|
||||
$ret = download_file_from_url(
|
||||
$context->getHttpDriver(),
|
||||
$context->get(HttpDriver::class),
|
||||
$_POST['file_url'],
|
||||
$config['upload_by_url_timeout'],
|
||||
$allowed_extensions,
|
||||
@ -1163,7 +1163,7 @@ if (isset($_POST['delete'])) {
|
||||
try {
|
||||
$file['size'] = strip_image_metadata($file['tmp_name']);
|
||||
} catch (RuntimeException $e) {
|
||||
$context->getLog()->log(Log::ERROR, "Could not strip image metadata: {$e->getMessage()}");
|
||||
$context->get(Log::class)->log(Log::ERROR, "Could not strip image metadata: {$e->getMessage()}");
|
||||
// Since EXIF metadata can countain sensible info, fail the request.
|
||||
error(_('Could not strip EXIF metadata!'), null, $error);
|
||||
}
|
||||
@ -1201,7 +1201,7 @@ if (isset($_POST['delete'])) {
|
||||
$post['body_nomarkup'] .= "<tinyboard ocr image $key>" . htmlspecialchars($value) . "</tinyboard>";
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
$context->getLog()->log(Log::ERROR, "Could not OCR image: {$e->getMessage()}");
|
||||
$context->get(Log::class)->log(Log::ERROR, "Could not OCR image: {$e->getMessage()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1395,7 +1395,7 @@ if (isset($_POST['delete'])) {
|
||||
|
||||
buildThread($post['op'] ? $id : $post['thread']);
|
||||
|
||||
$context->getLog()->log(
|
||||
$context->get(Log::class)->log(
|
||||
Log::INFO,
|
||||
'New post: /' . $board['dir'] . $config['dir']['res'] . link_for($post) . (!$post['op'] ? '#' . $id : '')
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user