forked from leftypol/leftypol
Merge branch 'context-port' into 'config'
Context and cache port See merge request leftypol/leftypol!14
This commit is contained in:
commit
5ec59a9a0f
20 changed files with 684 additions and 491 deletions
11
compose.yml
11
compose.yml
|
@ -23,6 +23,7 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- ./local-instances/${INSTANCE:-0}/www:/var/www
|
- ./local-instances/${INSTANCE:-0}/www:/var/www
|
||||||
- ./docker/php/www.conf:/usr/local/etc/php-fpm.d/www.conf
|
- ./docker/php/www.conf:/usr/local/etc/php-fpm.d/www.conf
|
||||||
|
- redis-sock:/var/run/redis
|
||||||
|
|
||||||
#MySQL Service
|
#MySQL Service
|
||||||
db:
|
db:
|
||||||
|
@ -36,3 +37,13 @@ services:
|
||||||
MYSQL_ROOT_PASSWORD: password
|
MYSQL_ROOT_PASSWORD: password
|
||||||
volumes:
|
volumes:
|
||||||
- ./local-instances/${INSTANCE:-0}/mysql:/var/lib/mysql
|
- ./local-instances/${INSTANCE:-0}/mysql:/var/lib/mysql
|
||||||
|
|
||||||
|
redis:
|
||||||
|
build:
|
||||||
|
context: ./
|
||||||
|
dockerfile: ./docker/redis/Dockerfile
|
||||||
|
volumes:
|
||||||
|
- redis-sock:/var/run/redis
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
redis-sock:
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
"files": [
|
"files": [
|
||||||
"inc/anti-bot.php",
|
"inc/anti-bot.php",
|
||||||
"inc/bootstrap.php",
|
"inc/bootstrap.php",
|
||||||
|
"inc/context.php",
|
||||||
"inc/display.php",
|
"inc/display.php",
|
||||||
"inc/template.php",
|
"inc/template.php",
|
||||||
"inc/database.php",
|
"inc/database.php",
|
||||||
|
|
6
docker/redis/Dockerfile
Normal file
6
docker/redis/Dockerfile
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
FROM redis:7.4-alpine
|
||||||
|
|
||||||
|
RUN mkdir -p /var/run/redis && chmod 777 /var/run/redis
|
||||||
|
COPY ./docker/redis/redis.conf /etc/redis.conf
|
||||||
|
|
||||||
|
ENTRYPOINT [ "docker-entrypoint.sh", "/etc/redis.conf" ]
|
16
docker/redis/redis.conf
Normal file
16
docker/redis/redis.conf
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# Accept connections on the specified port, default is 6379 (IANA #815344).
|
||||||
|
# If port 0 is specified Redis will not listen on a TCP socket.
|
||||||
|
#port 6379
|
||||||
|
port 0
|
||||||
|
|
||||||
|
# Unix socket.
|
||||||
|
#
|
||||||
|
# Specify the path for the Unix socket that will be used to listen for
|
||||||
|
# incoming connections. There is no default, so Redis will not listen
|
||||||
|
# on a unix socket when not specified.
|
||||||
|
#
|
||||||
|
unixsocket /var/run/redis/redis-server.sock
|
||||||
|
# Executig a socket is a no-op, and we need to share acces to other programs.
|
||||||
|
# Shared the connection only with programs in the redis group for security.
|
||||||
|
#unixsocketperm 700
|
||||||
|
unixsocketperm 666
|
28
inc/Data/Driver/ApcuCacheDriver.php
Normal file
28
inc/Data/Driver/ApcuCacheDriver.php
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
namespace Vichan\Data\Driver;
|
||||||
|
|
||||||
|
defined('TINYBOARD') or exit;
|
||||||
|
|
||||||
|
|
||||||
|
class ApcuCacheDriver implements CacheDriver {
|
||||||
|
public function get(string $key): mixed {
|
||||||
|
$success = false;
|
||||||
|
$ret = \apcu_fetch($key, $success);
|
||||||
|
if ($success === false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(string $key, mixed $value, mixed $expires = false): void {
|
||||||
|
\apcu_store($key, $value, (int)$expires);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(string $key): void {
|
||||||
|
\apcu_delete($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function flush(): void {
|
||||||
|
\apcu_clear_cache();
|
||||||
|
}
|
||||||
|
}
|
28
inc/Data/Driver/ArrayCacheDriver.php
Normal file
28
inc/Data/Driver/ArrayCacheDriver.php
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
namespace Vichan\Data\Driver;
|
||||||
|
|
||||||
|
defined('TINYBOARD') or exit;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple process-wide PHP array.
|
||||||
|
*/
|
||||||
|
class ArrayCacheDriver implements CacheDriver {
|
||||||
|
private static array $inner = [];
|
||||||
|
|
||||||
|
public function get(string $key): mixed {
|
||||||
|
return isset(self::$inner[$key]) ? self::$inner[$key] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(string $key, mixed $value, mixed $expires = false): void {
|
||||||
|
self::$inner[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(string $key): void {
|
||||||
|
unset(self::$inner[$key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function flush(): void {
|
||||||
|
self::$inner = [];
|
||||||
|
}
|
||||||
|
}
|
38
inc/Data/Driver/CacheDriver.php
Normal file
38
inc/Data/Driver/CacheDriver.php
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
namespace Vichan\Data\Driver;
|
||||||
|
|
||||||
|
defined('TINYBOARD') or exit;
|
||||||
|
|
||||||
|
|
||||||
|
interface CacheDriver {
|
||||||
|
/**
|
||||||
|
* Get the value of associated with the key.
|
||||||
|
*
|
||||||
|
* @param string $key The key of the value.
|
||||||
|
* @return mixed|null The value associated with the key, or null if there is none.
|
||||||
|
*/
|
||||||
|
public function get(string $key): mixed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a key-value pair.
|
||||||
|
*
|
||||||
|
* @param string $key The key.
|
||||||
|
* @param mixed $value The value.
|
||||||
|
* @param int|false $expires After how many seconds the pair will expire. Use false or ignore this parameter to keep
|
||||||
|
* the value until it gets evicted to make space for more items. Some drivers will always
|
||||||
|
* ignore this parameter and store the pair until it's removed.
|
||||||
|
*/
|
||||||
|
public function set(string $key, mixed $value, mixed $expires = false): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a key-value pair.
|
||||||
|
*
|
||||||
|
* @param string $key The key.
|
||||||
|
*/
|
||||||
|
public function delete(string $key): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all the key-value pairs.
|
||||||
|
*/
|
||||||
|
public function flush(): void;
|
||||||
|
}
|
155
inc/Data/Driver/FsCachedriver.php
Normal file
155
inc/Data/Driver/FsCachedriver.php
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
<?php
|
||||||
|
namespace Vichan\Data\Driver;
|
||||||
|
|
||||||
|
defined('TINYBOARD') or exit;
|
||||||
|
|
||||||
|
|
||||||
|
class FsCacheDriver implements CacheDriver {
|
||||||
|
private string $prefix;
|
||||||
|
private string $base_path;
|
||||||
|
private mixed $lock_fd;
|
||||||
|
private int|false $collect_chance_den;
|
||||||
|
|
||||||
|
|
||||||
|
private function prepareKey(string $key): string {
|
||||||
|
$key = \str_replace('/', '::', $key);
|
||||||
|
$key = \str_replace("\0", '', $key);
|
||||||
|
return $this->prefix . $key;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sharedLockCache(): void {
|
||||||
|
\flock($this->lock_fd, LOCK_SH);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function exclusiveLockCache(): void {
|
||||||
|
\flock($this->lock_fd, LOCK_EX);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function unlockCache(): void {
|
||||||
|
\flock($this->lock_fd, LOCK_UN);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function collectImpl(): int {
|
||||||
|
/*
|
||||||
|
* A read lock is ok, since it's alright if we delete expired items from under the feet of other processes, and
|
||||||
|
* no other process add new cache items or refresh existing ones.
|
||||||
|
*/
|
||||||
|
$files = \glob($this->base_path . $this->prefix . '*', \GLOB_NOSORT);
|
||||||
|
$count = 0;
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$data = \file_get_contents($file);
|
||||||
|
$wrapped = \json_decode($data, true, 512, \JSON_THROW_ON_ERROR);
|
||||||
|
if ($wrapped['expires'] !== false && $wrapped['expires'] <= \time()) {
|
||||||
|
if (@\unlink($file)) {
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function maybeCollect(): void {
|
||||||
|
if ($this->collect_chance_den !== false && \mt_rand(0, $this->collect_chance_den - 1) === 0) {
|
||||||
|
$this->collect_chance_den = false; // Collect only once per instance (aka process).
|
||||||
|
$this->collectImpl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct(string $prefix, string $base_path, string $lock_file, int|false $collect_chance_den) {
|
||||||
|
if ($base_path[\strlen($base_path) - 1] !== '/') {
|
||||||
|
$base_path = "$base_path/";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!\is_dir($base_path)) {
|
||||||
|
throw new \RuntimeException("$base_path is not a directory!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!\is_writable($base_path)) {
|
||||||
|
throw new \RuntimeException("$base_path is not writable!");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->lock_fd = \fopen($base_path . $lock_file, 'w');
|
||||||
|
if ($this->lock_fd === false) {
|
||||||
|
throw new \RuntimeException('Unable to open the lock file!');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->prefix = $prefix;
|
||||||
|
$this->base_path = $base_path;
|
||||||
|
$this->collect_chance_den = $collect_chance_den;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __destruct() {
|
||||||
|
$this->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(string $key): mixed {
|
||||||
|
$key = $this->prepareKey($key);
|
||||||
|
|
||||||
|
$this->sharedLockCache();
|
||||||
|
|
||||||
|
// Collect expired items first so if the target key is expired we shortcut to failure in the next lines.
|
||||||
|
$this->maybeCollect();
|
||||||
|
|
||||||
|
$fd = \fopen($this->base_path . $key, 'r');
|
||||||
|
if ($fd === false) {
|
||||||
|
$this->unlockCache();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = \stream_get_contents($fd);
|
||||||
|
\fclose($fd);
|
||||||
|
$this->unlockCache();
|
||||||
|
$wrapped = \json_decode($data, true, 512, \JSON_THROW_ON_ERROR);
|
||||||
|
|
||||||
|
if ($wrapped['expires'] !== false && $wrapped['expires'] <= \time()) {
|
||||||
|
// Already expired, leave it there since we already released the lock and pretend it doesn't exist.
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return $wrapped['inner'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(string $key, mixed $value, mixed $expires = false): void {
|
||||||
|
$key = $this->prepareKey($key);
|
||||||
|
|
||||||
|
$wrapped = [
|
||||||
|
'expires' => $expires ? \time() + $expires : false,
|
||||||
|
'inner' => $value
|
||||||
|
];
|
||||||
|
|
||||||
|
$data = \json_encode($wrapped);
|
||||||
|
$this->exclusiveLockCache();
|
||||||
|
$this->maybeCollect();
|
||||||
|
\file_put_contents($this->base_path . $key, $data);
|
||||||
|
$this->unlockCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(string $key): void {
|
||||||
|
$key = $this->prepareKey($key);
|
||||||
|
|
||||||
|
$this->exclusiveLockCache();
|
||||||
|
@\unlink($this->base_path . $key);
|
||||||
|
$this->maybeCollect();
|
||||||
|
$this->unlockCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function collect(): int {
|
||||||
|
$this->sharedLockCache();
|
||||||
|
$count = $this->collectImpl();
|
||||||
|
$this->unlockCache();
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function flush(): void {
|
||||||
|
$this->exclusiveLockCache();
|
||||||
|
$files = \glob($this->base_path . $this->prefix . '*', \GLOB_NOSORT);
|
||||||
|
foreach ($files as $file) {
|
||||||
|
@\unlink($file);
|
||||||
|
}
|
||||||
|
$this->unlockCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function close(): void {
|
||||||
|
\fclose($this->lock_fd);
|
||||||
|
}
|
||||||
|
}
|
43
inc/Data/Driver/MemcacheCacheDriver.php
Normal file
43
inc/Data/Driver/MemcacheCacheDriver.php
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
namespace Vichan\Data\Driver;
|
||||||
|
|
||||||
|
defined('TINYBOARD') or exit;
|
||||||
|
|
||||||
|
|
||||||
|
class MemcachedCacheDriver implements CacheDriver {
|
||||||
|
private \Memcached $inner;
|
||||||
|
|
||||||
|
public function __construct(string $prefix, string $memcached_server) {
|
||||||
|
$this->inner = new \Memcached();
|
||||||
|
if (!$this->inner->setOption(\Memcached::OPT_BINARY_PROTOCOL, true)) {
|
||||||
|
throw new \RuntimeException('Unable to set the memcached protocol!');
|
||||||
|
}
|
||||||
|
if (!$this->inner->setOption(\Memcached::OPT_PREFIX_KEY, $prefix)) {
|
||||||
|
throw new \RuntimeException('Unable to set the memcached prefix!');
|
||||||
|
}
|
||||||
|
if (!$this->inner->addServers($memcached_server)) {
|
||||||
|
throw new \RuntimeException('Unable to add the memcached server!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(string $key): mixed {
|
||||||
|
$ret = $this->inner->get($key);
|
||||||
|
// If the returned value is false but the retrival was a success, then the value stored was a boolean false.
|
||||||
|
if ($ret === false && $this->inner->getResultCode() !== \Memcached::RES_SUCCESS) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(string $key, mixed $value, mixed $expires = false): void {
|
||||||
|
$this->inner->set($key, $value, (int)$expires);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(string $key): void {
|
||||||
|
$this->inner->delete($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function flush(): void {
|
||||||
|
$this->inner->flush();
|
||||||
|
}
|
||||||
|
}
|
26
inc/Data/Driver/NoneCacheDriver.php
Normal file
26
inc/Data/Driver/NoneCacheDriver.php
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
namespace Vichan\Data\Driver;
|
||||||
|
|
||||||
|
defined('TINYBOARD') or exit;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No-op cache. Useful for testing.
|
||||||
|
*/
|
||||||
|
class NoneCacheDriver implements CacheDriver {
|
||||||
|
public function get(string $key): mixed {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(string $key, mixed $value, mixed $expires = false): void {
|
||||||
|
// No-op.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(string $key): void {
|
||||||
|
// No-op.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function flush(): void {
|
||||||
|
// No-op.
|
||||||
|
}
|
||||||
|
}
|
70
inc/Data/Driver/RedisCacheDriver.php
Normal file
70
inc/Data/Driver/RedisCacheDriver.php
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<?php
|
||||||
|
namespace Vichan\Data\Driver;
|
||||||
|
|
||||||
|
defined('TINYBOARD') or exit;
|
||||||
|
|
||||||
|
|
||||||
|
class RedisCacheDriver implements CacheDriver {
|
||||||
|
private string $prefix;
|
||||||
|
private \Redis $inner;
|
||||||
|
|
||||||
|
public function __construct(string $prefix, string $host, ?int $port, ?string $password, int $database) {
|
||||||
|
$this->inner = new \Redis();
|
||||||
|
if (str_starts_with($host, 'unix:') || str_starts_with($host, ':')) {
|
||||||
|
$ret = \explode(':', $host);
|
||||||
|
if (count($ret) < 2) {
|
||||||
|
throw new \RuntimeException("Invalid unix socket path $host");
|
||||||
|
}
|
||||||
|
// Unix socket.
|
||||||
|
$this->inner->connect($ret[1]);
|
||||||
|
} elseif ($port === null) {
|
||||||
|
$this->inner->connect($host);
|
||||||
|
} else {
|
||||||
|
// IP + port.
|
||||||
|
$this->inner->connect($host, $port);
|
||||||
|
}
|
||||||
|
if ($password) {
|
||||||
|
$this->inner->auth($password);
|
||||||
|
}
|
||||||
|
if (!$this->inner->setOption(\Redis::OPT_SERIALIZER, \Redis::SERIALIZER_JSON)) {
|
||||||
|
throw new \RuntimeException('Unable to configure Redis serializer');
|
||||||
|
}
|
||||||
|
if (!$this->inner->select($database)) {
|
||||||
|
throw new \RuntimeException('Unable to connect to Redis database!');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->prefix = $prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(string $key): mixed {
|
||||||
|
$ret = $this->inner->get($this->prefix . $key);
|
||||||
|
if ($ret === false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if ($ret === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(string $key, mixed $value, mixed $expires = false): void {
|
||||||
|
$value = $value === false ? null : $value;
|
||||||
|
if ($expires === false) {
|
||||||
|
$this->inner->set($this->prefix . $key, $value);
|
||||||
|
} else {
|
||||||
|
$this->inner->setEx($this->prefix . $key, $expires, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(string $key): void {
|
||||||
|
$this->inner->del($this->prefix . $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function flush(): void {
|
||||||
|
if (empty($this->prefix)) {
|
||||||
|
$this->inner->flushDB();
|
||||||
|
} else {
|
||||||
|
$this->inner->unlink($this->inner->keys("{$this->prefix}*"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
196
inc/cache.php
196
inc/cache.php
|
@ -4,183 +4,89 @@
|
||||||
* Copyright (c) 2010-2013 Tinyboard Development Group
|
* Copyright (c) 2010-2013 Tinyboard Development Group
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use Vichan\Data\Driver\{CacheDriver, ApcuCacheDriver, ArrayCacheDriver, FsCacheDriver, MemcachedCacheDriver, NoneCacheDriver, RedisCacheDriver};
|
||||||
|
|
||||||
defined('TINYBOARD') or exit;
|
defined('TINYBOARD') or exit;
|
||||||
|
|
||||||
|
|
||||||
class Cache {
|
class Cache {
|
||||||
private static $cache;
|
private static function buildCache(): CacheDriver {
|
||||||
public static function init() {
|
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
switch ($config['cache']['enabled']) {
|
switch ($config['cache']['enabled']) {
|
||||||
case 'memcached':
|
case 'memcached':
|
||||||
self::$cache = new Memcached();
|
return new MemcachedCacheDriver(
|
||||||
self::$cache->addServers($config['cache']['memcached']);
|
$config['cache']['prefix'],
|
||||||
break;
|
$config['cache']['memcached']
|
||||||
|
);
|
||||||
case 'redis':
|
case 'redis':
|
||||||
self::$cache = new Redis();
|
return new RedisCacheDriver(
|
||||||
|
$config['cache']['prefix'],
|
||||||
$ret = explode(':', $config['cache']['redis'][0]);
|
$config['cache']['redis'][0],
|
||||||
if (count($ret) > 0) {
|
$config['cache']['redis'][1],
|
||||||
// Unix socket.
|
$config['cache']['redis'][2],
|
||||||
self::$cache->connect($ret[1]);
|
$config['cache']['redis'][3]
|
||||||
} else {
|
);
|
||||||
// IP + port.
|
case 'apcu':
|
||||||
self::$cache->connect($ret[0], $config['cache']['redis'][1]);
|
return new ApcuCacheDriver;
|
||||||
}
|
case 'fs':
|
||||||
|
return new FsCacheDriver(
|
||||||
if ($config['cache']['redis'][2]) {
|
$config['cache']['prefix'],
|
||||||
self::$cache->auth($config['cache']['redis'][2]);
|
"tmp/cache/{$config['cache']['prefix']}",
|
||||||
}
|
'.lock',
|
||||||
self::$cache->select($config['cache']['redis'][3]) or die('cache select failure');
|
$config['auto_maintenance'] ? 1000 : false
|
||||||
break;
|
);
|
||||||
|
case 'none':
|
||||||
|
return new NoneCacheDriver();
|
||||||
case 'php':
|
case 'php':
|
||||||
self::$cache = array();
|
default:
|
||||||
break;
|
return new ArrayCacheDriver();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getCache(): CacheDriver {
|
||||||
|
static $cache;
|
||||||
|
return $cache ??= self::buildCache();
|
||||||
|
}
|
||||||
|
|
||||||
public static function get($key) {
|
public static function get($key) {
|
||||||
global $config, $debug;
|
global $config, $debug;
|
||||||
|
|
||||||
$key = $config['cache']['prefix'] . $key;
|
$ret = self::getCache()->get($key);
|
||||||
|
if ($ret === null) {
|
||||||
$data = false;
|
$ret = false;
|
||||||
switch ($config['cache']['enabled']) {
|
|
||||||
case 'memcached':
|
|
||||||
if (!self::$cache)
|
|
||||||
self::init();
|
|
||||||
$data = self::$cache->get($key);
|
|
||||||
break;
|
|
||||||
case 'apc':
|
|
||||||
$data = apc_fetch($key);
|
|
||||||
break;
|
|
||||||
case 'xcache':
|
|
||||||
$data = xcache_get($key);
|
|
||||||
break;
|
|
||||||
case 'php':
|
|
||||||
$data = isset(self::$cache[$key]) ? self::$cache[$key] : false;
|
|
||||||
break;
|
|
||||||
case 'fs':
|
|
||||||
$key = str_replace('/', '::', $key);
|
|
||||||
$key = str_replace("\0", '', $key);
|
|
||||||
if (!file_exists('tmp/cache/'.$key)) {
|
|
||||||
$data = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$data = file_get_contents('tmp/cache/'.$key);
|
|
||||||
$data = json_decode($data, true);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'redis':
|
|
||||||
if (!self::$cache)
|
|
||||||
self::init();
|
|
||||||
$ret = self::$cache->get($key);
|
|
||||||
$data = $ret !== false ? json_decode($ret, true) : false;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($config['debug'])
|
if ($config['debug']) {
|
||||||
$debug['cached'][] = $key . ($data === false ? ' (miss)' : ' (hit)');
|
$debug['cached'][] = $config['cache']['prefix'] . $key . ($ret === false ? ' (miss)' : ' (hit)');
|
||||||
|
}
|
||||||
|
|
||||||
return $data;
|
return $ret;
|
||||||
}
|
}
|
||||||
public static function set($key, $value, $expires = false) {
|
public static function set($key, $value, $expires = false) {
|
||||||
global $config, $debug;
|
global $config, $debug;
|
||||||
|
|
||||||
$key = $config['cache']['prefix'] . $key;
|
if (!$expires) {
|
||||||
|
|
||||||
if (!$expires)
|
|
||||||
$expires = $config['cache']['timeout'];
|
$expires = $config['cache']['timeout'];
|
||||||
|
|
||||||
switch ($config['cache']['enabled']) {
|
|
||||||
case 'memcached':
|
|
||||||
if (!self::$cache)
|
|
||||||
self::init();
|
|
||||||
self::$cache->set($key, $value, $expires);
|
|
||||||
break;
|
|
||||||
case 'redis':
|
|
||||||
if (!self::$cache)
|
|
||||||
self::init();
|
|
||||||
self::$cache->setEx($key, $expires, json_encode($value));
|
|
||||||
break;
|
|
||||||
case 'apc':
|
|
||||||
apc_store($key, $value, $expires);
|
|
||||||
break;
|
|
||||||
case 'xcache':
|
|
||||||
xcache_set($key, $value, $expires);
|
|
||||||
break;
|
|
||||||
case 'fs':
|
|
||||||
$key = str_replace('/', '::', $key);
|
|
||||||
$key = str_replace("\0", '', $key);
|
|
||||||
file_put_contents('tmp/cache/'.$key, json_encode($value));
|
|
||||||
break;
|
|
||||||
case 'php':
|
|
||||||
self::$cache[$key] = $value;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($config['debug'])
|
self::getCache()->set($key, $value, $expires);
|
||||||
$debug['cached'][] = $key . ' (set)';
|
|
||||||
|
if ($config['debug']) {
|
||||||
|
$debug['cached'][] = $config['cache']['prefix'] . $key . ' (set)';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public static function delete($key) {
|
public static function delete($key) {
|
||||||
global $config, $debug;
|
global $config, $debug;
|
||||||
|
|
||||||
$key = $config['cache']['prefix'] . $key;
|
self::getCache()->delete($key);
|
||||||
|
|
||||||
switch ($config['cache']['enabled']) {
|
if ($config['debug']) {
|
||||||
case 'memcached':
|
$debug['cached'][] = $config['cache']['prefix'] . $key . ' (deleted)';
|
||||||
if (!self::$cache)
|
|
||||||
self::init();
|
|
||||||
self::$cache->delete($key);
|
|
||||||
break;
|
|
||||||
case 'redis':
|
|
||||||
if (!self::$cache)
|
|
||||||
self::init();
|
|
||||||
self::$cache->del($key);
|
|
||||||
break;
|
|
||||||
case 'apc':
|
|
||||||
apc_delete($key);
|
|
||||||
break;
|
|
||||||
case 'xcache':
|
|
||||||
xcache_unset($key);
|
|
||||||
break;
|
|
||||||
case 'fs':
|
|
||||||
$key = str_replace('/', '::', $key);
|
|
||||||
$key = str_replace("\0", '', $key);
|
|
||||||
@unlink('tmp/cache/'.$key);
|
|
||||||
break;
|
|
||||||
case 'php':
|
|
||||||
unset(self::$cache[$key]);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($config['debug'])
|
|
||||||
$debug['cached'][] = $key . ' (deleted)';
|
|
||||||
}
|
}
|
||||||
public static function flush() {
|
public static function flush() {
|
||||||
global $config;
|
self::getCache()->flush();
|
||||||
|
|
||||||
switch ($config['cache']['enabled']) {
|
|
||||||
case 'memcached':
|
|
||||||
if (!self::$cache)
|
|
||||||
self::init();
|
|
||||||
return self::$cache->flush();
|
|
||||||
case 'apc':
|
|
||||||
return apc_clear_cache('user');
|
|
||||||
case 'php':
|
|
||||||
self::$cache = array();
|
|
||||||
break;
|
|
||||||
case 'fs':
|
|
||||||
$files = glob('tmp/cache/*');
|
|
||||||
foreach ($files as $file) {
|
|
||||||
unlink($file);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'redis':
|
|
||||||
if (!self::$cache)
|
|
||||||
self::init();
|
|
||||||
return self::$cache->flushDB();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,18 +117,26 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On top of the static file caching system, you can enable the additional caching system which is
|
* On top of the static file caching system, you can enable the additional caching system which is
|
||||||
* designed to minimize SQL queries and can significantly increase speed when posting or using the
|
* designed to minimize request processing can significantly increase speed when posting or using
|
||||||
* moderator interface. APC is the recommended method of caching.
|
* the moderator interface.
|
||||||
*
|
*
|
||||||
* http://tinyboard.org/docs/index.php?p=Config/Cache
|
* https://github.com/vichan-devel/vichan/wiki/cache
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Uses a PHP array. MUST NOT be used in multiprocess environments.
|
||||||
$config['cache']['enabled'] = 'php';
|
$config['cache']['enabled'] = 'php';
|
||||||
// $config['cache']['enabled'] = 'xcache';
|
// The recommended in-memory method of caching. Requires the extension. Due to how APCu works, this should be
|
||||||
// $config['cache']['enabled'] = 'apc';
|
// disabled when you run tools from the cli.
|
||||||
|
// $config['cache']['enabled'] = 'apcu';
|
||||||
|
// The Memcache server. Requires the memcached extension, with a final D.
|
||||||
// $config['cache']['enabled'] = 'memcached';
|
// $config['cache']['enabled'] = 'memcached';
|
||||||
|
// The Redis server. Requires the extension.
|
||||||
// $config['cache']['enabled'] = 'redis';
|
// $config['cache']['enabled'] = 'redis';
|
||||||
|
// Use the local cache folder. Slower than native but available out of the box and compatible with multiprocess
|
||||||
|
// environments. You can mount a ram-based filesystem in the cache directory to improve performance.
|
||||||
// $config['cache']['enabled'] = 'fs';
|
// $config['cache']['enabled'] = 'fs';
|
||||||
|
// Technically available, offers a no-op fake cache. Don't use this outside of testing or debugging.
|
||||||
|
// $config['cache']['enabled'] = 'none';
|
||||||
|
|
||||||
// Timeout for cached objects such as posts and HTML.
|
// Timeout for cached objects such as posts and HTML.
|
||||||
$config['cache']['timeout'] = 60 * 60 * 48; // 48 hours
|
$config['cache']['timeout'] = 60 * 60 * 48; // 48 hours
|
||||||
|
@ -144,7 +152,7 @@
|
||||||
// Redis server to use. Location, port, password, database id.
|
// Redis server to use. Location, port, password, database id.
|
||||||
// Note that Tinyboard may clear the database at times, so you may want to pick a database id just for
|
// Note that Tinyboard may clear the database at times, so you may want to pick a database id just for
|
||||||
// Tinyboard to use.
|
// Tinyboard to use.
|
||||||
$config['cache']['redis'] = array('localhost', 6379, '', 1);
|
$config['cache']['redis'] = [ 'localhost', 6379, null, 1 ];
|
||||||
|
|
||||||
// EXPERIMENTAL: Should we cache configs? Warning: this changes board behaviour, i'd say, a lot.
|
// EXPERIMENTAL: Should we cache configs? Warning: this changes board behaviour, i'd say, a lot.
|
||||||
// If you have any lambdas/includes present in your config, you should move them to instance-functions.php
|
// If you have any lambdas/includes present in your config, you should move them to instance-functions.php
|
||||||
|
|
38
inc/context.php
Normal file
38
inc/context.php
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
namespace Vichan;
|
||||||
|
|
||||||
|
use Vichan\Data\Driver\CacheDriver;
|
||||||
|
|
||||||
|
defined('TINYBOARD') or exit;
|
||||||
|
|
||||||
|
|
||||||
|
class Context {
|
||||||
|
private array $definitions;
|
||||||
|
|
||||||
|
public function __construct(array $definitions) {
|
||||||
|
$this->definitions = $definitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(string $name): mixed {
|
||||||
|
if (!isset($this->definitions[$name])) {
|
||||||
|
throw new \RuntimeException("Could not find a dependency named $name");
|
||||||
|
}
|
||||||
|
|
||||||
|
$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,
|
||||||
|
CacheDriver::class => function($c) {
|
||||||
|
// Use the global for backwards compatibility.
|
||||||
|
return \cache::getCache();
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
|
@ -4,6 +4,7 @@
|
||||||
* Copyright (c) 2010-2013 Tinyboard Development Group
|
* Copyright (c) 2010-2013 Tinyboard Development Group
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use Vichan\Context;
|
||||||
use Vichan\Functions\Net;
|
use Vichan\Functions\Net;
|
||||||
|
|
||||||
defined('TINYBOARD') or exit;
|
defined('TINYBOARD') or exit;
|
||||||
|
@ -177,7 +178,7 @@ function make_secure_link_token($uri) {
|
||||||
return substr(sha1($config['cookies']['salt'] . '-' . $uri . '-' . $mod['id']), 0, 8);
|
return substr(sha1($config['cookies']['salt'] . '-' . $uri . '-' . $mod['id']), 0, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
function check_login($prompt = false) {
|
function check_login(Context $ctx, $prompt = false) {
|
||||||
global $config, $mod;
|
global $config, $mod;
|
||||||
|
|
||||||
// Validate session
|
// Validate session
|
||||||
|
@ -187,7 +188,7 @@ function check_login($prompt = false) {
|
||||||
if (count($cookie) != 3) {
|
if (count($cookie) != 3) {
|
||||||
// Malformed cookies
|
// Malformed cookies
|
||||||
destroyCookies();
|
destroyCookies();
|
||||||
if ($prompt) mod_login();
|
if ($prompt) mod_login($ctx);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +201,7 @@ function check_login($prompt = false) {
|
||||||
if ($cookie[1] !== mkhash($cookie[0], $user['password'], $cookie[2])) {
|
if ($cookie[1] !== mkhash($cookie[0], $user['password'], $cookie[2])) {
|
||||||
// Malformed cookies
|
// Malformed cookies
|
||||||
destroyCookies();
|
destroyCookies();
|
||||||
if ($prompt) mod_login();
|
if ($prompt) mod_login($ctx);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2010-2013 Tinyboard Development Group
|
* Copyright (c) 2010-2013 Tinyboard Development Group
|
||||||
*/
|
*/
|
||||||
|
use Vichan\Context;
|
||||||
|
use Vichan\Functions\Format;
|
||||||
use Vichan\Functions\Net;
|
use Vichan\Functions\Net;
|
||||||
|
|
||||||
use function Vichan\Functions\Net\decode_cursor;
|
use function Vichan\Functions\Net\decode_cursor;
|
||||||
|
@ -45,7 +45,7 @@ function clone_wrapped_with_exist_check($clonefn, $src, $dest) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_login($redirect = false) {
|
function mod_login(Context $ctx, $redirect = false) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
$args = [];
|
$args = [];
|
||||||
|
@ -81,22 +81,22 @@ function mod_login($redirect = false) {
|
||||||
mod_page(_('Login'), 'mod/login.html', $args);
|
mod_page(_('Login'), 'mod/login.html', $args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_confirm($request) {
|
function mod_confirm(Context $ctx, $request) {
|
||||||
$args = array('request' => $request, 'token' => make_secure_link_token($request));
|
$args = [ 'request' => $request, 'token' => make_secure_link_token($request) ];
|
||||||
if(isset($_GET['thread'])) {
|
if(isset($_GET['thread'])) {
|
||||||
$args['rest'] = 'thread=' . $_GET['thread'];
|
$args['rest'] = 'thread=' . $_GET['thread'];
|
||||||
}
|
}
|
||||||
mod_page(_('Confirm action'), 'mod/confirm.html', $args);
|
mod_page(_('Confirm action'), 'mod/confirm.html', $args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_logout() {
|
function mod_logout(Context $ctx) {
|
||||||
global $config;
|
global $config;
|
||||||
destroyCookies();
|
destroyCookies();
|
||||||
|
|
||||||
header('Location: ?/', true, $config['redirect_http']);
|
header('Location: ?/', true, $config['redirect_http']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_dashboard() {
|
function mod_dashboard(Context $ctx) {
|
||||||
global $config, $mod;
|
global $config, $mod;
|
||||||
|
|
||||||
$args = [];
|
$args = [];
|
||||||
|
@ -190,7 +190,7 @@ function mod_dashboard() {
|
||||||
mod_page(_('Dashboard'), 'mod/dashboard.html', $args);
|
mod_page(_('Dashboard'), 'mod/dashboard.html', $args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_search_redirect() {
|
function mod_search_redirect(Context $ctx) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['search']))
|
if (!hasPermission($config['mod']['search']))
|
||||||
|
@ -213,7 +213,7 @@ function mod_search_redirect() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_search($type, $search_query_escaped, $page_no = 1) {
|
function mod_search(Context $ctx, $type, $search_query_escaped, $page_no = 1) {
|
||||||
global $pdo, $config;
|
global $pdo, $config;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['search']))
|
if (!hasPermission($config['mod']['search']))
|
||||||
|
@ -368,7 +368,7 @@ function mod_search($type, $search_query_escaped, $page_no = 1) {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_edit_board($boardName) {
|
function mod_edit_board(Context $ctx, $boardName) {
|
||||||
global $board, $config;
|
global $board, $config;
|
||||||
|
|
||||||
if (!openBoard($boardName))
|
if (!openBoard($boardName))
|
||||||
|
@ -470,7 +470,7 @@ function mod_edit_board($boardName) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_new_board() {
|
function mod_new_board(Context $ctx) {
|
||||||
global $config, $board;
|
global $config, $board;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['newboard']))
|
if (!hasPermission($config['mod']['newboard']))
|
||||||
|
@ -536,7 +536,7 @@ function mod_new_board() {
|
||||||
mod_page(_('New board'), 'mod/board.html', array('new' => true, 'token' => make_secure_link_token('new-board')));
|
mod_page(_('New board'), 'mod/board.html', array('new' => true, 'token' => make_secure_link_token('new-board')));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_noticeboard($page_no = 1) {
|
function mod_noticeboard(Context $ctx, $page_no = 1) {
|
||||||
global $config, $pdo, $mod;
|
global $config, $pdo, $mod;
|
||||||
|
|
||||||
if ($page_no < 1)
|
if ($page_no < 1)
|
||||||
|
@ -591,7 +591,7 @@ function mod_noticeboard($page_no = 1) {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_noticeboard_delete($id) {
|
function mod_noticeboard_delete(Context $ctx, $id) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['noticeboard_delete']))
|
if (!hasPermission($config['mod']['noticeboard_delete']))
|
||||||
|
@ -609,7 +609,7 @@ function mod_noticeboard_delete($id) {
|
||||||
header('Location: ?/noticeboard', true, $config['redirect_http']);
|
header('Location: ?/noticeboard', true, $config['redirect_http']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_news($page_no = 1) {
|
function mod_news(Context $ctx, $page_no = 1) {
|
||||||
global $config, $pdo, $mod;
|
global $config, $pdo, $mod;
|
||||||
|
|
||||||
if ($page_no < 1)
|
if ($page_no < 1)
|
||||||
|
@ -656,7 +656,7 @@ function mod_news($page_no = 1) {
|
||||||
mod_page(_('News'), 'mod/news.html', array('news' => $news, 'count' => $count, 'token' => make_secure_link_token('edit_news')));
|
mod_page(_('News'), 'mod/news.html', array('news' => $news, 'count' => $count, 'token' => make_secure_link_token('edit_news')));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_news_delete($id) {
|
function mod_news_delete(Context $ctx, $id) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['news_delete']))
|
if (!hasPermission($config['mod']['news_delete']))
|
||||||
|
@ -671,7 +671,7 @@ function mod_news_delete($id) {
|
||||||
header('Location: ?/edit_news', true, $config['redirect_http']);
|
header('Location: ?/edit_news', true, $config['redirect_http']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_log($page_no = 1) {
|
function mod_log(Context $ctx, $page_no = 1) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if ($page_no < 1)
|
if ($page_no < 1)
|
||||||
|
@ -696,7 +696,7 @@ function mod_log($page_no = 1) {
|
||||||
mod_page(_('Moderation log'), 'mod/log.html', array('logs' => $logs, 'count' => $count));
|
mod_page(_('Moderation log'), 'mod/log.html', array('logs' => $logs, 'count' => $count));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_user_log($username, $page_no = 1) {
|
function mod_user_log(Context $ctx, $username, $page_no = 1) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if ($page_no < 1)
|
if ($page_no < 1)
|
||||||
|
@ -733,7 +733,7 @@ function protect_ip($entry) {
|
||||||
return preg_replace(array($ipv4_link_regex, $ipv6_link_regex), "xxxx", $entry);
|
return preg_replace(array($ipv4_link_regex, $ipv6_link_regex), "xxxx", $entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_board_log($board, $page_no = 1, $hide_names = false, $public = false) {
|
function mod_board_log(Context $ctx, $board, $page_no = 1, $hide_names = false, $public = false) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if ($page_no < 1)
|
if ($page_no < 1)
|
||||||
|
@ -766,8 +766,8 @@ function mod_board_log($board, $page_no = 1, $hide_names = false, $public = fals
|
||||||
mod_page(_('Board log'), 'mod/log.html', array('logs' => $logs, 'count' => $count, 'board' => $board, 'hide_names' => $hide_names, 'public' => $public));
|
mod_page(_('Board log'), 'mod/log.html', array('logs' => $logs, 'count' => $count, 'board' => $board, 'hide_names' => $hide_names, 'public' => $public));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_view_catalog($boardName) {
|
function mod_view_catalog(Context $ctx, $boardName) {
|
||||||
global $config, $mod;
|
global $config;
|
||||||
require_once($config['dir']['themes'].'/catalog/theme.php');
|
require_once($config['dir']['themes'].'/catalog/theme.php');
|
||||||
$settings = [];
|
$settings = [];
|
||||||
$settings['boards'] = $boardName;
|
$settings['boards'] = $boardName;
|
||||||
|
@ -798,7 +798,7 @@ function mod_view_catalog($boardName) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_view_board($boardName, $page_no = 1) {
|
function mod_view_board(Context $ctx, $boardName, $page_no = 1) {
|
||||||
global $config, $mod;
|
global $config, $mod;
|
||||||
|
|
||||||
if (!openBoard($boardName)){
|
if (!openBoard($boardName)){
|
||||||
|
@ -829,7 +829,7 @@ function mod_view_board($boardName, $page_no = 1) {
|
||||||
echo Element('index.html', $page);
|
echo Element('index.html', $page);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_view_thread($boardName, $thread) {
|
function mod_view_thread(Context $ctx, $boardName, $thread) {
|
||||||
global $config, $mod;
|
global $config, $mod;
|
||||||
|
|
||||||
if (!openBoard($boardName))
|
if (!openBoard($boardName))
|
||||||
|
@ -839,7 +839,7 @@ function mod_view_thread($boardName, $thread) {
|
||||||
echo $page;
|
echo $page;
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_view_thread50($boardName, $thread) {
|
function mod_view_thread50(Context $ctx, $boardName, $thread) {
|
||||||
global $config, $mod;
|
global $config, $mod;
|
||||||
|
|
||||||
if (!openBoard($boardName))
|
if (!openBoard($boardName))
|
||||||
|
@ -849,8 +849,8 @@ function mod_view_thread50($boardName, $thread) {
|
||||||
echo $page;
|
echo $page;
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_ip_remove_note($ip, $id) {
|
function mod_ip_remove_note(Context $ctx, $ip, $id) {
|
||||||
global $config, $mod;
|
global $config;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['remove_notes']))
|
if (!hasPermission($config['mod']['remove_notes']))
|
||||||
error($config['error']['noaccess']);
|
error($config['error']['noaccess']);
|
||||||
|
@ -868,7 +868,7 @@ function mod_ip_remove_note($ip, $id) {
|
||||||
header('Location: ?/IP/' . $ip . '#notes', true, $config['redirect_http']);
|
header('Location: ?/IP/' . $ip . '#notes', true, $config['redirect_http']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_page_ip($ip, string $encoded_cursor = '') {
|
function mod_ip(Context $ctx, $ip, string $encoded_cursor = '') {
|
||||||
global $config, $mod;
|
global $config, $mod;
|
||||||
|
|
||||||
if (filter_var($ip, FILTER_VALIDATE_IP) === false)
|
if (filter_var($ip, FILTER_VALIDATE_IP) === false)
|
||||||
|
@ -1057,7 +1057,7 @@ function mod_page_ip($ip, string $encoded_cursor = '') {
|
||||||
mod_page(sprintf('%s: %s', _('IP'), htmlspecialchars($ip)), 'mod/view_ip.html', $args, $args['hostname']);
|
mod_page(sprintf('%s: %s', _('IP'), htmlspecialchars($ip)), 'mod/view_ip.html', $args, $args['hostname']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_ban() {
|
function mod_ban(Context $ctx) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['ban']))
|
if (!hasPermission($config['mod']['ban']))
|
||||||
|
@ -1078,7 +1078,7 @@ function mod_ban() {
|
||||||
header('Location: ?/', true, $config['redirect_http']);
|
header('Location: ?/', true, $config['redirect_http']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_warning() {
|
function mod_warning(Context $ctx) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['warning']))
|
if (!hasPermission($config['mod']['warning']))
|
||||||
|
@ -1095,7 +1095,7 @@ function mod_warning() {
|
||||||
header('Location: ?/', true, $config['redirect_http']);
|
header('Location: ?/', true, $config['redirect_http']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_bans() {
|
function mod_bans(Context $ctx) {
|
||||||
global $config;
|
global $config;
|
||||||
global $mod;
|
global $mod;
|
||||||
|
|
||||||
|
@ -1130,7 +1130,7 @@ function mod_bans() {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_bans_json() {
|
function mod_bans_json(Context $ctx) {
|
||||||
global $config, $mod;
|
global $config, $mod;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['ban']))
|
if (!hasPermission($config['mod']['ban']))
|
||||||
|
@ -1142,7 +1142,7 @@ function mod_bans_json() {
|
||||||
Bans::stream_json(false, false, !hasPermission($config['mod']['view_banstaff']), $mod['boards']);
|
Bans::stream_json(false, false, !hasPermission($config['mod']['view_banstaff']), $mod['boards']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_ban_appeals() {
|
function mod_ban_appeals(Context $ctx) {
|
||||||
global $config, $board;
|
global $config, $board;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['view_ban_appeals']))
|
if (!hasPermission($config['mod']['view_ban_appeals']))
|
||||||
|
@ -1224,7 +1224,7 @@ function mod_ban_appeals() {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_lock($board, $unlock, $post) {
|
function mod_lock(Context $ctx, $board, $unlock, $post) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if (!openBoard($board))
|
if (!openBoard($board))
|
||||||
|
@ -1260,7 +1260,7 @@ function mod_lock($board, $unlock, $post) {
|
||||||
event('lock', $post);
|
event('lock', $post);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_sticky($board, $unsticky, $post) {
|
function mod_sticky(Context $ctx, $board, $unsticky, $post) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if (!openBoard($board))
|
if (!openBoard($board))
|
||||||
|
@ -1284,7 +1284,7 @@ function mod_sticky($board, $unsticky, $post) {
|
||||||
header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']);
|
header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_cycle($board, $uncycle, $post) {
|
function mod_cycle(Context $ctx, $board, $uncycle, $post) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if (!openBoard($board))
|
if (!openBoard($board))
|
||||||
|
@ -1306,7 +1306,7 @@ function mod_cycle($board, $uncycle, $post) {
|
||||||
header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']);
|
header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_bumplock($board, $unbumplock, $post) {
|
function mod_bumplock(Context $ctx, $board, $unbumplock, $post) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if (!openBoard($board))
|
if (!openBoard($board))
|
||||||
|
@ -1328,8 +1328,8 @@ function mod_bumplock($board, $unbumplock, $post) {
|
||||||
header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']);
|
header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_move_reply($originBoard, $postID) {
|
function mod_move_reply(Context $ctx, $originBoard, $postID) {
|
||||||
global $board, $config, $mod;
|
global $board, $config;
|
||||||
|
|
||||||
if (!openBoard($originBoard))
|
if (!openBoard($originBoard))
|
||||||
error($config['error']['noboard']);
|
error($config['error']['noboard']);
|
||||||
|
@ -1432,8 +1432,8 @@ function mod_move_reply($originBoard, $postID) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_move($originBoard, $postID) {
|
function mod_move(Context $ctx, $originBoard, $postID) {
|
||||||
global $board, $config, $mod, $pdo;
|
global $board, $config, $pdo;
|
||||||
|
|
||||||
if (!openBoard($originBoard))
|
if (!openBoard($originBoard))
|
||||||
error($config['error']['noboard']);
|
error($config['error']['noboard']);
|
||||||
|
@ -1645,8 +1645,8 @@ function mod_move($originBoard, $postID) {
|
||||||
mod_page(_('Move thread'), 'mod/move.html', array('post' => $postID, 'board' => $originBoard, 'boards' => $boards, 'token' => $security_token));
|
mod_page(_('Move thread'), 'mod/move.html', array('post' => $postID, 'board' => $originBoard, 'boards' => $boards, 'token' => $security_token));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_merge($originBoard, $postID) {
|
function mod_merge(Context $ctx, $originBoard, $postID) {
|
||||||
global $board, $config, $mod, $pdo;
|
global $board, $config, $pdo;
|
||||||
|
|
||||||
if (!openBoard($originBoard))
|
if (!openBoard($originBoard))
|
||||||
error($config['error']['noboard']);
|
error($config['error']['noboard']);
|
||||||
|
@ -1655,10 +1655,11 @@ function mod_merge($originBoard, $postID) {
|
||||||
error($config['error']['noaccess']);
|
error($config['error']['noaccess']);
|
||||||
|
|
||||||
$query = prepare(sprintf('SELECT * FROM ``posts_%s`` WHERE `id` = :id AND `thread` IS NULL', $originBoard));
|
$query = prepare(sprintf('SELECT * FROM ``posts_%s`` WHERE `id` = :id AND `thread` IS NULL', $originBoard));
|
||||||
$query->bindValue(':id', $postID);
|
$query->bindValue(':id', (int)$postID, \PDO::PARAM_INT);
|
||||||
$query->execute() or error(db_error($query));
|
$query->execute() or error(db_error($query));
|
||||||
if (!$post = $query->fetch(PDO::FETCH_ASSOC))
|
if (!$post = $query->fetch(PDO::FETCH_ASSOC)) {
|
||||||
error($config['error']['404']);
|
error($config['error']['404']);
|
||||||
|
}
|
||||||
$sourceOp = "";
|
$sourceOp = "";
|
||||||
if ($post['thread']){
|
if ($post['thread']){
|
||||||
$sourceOp = $post['thread'];
|
$sourceOp = $post['thread'];
|
||||||
|
@ -1886,7 +1887,7 @@ function mod_merge($originBoard, $postID) {
|
||||||
mod_page(_('Merge thread'), 'mod/merge.html', array('post' => $postID, 'board' => $originBoard, 'boards' => $boards, 'token' => $security_token));
|
mod_page(_('Merge thread'), 'mod/merge.html', array('post' => $postID, 'board' => $originBoard, 'boards' => $boards, 'token' => $security_token));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_ban_post($board, $delete, $post, $token = false) {
|
function mod_ban_post(Context $ctx, $board, $delete, $post, $token = false) {
|
||||||
global $config, $mod;
|
global $config, $mod;
|
||||||
|
|
||||||
if (!openBoard($board))
|
if (!openBoard($board))
|
||||||
|
@ -2009,7 +2010,7 @@ function mod_ban_post($board, $delete, $post, $token = false) {
|
||||||
mod_page(_('New ban'), 'mod/ban_form.html', $args);
|
mod_page(_('New ban'), 'mod/ban_form.html', $args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_warning_post($board,$post, $token = false) {
|
function mod_warning_post(Context $ctx, $board, $post, $token = false) {
|
||||||
global $config, $mod;
|
global $config, $mod;
|
||||||
|
|
||||||
if (!openBoard($board))
|
if (!openBoard($board))
|
||||||
|
@ -2109,8 +2110,8 @@ function mod_warning_post($board,$post, $token = false) {
|
||||||
mod_page(_('New warning'), 'mod/warning_form.html', $args);
|
mod_page(_('New warning'), 'mod/warning_form.html', $args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_edit_post($board, $edit_raw_html, $postID) {
|
function mod_edit_post(Context $ctx, $board, $edit_raw_html, $postID) {
|
||||||
global $config, $mod;
|
global $config;
|
||||||
|
|
||||||
if (!openBoard($board))
|
if (!openBoard($board))
|
||||||
error($config['error']['noboard']);
|
error($config['error']['noboard']);
|
||||||
|
@ -2186,8 +2187,8 @@ function mod_edit_post($board, $edit_raw_html, $postID) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_delete($board, $post) {
|
function mod_delete(Context $ctx, $board, $post) {
|
||||||
global $config, $mod;
|
global $config;
|
||||||
|
|
||||||
if (!openBoard($board))
|
if (!openBoard($board))
|
||||||
error($config['error']['noboard']);
|
error($config['error']['noboard']);
|
||||||
|
@ -2252,8 +2253,8 @@ function mod_delete($board, $post) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_deletefile($board, $post, $file) {
|
function mod_deletefile(Context $ctx, $board, $post, $file) {
|
||||||
global $config, $mod;
|
global $config;
|
||||||
|
|
||||||
if (!openBoard($board))
|
if (!openBoard($board))
|
||||||
error($config['error']['noboard']);
|
error($config['error']['noboard']);
|
||||||
|
@ -2275,8 +2276,8 @@ function mod_deletefile($board, $post, $file) {
|
||||||
header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']);
|
header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_spoiler_image($board, $post, $file) {
|
function mod_spoiler_image(Context $ctx, $board, $post, $file) {
|
||||||
global $config, $mod;
|
global $config;
|
||||||
|
|
||||||
if (!openBoard($board))
|
if (!openBoard($board))
|
||||||
error($config['error']['noboard']);
|
error($config['error']['noboard']);
|
||||||
|
@ -2320,8 +2321,8 @@ function mod_spoiler_image($board, $post, $file) {
|
||||||
header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']);
|
header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_deletebyip($boardName, $post, $global = false) {
|
function mod_deletebyip(Context $ctx, $boardName, $post, $global = false) {
|
||||||
global $config, $mod, $board;
|
global $config, $board;
|
||||||
|
|
||||||
$global = (bool)$global;
|
$global = (bool)$global;
|
||||||
|
|
||||||
|
@ -2442,7 +2443,7 @@ function mod_deletebyip($boardName, $post, $global = false) {
|
||||||
header('Location: ?/' . sprintf($config['board_path'], $boardName) . $config['file_index'], true, $config['redirect_http']);
|
header('Location: ?/' . sprintf($config['board_path'], $boardName) . $config['file_index'], true, $config['redirect_http']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_user($uid) {
|
function mod_user(Context $ctx, $uid) {
|
||||||
global $config, $mod;
|
global $config, $mod;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['editusers']) && !(hasPermission($config['mod']['change_password']) && $uid == $mod['id']))
|
if (!hasPermission($config['mod']['editusers']) && !(hasPermission($config['mod']['change_password']) && $uid == $mod['id']))
|
||||||
|
@ -2567,7 +2568,7 @@ function mod_user($uid) {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_user_new() {
|
function mod_user_new(Context $ctx) {
|
||||||
global $pdo, $config;
|
global $pdo, $config;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['createusers']))
|
if (!hasPermission($config['mod']['createusers']))
|
||||||
|
@ -2620,7 +2621,7 @@ function mod_user_new() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function mod_users() {
|
function mod_users(Context $ctx) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['manageusers']))
|
if (!hasPermission($config['mod']['manageusers']))
|
||||||
|
@ -2641,7 +2642,7 @@ function mod_users() {
|
||||||
mod_page(sprintf('%s (%d)', _('Manage users'), count($users)), 'mod/users.html', array('users' => $users));
|
mod_page(sprintf('%s (%d)', _('Manage users'), count($users)), 'mod/users.html', array('users' => $users));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_user_promote($uid, $action) {
|
function mod_user_promote(Context $ctx, $uid, $action) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['promoteusers']))
|
if (!hasPermission($config['mod']['promoteusers']))
|
||||||
|
@ -2684,7 +2685,7 @@ function mod_user_promote($uid, $action) {
|
||||||
header('Location: ?/users', true, $config['redirect_http']);
|
header('Location: ?/users', true, $config['redirect_http']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_pm($id, $reply = false) {
|
function mod_pm(Context $ctx, $id, $reply = false) {
|
||||||
global $mod, $config;
|
global $mod, $config;
|
||||||
|
|
||||||
if ($reply && !hasPermission($config['mod']['create_pm']))
|
if ($reply && !hasPermission($config['mod']['create_pm']))
|
||||||
|
@ -2739,7 +2740,7 @@ function mod_pm($id, $reply = false) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_inbox() {
|
function mod_inbox(Context $ctx) {
|
||||||
global $config, $mod;
|
global $config, $mod;
|
||||||
|
|
||||||
$query = prepare('SELECT `unread`,``pms``.`id`, `time`, `sender`, `to`, `message`, `username` FROM ``pms`` LEFT JOIN ``mods`` ON ``mods``.`id` = `sender` WHERE `to` = :mod ORDER BY `unread` DESC, `time` DESC');
|
$query = prepare('SELECT `unread`,``pms``.`id`, `time`, `sender`, `to`, `message`, `username` FROM ``pms`` LEFT JOIN ``mods`` ON ``mods``.`id` = `sender` WHERE `to` = :mod ORDER BY `unread` DESC, `time` DESC');
|
||||||
|
@ -2763,7 +2764,7 @@ function mod_inbox() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function mod_new_pm($username) {
|
function mod_new_pm(Context $ctx, $username) {
|
||||||
global $config, $mod;
|
global $config, $mod;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['create_pm']))
|
if (!hasPermission($config['mod']['create_pm']))
|
||||||
|
@ -2811,7 +2812,7 @@ function mod_new_pm($username) {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_rebuild() {
|
function mod_rebuild(Context $ctx) {
|
||||||
global $config, $twig;
|
global $config, $twig;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['rebuild']))
|
if (!hasPermission($config['mod']['rebuild']))
|
||||||
|
@ -2883,7 +2884,7 @@ function mod_rebuild() {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_reports() {
|
function mod_reports(Context $ctx) {
|
||||||
global $config, $mod;
|
global $config, $mod;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['reports']))
|
if (!hasPermission($config['mod']['reports']))
|
||||||
|
@ -2987,7 +2988,7 @@ function mod_reports() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_report_dismiss($id, $all = false) {
|
function mod_report_dismiss(Context $ctx, $id, $all = false) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
$query = prepare("SELECT `post`, `board`, `ip` FROM ``reports`` WHERE `id` = :id");
|
$query = prepare("SELECT `post`, `board`, `ip` FROM ``reports`` WHERE `id` = :id");
|
||||||
|
@ -3024,7 +3025,7 @@ function mod_report_dismiss($id, $all = false) {
|
||||||
header('Location: ?/reports', true, $config['redirect_http']);
|
header('Location: ?/reports', true, $config['redirect_http']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_recent_posts($lim,$board_list = false,$json=false) {
|
function mod_recent_posts(Context $ctx, $lim, $board_list = false, $json = false) {
|
||||||
global $config, $mod, $pdo;
|
global $config, $mod, $pdo;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['recent']))
|
if (!hasPermission($config['mod']['recent']))
|
||||||
|
@ -3122,7 +3123,7 @@ function mod_recent_posts($lim,$board_list = false,$json=false) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_config($board_config = false) {
|
function mod_config(Context $ctx, $board_config = false) {
|
||||||
global $config, $mod, $board;
|
global $config, $mod, $board;
|
||||||
|
|
||||||
if ($board_config && !openBoard($board_config))
|
if ($board_config && !openBoard($board_config))
|
||||||
|
@ -3262,7 +3263,7 @@ function mod_config($board_config = false) {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_themes_list() {
|
function mod_themes_list(Context $ctx) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['themes']))
|
if (!hasPermission($config['mod']['themes']))
|
||||||
|
@ -3296,7 +3297,7 @@ function mod_themes_list() {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_theme_configure($theme_name) {
|
function mod_theme_configure(Context $ctx, $theme_name) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['themes']))
|
if (!hasPermission($config['mod']['themes']))
|
||||||
|
@ -3378,7 +3379,7 @@ function mod_theme_configure($theme_name) {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_theme_uninstall($theme_name) {
|
function mod_theme_uninstall(Context $ctx, $theme_name) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['themes']))
|
if (!hasPermission($config['mod']['themes']))
|
||||||
|
@ -3395,7 +3396,7 @@ function mod_theme_uninstall($theme_name) {
|
||||||
header('Location: ?/themes', true, $config['redirect_http']);
|
header('Location: ?/themes', true, $config['redirect_http']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_theme_rebuild($theme_name) {
|
function mod_theme_rebuild(Context $ctx, $theme_name) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['themes']))
|
if (!hasPermission($config['mod']['themes']))
|
||||||
|
@ -3436,15 +3437,15 @@ function delete_page_base($page = '', $board = false) {
|
||||||
header('Location: ?/edit_pages' . ($board ? ('/' . $board) : ''), true, $config['redirect_http']);
|
header('Location: ?/edit_pages' . ($board ? ('/' . $board) : ''), true, $config['redirect_http']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_delete_page($page = '') {
|
function mod_delete_page(Context $ctx, $page = '') {
|
||||||
delete_page_base($page);
|
delete_page_base($ctx, $page);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_delete_page_board($page = '', $board = false) {
|
function mod_delete_page_board(Context $ctx, $page = '', $board = false) {
|
||||||
delete_page_base($page, $board);
|
delete_page_base($ctx, $page, $board);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_edit_page($id) {
|
function mod_edit_page(Context $ctx, $id) {
|
||||||
global $config, $mod, $board;
|
global $config, $mod, $board;
|
||||||
|
|
||||||
$query = prepare('SELECT * FROM ``pages`` WHERE `id` = :id');
|
$query = prepare('SELECT * FROM ``pages`` WHERE `id` = :id');
|
||||||
|
@ -3515,7 +3516,7 @@ function mod_edit_page($id) {
|
||||||
mod_page(sprintf(_('Editing static page: %s'), $page['name']), 'mod/edit_page.html', array('page' => $page, 'token' => make_secure_link_token("edit_page/$id"), 'content' => prettify_textarea($content), 'board' => $board));
|
mod_page(sprintf(_('Editing static page: %s'), $page['name']), 'mod/edit_page.html', array('page' => $page, 'token' => make_secure_link_token("edit_page/$id"), 'content' => prettify_textarea($content), 'board' => $board));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_pages($board = false) {
|
function mod_pages(Context $ctx, $board = false) {
|
||||||
global $config, $mod, $pdo;
|
global $config, $mod, $pdo;
|
||||||
|
|
||||||
if (empty($board))
|
if (empty($board))
|
||||||
|
@ -3569,7 +3570,7 @@ function mod_pages($board = false) {
|
||||||
mod_page(_('Pages'), 'mod/pages.html', array('pages' => $pages, 'token' => make_secure_link_token('edit_pages' . ($board ? ('/' . $board) : '')), 'board' => $board));
|
mod_page(_('Pages'), 'mod/pages.html', array('pages' => $pages, 'token' => make_secure_link_token('edit_pages' . ($board ? ('/' . $board) : '')), 'board' => $board));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_debug_antispam() {
|
function mod_debug_antispam(Context $ctx) {
|
||||||
global $pdo, $config;
|
global $pdo, $config;
|
||||||
|
|
||||||
$args = [];
|
$args = [];
|
||||||
|
@ -3606,7 +3607,7 @@ function mod_debug_antispam() {
|
||||||
mod_page(_('Debug: Anti-spam'), 'mod/debug/antispam.html', $args);
|
mod_page(_('Debug: Anti-spam'), 'mod/debug/antispam.html', $args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_debug_recent_posts() {
|
function mod_debug_recent_posts(Context $ctx) {
|
||||||
global $pdo, $config;
|
global $pdo, $config;
|
||||||
|
|
||||||
$limit = 500;
|
$limit = 500;
|
||||||
|
@ -3640,7 +3641,7 @@ function mod_debug_recent_posts() {
|
||||||
mod_page(_('Debug: Recent posts'), 'mod/debug/recent_posts.html', array('posts' => $posts, 'flood_posts' => $flood_posts));
|
mod_page(_('Debug: Recent posts'), 'mod/debug/recent_posts.html', array('posts' => $posts, 'flood_posts' => $flood_posts));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_debug_sql() {
|
function mod_debug_sql(Context $ctx) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['debug_sql']))
|
if (!hasPermission($config['mod']['debug_sql']))
|
||||||
|
@ -3663,25 +3664,3 @@ function mod_debug_sql() {
|
||||||
|
|
||||||
mod_page(_('Debug: SQL'), 'mod/debug/sql.html', $args);
|
mod_page(_('Debug: SQL'), 'mod/debug/sql.html', $args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mod_debug_apc() {
|
|
||||||
global $config;
|
|
||||||
|
|
||||||
if (!hasPermission($config['mod']['debug_apc']))
|
|
||||||
error($config['error']['noaccess']);
|
|
||||||
|
|
||||||
if ($config['cache']['enabled'] != 'apc')
|
|
||||||
error('APC is not enabled.');
|
|
||||||
|
|
||||||
$cache_info = apc_cache_info('user');
|
|
||||||
|
|
||||||
// $cached_vars = new APCIterator('user', '/^' . $config['cache']['prefix'] . '/');
|
|
||||||
$cached_vars = [];
|
|
||||||
foreach ($cache_info['cache_list'] as $var) {
|
|
||||||
if ($config['cache']['prefix'] != '' && strpos(isset($var['key']) ? $var['key'] : $var['info'], $config['cache']['prefix']) !== 0)
|
|
||||||
continue;
|
|
||||||
$cached_vars[] = $var;
|
|
||||||
}
|
|
||||||
|
|
||||||
mod_page(_('Debug: APC'), 'mod/debug/apc.html', array('cached_vars' => $cached_vars));
|
|
||||||
}
|
|
||||||
|
|
187
inc/polyfill.php
187
inc/polyfill.php
|
@ -1,187 +1,10 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
// PHP 5.4
|
// PHP 8.0
|
||||||
|
|
||||||
if (!function_exists('hex2bin')) {
|
if (!function_exists('str_starts_with')) {
|
||||||
function hex2bin($data) {
|
function str_starts_with(string $haystack, string $needle): bool {
|
||||||
return pack("H*" , $hex_string);
|
// https://wiki.php.net/rfc/add_str_starts_with_and_ends_with_functions#str_starts_with
|
||||||
}
|
return \strncmp($haystack, $needle, \strlen($needle)) === 0;
|
||||||
}
|
|
||||||
|
|
||||||
// PHP 5.6
|
|
||||||
|
|
||||||
if (!function_exists('hash_equals')) {
|
|
||||||
function hash_equals($ours, $theirs) {
|
|
||||||
$ours = (string)$ours;
|
|
||||||
$theirs = (string)$theirs;
|
|
||||||
|
|
||||||
$tlen = strlen($theirs);
|
|
||||||
$olen = strlen($ours);
|
|
||||||
|
|
||||||
$answer = 0;
|
|
||||||
for ($i = 0; $i < $tlen; $i++) {
|
|
||||||
$answer |= ord($ours[$olen > $i ? $i : 0]) ^ ord($theirs[$i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $answer === 0 && $olen === $tlen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!function_exists('imagecreatefrombmp')) {
|
|
||||||
/*********************************************/
|
|
||||||
/* Fonction: imagecreatefrombmp */
|
|
||||||
/* Author: DHKold */
|
|
||||||
/* Contact: admin@dhkold.com */
|
|
||||||
/* Date: The 15th of June 2005 */
|
|
||||||
/* Version: 2.0B */
|
|
||||||
/*********************************************/
|
|
||||||
function imagecreatefrombmp($filename) {
|
|
||||||
if (! $f1 = fopen($filename,"rb")) return FALSE;
|
|
||||||
$FILE = unpack("vfile_type/Vfile_size/Vreserved/Vbitmap_offset", fread($f1,14));
|
|
||||||
if ($FILE['file_type'] != 19778) return FALSE;
|
|
||||||
$BMP = unpack('Vheader_size/Vwidth/Vheight/vplanes/vbits_per_pixel'.
|
|
||||||
'/Vcompression/Vsize_bitmap/Vhoriz_resolution'.
|
|
||||||
'/Vvert_resolution/Vcolors_used/Vcolors_important', fread($f1,40));
|
|
||||||
$BMP['colors'] = pow(2,$BMP['bits_per_pixel']);
|
|
||||||
if ($BMP['size_bitmap'] == 0) $BMP['size_bitmap'] = $FILE['file_size'] - $FILE['bitmap_offset'];
|
|
||||||
$BMP['bytes_per_pixel'] = $BMP['bits_per_pixel']/8;
|
|
||||||
$BMP['bytes_per_pixel2'] = ceil($BMP['bytes_per_pixel']);
|
|
||||||
$BMP['decal'] = ($BMP['width']*$BMP['bytes_per_pixel']/4);
|
|
||||||
$BMP['decal'] -= floor($BMP['width']*$BMP['bytes_per_pixel']/4);
|
|
||||||
$BMP['decal'] = 4-(4*$BMP['decal']);
|
|
||||||
if ($BMP['decal'] == 4) $BMP['decal'] = 0;
|
|
||||||
$PALETTE = array();
|
|
||||||
if ($BMP['colors'] < 16777216)
|
|
||||||
{
|
|
||||||
$PALETTE = unpack('V'.$BMP['colors'], fread($f1,$BMP['colors']*4));
|
|
||||||
}
|
|
||||||
$IMG = fread($f1,$BMP['size_bitmap']);
|
|
||||||
$VIDE = chr(0);
|
|
||||||
$res = imagecreatetruecolor($BMP['width'],$BMP['height']);
|
|
||||||
$P = 0;
|
|
||||||
$Y = $BMP['height']-1;
|
|
||||||
while ($Y >= 0)
|
|
||||||
{
|
|
||||||
$X=0;
|
|
||||||
while ($X < $BMP['width'])
|
|
||||||
{
|
|
||||||
if ($BMP['bits_per_pixel'] == 24)
|
|
||||||
$COLOR = unpack("V",substr($IMG,$P,3).$VIDE);
|
|
||||||
elseif ($BMP['bits_per_pixel'] == 16)
|
|
||||||
{
|
|
||||||
$COLOR = unpack("n",substr($IMG,$P,2));
|
|
||||||
$COLOR[1] = $PALETTE[$COLOR[1]+1];
|
|
||||||
}
|
|
||||||
elseif ($BMP['bits_per_pixel'] == 8)
|
|
||||||
{
|
|
||||||
$COLOR = unpack("n",$VIDE.substr($IMG,$P,1));
|
|
||||||
$COLOR[1] = $PALETTE[$COLOR[1]+1];
|
|
||||||
}
|
|
||||||
elseif ($BMP['bits_per_pixel'] == 4)
|
|
||||||
{
|
|
||||||
$COLOR = unpack("n",$VIDE.substr($IMG,floor($P),1));
|
|
||||||
if (($P*2)%2 == 0) $COLOR[1] = ($COLOR[1] >> 4) ; else $COLOR[1] = ($COLOR[1] & 0x0F);
|
|
||||||
$COLOR[1] = $PALETTE[$COLOR[1]+1];
|
|
||||||
}
|
|
||||||
elseif ($BMP['bits_per_pixel'] == 1)
|
|
||||||
{
|
|
||||||
$COLOR = unpack("n",$VIDE.substr($IMG,floor($P),1));
|
|
||||||
if (($P*8)%8 == 0) $COLOR[1] = $COLOR[1] >>7;
|
|
||||||
elseif (($P*8)%8 == 1) $COLOR[1] = ($COLOR[1] & 0x40)>>6;
|
|
||||||
elseif (($P*8)%8 == 2) $COLOR[1] = ($COLOR[1] & 0x20)>>5;
|
|
||||||
elseif (($P*8)%8 == 3) $COLOR[1] = ($COLOR[1] & 0x10)>>4;
|
|
||||||
elseif (($P*8)%8 == 4) $COLOR[1] = ($COLOR[1] & 0x8)>>3;
|
|
||||||
elseif (($P*8)%8 == 5) $COLOR[1] = ($COLOR[1] & 0x4)>>2;
|
|
||||||
elseif (($P*8)%8 == 6) $COLOR[1] = ($COLOR[1] & 0x2)>>1;
|
|
||||||
elseif (($P*8)%8 == 7) $COLOR[1] = ($COLOR[1] & 0x1);
|
|
||||||
$COLOR[1] = $PALETTE[$COLOR[1]+1];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return FALSE;
|
|
||||||
imagesetpixel($res,$X,$Y,$COLOR[1]);
|
|
||||||
$X++;
|
|
||||||
$P += $BMP['bytes_per_pixel'];
|
|
||||||
}
|
|
||||||
$Y--;
|
|
||||||
$P+=$BMP['decal'];
|
|
||||||
}
|
|
||||||
fclose($f1);
|
|
||||||
return $res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!function_exists('imagebmp')) {
|
|
||||||
function imagebmp(&$img, $filename='') {
|
|
||||||
$widthOrig = imagesx($img);
|
|
||||||
$widthFloor = ((floor($widthOrig/16))*16);
|
|
||||||
$widthCeil = ((ceil($widthOrig/16))*16);
|
|
||||||
$height = imagesy($img);
|
|
||||||
$size = ($widthCeil*$height*3)+54;
|
|
||||||
// Bitmap File Header
|
|
||||||
$result = 'BM'; // header (2b)
|
|
||||||
$result .= int_to_dword($size); // size of file (4b)
|
|
||||||
$result .= int_to_dword(0); // reserved (4b)
|
|
||||||
$result .= int_to_dword(54); // byte location in the file which is first byte of IMAGE (4b)
|
|
||||||
// Bitmap Info Header
|
|
||||||
$result .= int_to_dword(40); // Size of BITMAPINFOHEADER (4b)
|
|
||||||
$result .= int_to_dword($widthCeil); // width of bitmap (4b)
|
|
||||||
$result .= int_to_dword($height); // height of bitmap (4b)
|
|
||||||
$result .= int_to_word(1); // biPlanes = 1 (2b)
|
|
||||||
$result .= int_to_word(24); // biBitCount = {1 (mono) or 4 (16 clr ) or 8 (256 clr) or 24 (16 Mil)} (2b
|
|
||||||
$result .= int_to_dword(0); // RLE COMPRESSION (4b)
|
|
||||||
$result .= int_to_dword(0); // width x height (4b)
|
|
||||||
$result .= int_to_dword(0); // biXPelsPerMeter (4b)
|
|
||||||
$result .= int_to_dword(0); // biYPelsPerMeter (4b)
|
|
||||||
$result .= int_to_dword(0); // Number of palettes used (4b)
|
|
||||||
$result .= int_to_dword(0); // Number of important colour (4b)
|
|
||||||
// is faster than chr()
|
|
||||||
$arrChr = array();
|
|
||||||
for ($i=0; $i<256; $i++){
|
|
||||||
$arrChr[$i] = chr($i);
|
|
||||||
}
|
|
||||||
// creates image data
|
|
||||||
$bgfillcolor = array('red'=>0, 'green'=>0, 'blue'=>0);
|
|
||||||
// bottom to top - left to right - attention blue green red !!!
|
|
||||||
$y=$height-1;
|
|
||||||
for ($y2=0; $y2<$height; $y2++) {
|
|
||||||
for ($x=0; $x<$widthFloor; ) {
|
|
||||||
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
|
|
||||||
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
|
|
||||||
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
|
|
||||||
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
|
|
||||||
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
|
|
||||||
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
|
|
||||||
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
|
|
||||||
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
|
|
||||||
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
|
|
||||||
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
|
|
||||||
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
|
|
||||||
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
|
|
||||||
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
|
|
||||||
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
|
|
||||||
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
|
|
||||||
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
|
|
||||||
}
|
|
||||||
for ($x=$widthFloor; $x<$widthCeil; $x++) {
|
|
||||||
$rgb = ($x<$widthOrig) ? imagecolorsforindex($img, imagecolorat($img, $x, $y)) : $bgfillcolor;
|
|
||||||
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
|
|
||||||
}
|
|
||||||
$y--;
|
|
||||||
}
|
|
||||||
// see imagegif
|
|
||||||
if ($filename == '') {
|
|
||||||
echo $result;
|
|
||||||
} else {
|
|
||||||
$file = fopen($filename, 'wb');
|
|
||||||
fwrite($file, $result);
|
|
||||||
fclose($file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// imagebmp helpers
|
|
||||||
function int_to_dword($n) {
|
|
||||||
return chr($n & 255).chr(($n >> 8) & 255).chr(($n >> 16) & 255).chr(($n >> 24) & 255);
|
|
||||||
}
|
|
||||||
function int_to_word($n) {
|
|
||||||
return chr($n & 255).chr(($n >> 8) & 255);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
37
mod.php
37
mod.php
|
@ -1,18 +1,21 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2010-2014 Tinyboard Development Group
|
* Copyright (c) 2010-2014 Tinyboard Development Group
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once 'inc/bootstrap.php';
|
require_once 'inc/bootstrap.php';
|
||||||
|
|
||||||
if ($config['debug'])
|
if ($config['debug']) {
|
||||||
$parse_start_time = microtime(true);
|
$parse_start_time = microtime(true);
|
||||||
|
}
|
||||||
|
|
||||||
require_once 'inc/bans.php';
|
require_once 'inc/bans.php';
|
||||||
require_once 'inc/mod/pages.php';
|
require_once 'inc/mod/pages.php';
|
||||||
|
|
||||||
check_login(true);
|
|
||||||
|
$ctx = Vichan\build_context($config);
|
||||||
|
|
||||||
|
check_login($ctx, true);
|
||||||
|
|
||||||
$query = isset($_SERVER['QUERY_STRING']) ? rawurldecode($_SERVER['QUERY_STRING']) : '';
|
$query = isset($_SERVER['QUERY_STRING']) ? rawurldecode($_SERVER['QUERY_STRING']) : '';
|
||||||
|
|
||||||
|
@ -22,7 +25,7 @@ if(isset($_GET['thread'])) {
|
||||||
$query = explode("&thread=", $query)[0];
|
$query = explode("&thread=", $query)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
$pages = array(
|
$pages = [
|
||||||
'' => ':?/', // redirect to dashboard
|
'' => ':?/', // redirect to dashboard
|
||||||
'/' => 'dashboard', // dashboard
|
'/' => 'dashboard', // dashboard
|
||||||
'/confirm/(.+)' => 'confirm', // confirm action (if javascript didn't work)
|
'/confirm/(.+)' => 'confirm', // confirm action (if javascript didn't work)
|
||||||
|
@ -107,7 +110,6 @@ $pages = array(
|
||||||
// these pages aren't listed in the dashboard without $config['debug']
|
// these pages aren't listed in the dashboard without $config['debug']
|
||||||
'/debug/antispam' => 'debug_antispam',
|
'/debug/antispam' => 'debug_antispam',
|
||||||
'/debug/recent' => 'debug_recent_posts',
|
'/debug/recent' => 'debug_recent_posts',
|
||||||
'/debug/apc' => 'debug_apc',
|
|
||||||
'/debug/sql' => 'secure_POST debug_sql',
|
'/debug/sql' => 'secure_POST debug_sql',
|
||||||
|
|
||||||
// This should always be at the end:
|
// This should always be at the end:
|
||||||
|
@ -121,14 +123,14 @@ $pages = array(
|
||||||
str_replace('%d', '(\d+)', preg_quote($config['file_page'], '!')) => 'view_thread',
|
str_replace('%d', '(\d+)', preg_quote($config['file_page'], '!')) => 'view_thread',
|
||||||
|
|
||||||
'/(\%b)/' . preg_quote($config['dir']['res'], '!') .
|
'/(\%b)/' . preg_quote($config['dir']['res'], '!') .
|
||||||
str_replace(array('%d','%s'), array('(\d+)', '[a-z0-9-]+'), preg_quote($config['file_page50_slug'], '!')) => 'view_thread50',
|
str_replace([ '%d','%s' ], [ '(\d+)', '[a-z0-9-]+' ], preg_quote($config['file_page50_slug'], '!')) => 'view_thread50',
|
||||||
'/(\%b)/' . preg_quote($config['dir']['res'], '!') .
|
'/(\%b)/' . preg_quote($config['dir']['res'], '!') .
|
||||||
str_replace(array('%d','%s'), array('(\d+)', '[a-z0-9-]+'), preg_quote($config['file_page_slug'], '!')) => 'view_thread',
|
str_replace([ '%d','%s' ], [ '(\d+)', '[a-z0-9-]+' ], preg_quote($config['file_page_slug'], '!')) => 'view_thread',
|
||||||
);
|
];
|
||||||
|
|
||||||
|
|
||||||
if (!$mod) {
|
if (!$mod) {
|
||||||
$pages = array('!^(.+)?$!' => 'login');
|
$pages = [ '!^(.+)?$!' => 'login' ];
|
||||||
} elseif (isset($_GET['status'], $_GET['r'])) {
|
} elseif (isset($_GET['status'], $_GET['r'])) {
|
||||||
header('Location: ' . $_GET['r'], true, (int)$_GET['status']);
|
header('Location: ' . $_GET['r'], true, (int)$_GET['status']);
|
||||||
exit;
|
exit;
|
||||||
|
@ -138,12 +140,11 @@ if (isset($config['mod']['custom_pages'])) {
|
||||||
$pages = array_merge($pages, $config['mod']['custom_pages']);
|
$pages = array_merge($pages, $config['mod']['custom_pages']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$new_pages = array();
|
$new_pages = [];
|
||||||
foreach ($pages as $key => $callback) {
|
foreach ($pages as $key => $callback) {
|
||||||
if (is_string($callback) && preg_match('/^secure /', $callback)) {
|
if (is_string($callback) && preg_match('/^secure /', $callback)) {
|
||||||
$key .= '(/(?P<token>[a-f0-9]{8}))?';
|
$key .= '(/(?P<token>[a-f0-9]{8}))?';
|
||||||
}
|
}
|
||||||
|
|
||||||
$key = str_replace('\%b', '?P<board>' . sprintf(substr($config['board_path'], 0, -1), $config['board_regex']), $key);
|
$key = str_replace('\%b', '?P<board>' . sprintf(substr($config['board_path'], 0, -1), $config['board_regex']), $key);
|
||||||
$new_pages[@$key[0] == '!' ? $key : '!^' . $key . '(?:&[^&=]+=[^&]*)*$!u'] = $callback;
|
$new_pages[@$key[0] == '!' ? $key : '!^' . $key . '(?:&[^&=]+=[^&]*)*$!u'] = $callback;
|
||||||
}
|
}
|
||||||
|
@ -151,7 +152,7 @@ $pages = $new_pages;
|
||||||
|
|
||||||
foreach ($pages as $uri => $handler) {
|
foreach ($pages as $uri => $handler) {
|
||||||
if (preg_match($uri, $query, $matches)) {
|
if (preg_match($uri, $query, $matches)) {
|
||||||
$matches = array_slice($matches, 1);
|
$matches[0] = $ctx; // Replace the text captured by the full pattern with a reference to the context.
|
||||||
|
|
||||||
if (isset($matches['board'])) {
|
if (isset($matches['board'])) {
|
||||||
$board_match = $matches['board'];
|
$board_match = $matches['board'];
|
||||||
|
@ -171,7 +172,7 @@ foreach ($pages as $uri => $handler) {
|
||||||
if ($secure_post_only)
|
if ($secure_post_only)
|
||||||
error($config['error']['csrf']);
|
error($config['error']['csrf']);
|
||||||
else {
|
else {
|
||||||
mod_confirm(substr($query, 1));
|
mod_confirm($ctx, substr($query, 1));
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,24 +187,20 @@ foreach ($pages as $uri => $handler) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($config['debug']) {
|
if ($config['debug']) {
|
||||||
$debug['mod_page'] = array(
|
$debug['mod_page'] = [
|
||||||
'req' => $query,
|
'req' => $query,
|
||||||
'match' => $uri,
|
'match' => $uri,
|
||||||
'handler' => $handler,
|
'handler' => $handler,
|
||||||
);
|
];
|
||||||
$debug['time']['parse_mod_req'] = '~' . round((microtime(true) - $parse_start_time) * 1000, 2) . 'ms';
|
$debug['time']['parse_mod_req'] = '~' . round((microtime(true) - $parse_start_time) * 1000, 2) . 'ms';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_array($matches)) {
|
// We don't want to call named parameters (PHP 8).
|
||||||
// we don't want to call named parameters (PHP 8)
|
|
||||||
$matches = array_values($matches);
|
$matches = array_values($matches);
|
||||||
}
|
|
||||||
|
|
||||||
if (is_string($handler)) {
|
if (is_string($handler)) {
|
||||||
if ($handler[0] == ':') {
|
if ($handler[0] == ':') {
|
||||||
header('Location: ' . substr($handler, 1), true, $config['redirect_http']);
|
header('Location: ' . substr($handler, 1), true, $config['redirect_http']);
|
||||||
} elseif (is_callable("mod_page_$handler")) {
|
|
||||||
call_user_func_array("mod_page_$handler", $matches);
|
|
||||||
} elseif (is_callable("mod_$handler")) {
|
} elseif (is_callable("mod_$handler")) {
|
||||||
call_user_func_array("mod_$handler", $matches);
|
call_user_func_array("mod_$handler", $matches);
|
||||||
} else {
|
} else {
|
||||||
|
|
24
post.php
24
post.php
|
@ -3,6 +3,8 @@
|
||||||
* Copyright (c) 2010-2014 Tinyboard Development Group
|
* Copyright (c) 2010-2014 Tinyboard Development Group
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use Vichan\Context;
|
||||||
|
|
||||||
require_once 'inc/bootstrap.php';
|
require_once 'inc/bootstrap.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -529,7 +531,7 @@ function handle_nntpchan()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle_delete()
|
function handle_delete(Context $ctx)
|
||||||
{
|
{
|
||||||
// Delete
|
// Delete
|
||||||
global $config, $board, $mod;
|
global $config, $board, $mod;
|
||||||
|
@ -537,7 +539,7 @@ function handle_delete()
|
||||||
error($config['error']['bot']);
|
error($config['error']['bot']);
|
||||||
}
|
}
|
||||||
|
|
||||||
check_login(false);
|
check_login($ctx, false);
|
||||||
$is_mod = !!$mod;
|
$is_mod = !!$mod;
|
||||||
|
|
||||||
if (isset($_POST['mod']) && $_POST['mod'] && !$mod) {
|
if (isset($_POST['mod']) && $_POST['mod'] && !$mod) {
|
||||||
|
@ -653,7 +655,7 @@ function handle_delete()
|
||||||
rebuildThemes('post-delete', $board['uri']);
|
rebuildThemes('post-delete', $board['uri']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle_report()
|
function handle_report(Context $ctx)
|
||||||
{
|
{
|
||||||
global $config, $board;
|
global $config, $board;
|
||||||
if (!isset($_POST['board'], $_POST['reason']))
|
if (!isset($_POST['board'], $_POST['reason']))
|
||||||
|
@ -802,7 +804,7 @@ function handle_report()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle_post()
|
function handle_post(Context $ctx)
|
||||||
{
|
{
|
||||||
global $config, $dropped_post, $board, $mod, $pdo;
|
global $config, $dropped_post, $board, $mod, $pdo;
|
||||||
|
|
||||||
|
@ -911,7 +913,7 @@ function handle_post()
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($post['mod'] = isset($_POST['mod']) && $_POST['mod']) {
|
if ($post['mod'] = isset($_POST['mod']) && $_POST['mod']) {
|
||||||
check_login(false);
|
check_login($ctx, false);
|
||||||
if (!$mod) {
|
if (!$mod) {
|
||||||
// Liar. You're not a mod >:-[
|
// Liar. You're not a mod >:-[
|
||||||
error($config['error']['notamod']);
|
error($config['error']['notamod']);
|
||||||
|
@ -1846,7 +1848,7 @@ function handle_post()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle_appeal()
|
function handle_appeal(Context $ctx)
|
||||||
{
|
{
|
||||||
global $config;
|
global $config;
|
||||||
if (!isset($_POST['ban_id'])) {
|
if (!isset($_POST['ban_id'])) {
|
||||||
|
@ -1899,14 +1901,16 @@ if (isset($_GET['Newsgroups'])) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$ctx = Vichan\build_context($config);
|
||||||
|
|
||||||
if (isset($_POST['delete'])) {
|
if (isset($_POST['delete'])) {
|
||||||
handle_delete();
|
handle_delete($ctx);
|
||||||
} elseif (isset($_POST['report'])) {
|
} elseif (isset($_POST['report'])) {
|
||||||
handle_report();
|
handle_report($ctx);
|
||||||
} elseif (isset($_POST['post']) || $dropped_post) {
|
} elseif (isset($_POST['post']) || $dropped_post) {
|
||||||
handle_post();
|
handle_post($ctx);
|
||||||
} elseif (isset($_POST['appeal'])) {
|
} elseif (isset($_POST['appeal'])) {
|
||||||
handle_appeal();
|
handle_appeal($ctx);
|
||||||
} else {
|
} else {
|
||||||
if (!file_exists($config['has_installed'])) {
|
if (!file_exists($config['has_installed'])) {
|
||||||
header('Location: install.php', true, $config['redirect_http']);
|
header('Location: install.php', true, $config['redirect_http']);
|
||||||
|
|
|
@ -87,5 +87,20 @@ echo "Deleted $deleted_count invalid reports in $delta seconds!\n";
|
||||||
$time_tot += $delta;
|
$time_tot += $delta;
|
||||||
$deleted_tot += $deleted_count;
|
$deleted_tot += $deleted_count;
|
||||||
|
|
||||||
|
if ($config['cache']['enabled'] === 'fs') {
|
||||||
|
$fs_cache = new Vichan\Data\Driver\FsCacheDriver(
|
||||||
|
$config['cache']['prefix'],
|
||||||
|
"tmp/cache/{$config['cache']['prefix']}",
|
||||||
|
'.lock',
|
||||||
|
false
|
||||||
|
);
|
||||||
|
$start = microtime(true);
|
||||||
|
$fs_cache->collect();
|
||||||
|
$delta = microtime(true) - $start;
|
||||||
|
echo "Deleted $deleted_count expired filesystem cache items in $delta seconds!\n";
|
||||||
|
$time_tot = $delta;
|
||||||
|
$deleted_tot = $deleted_count;
|
||||||
|
}
|
||||||
|
|
||||||
$time_tot = number_format((float)$time_tot, 4, '.', '');
|
$time_tot = number_format((float)$time_tot, 4, '.', '');
|
||||||
modLog("Deleted $deleted_tot expired entries in {$time_tot}s with maintenance tool");
|
modLog("Deleted $deleted_tot expired entries in {$time_tot}s with maintenance tool");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue