Compare commits

...

62 Commits

Author SHA1 Message Date
Lorenzo Yario
ec2784c948
Update README.md
EOL
2026-07-06 16:20:27 -07:00
Lorenzo Yario
b12fc13239
Yes I am alive, rest in peace copypaste. 2026-02-26 21:57:55 -06:00
Lorenzo Yario
03e86f5bb2
Merge pull request #986 from vichan-devel/5.2.2
5.2.2
2025-10-29 17:18:07 -05:00
Lorenzo Yario
c8f993f962
Update image.php 2025-10-29 17:15:53 -05:00
Lorenzo Yario
83ae07baf8
Update install.php 2025-10-29 16:52:45 -05:00
Lorenzo Yario
0b49efffa4
Add files via upload 2025-10-29 16:52:17 -05:00
Lorenzo Yario
2315a70186
Create .gitkeep 2025-10-29 16:51:53 -05:00
Lorenzo Yario
f71a001a02
Delete static/banners/defaultbanner.png 2025-10-29 16:50:46 -05:00
Lorenzo Yario
f202fe93ec
Update api.php 2025-10-29 16:48:49 -05:00
Lorenzo Yario
44b9798c10
Update config.php 2025-10-29 16:44:55 -05:00
Lorenzo Yario
592c23359e
message for info too long 2025-10-29 16:44:19 -05:00
Lorenzo Yario
34e39905f9
add simple sanity check for logins 2025-10-29 16:43:18 -05:00
Lorenzo Yario
5e472bafac
Merge pull request #975 from catamphetamine/boardsApi
JSON API: Boards List
2025-10-26 03:36:04 -05:00
Nikolay
632293f927
Call JSON API's translateBoards() in setupBoard() function 2025-09-30 17:54:58 +03:00
Nikolay
90a47bbb8b
api.php — translateBoards() 2025-09-30 17:53:17 +03:00
Lorenzo Yario
2c57e84ac5
Merge pull request #974 from Mystia-Izakaya/patch-1
Fixed config-editor.php bug
2025-09-12 12:37:23 -07:00
Mystia-Izakaya
d3e8eb7480
Fixed config-editor.php bug
Who the hell thought that eval+@ is a good alternative to try catch block?
2025-09-07 01:19:14 +03:00
Lorenzo Yario
49276440e0
Update README.md 2025-05-14 03:03:49 -05:00
Lorenzo Yario
de52f98741
Merge pull request #930 from deffcolony/master
Improved Docker setup, installation, and documentation
2025-05-01 19:23:40 -05:00
alexveebee
e4104d4b05 update to check_container() 2025-05-01 15:16:53 +00:00
alexveebee
3050876be0 remove space 2025-05-01 15:09:36 +00:00
alexveebee
0518178a47 fix typo 2025-05-01 15:08:46 +00:00
alexveebee
23652b9830 lts 2025-04-30 19:34:47 +00:00
alexveebee
fe115048ac make optional for mariadb 2025-04-30 19:33:53 +00:00
alexveebee
a5e6470f56 update compose 2025-04-30 19:19:48 +00:00
alexveebee
14b8ce42a8 undo db image from mariadb, using mysql:latest 2025-04-30 02:02:10 +00:00
Alex
291bb26e74
Merge pull request #6 from Zankaria/mariadb-lts
Mariadb LTS
2025-04-25 21:51:59 +00:00
Alex
3781a10776
Merge pull request #5 from Zankaria/local-vars
PR fixup
2025-04-25 21:51:42 +00:00
Zankaria
4f99c62850 docker: use mariadb LTS 2025-04-25 18:32:25 +02:00
Zankaria
f959e790fd template.php: expose check_container function in twig templates 2025-04-25 18:09:42 +02:00
Zankaria
2c023ee644 templates.php: use local vars for container checking 2025-04-25 18:09:39 +02:00
Zankaria
553c925f40 template.php: use PHP style comments 2025-04-25 18:04:33 +02:00
Zankaria
12b4356a6a cache.php: use local vars 2025-04-25 18:04:31 +02:00
alexveebee
4d2f369af6 add twig to template.php: check container? 2025-04-25 14:22:42 +00:00
alexveebee
c3c9352f0a sperate code from config.php 2025-04-25 14:22:15 +00:00
alexveebee
135904ece0 use tab indents 2025-04-24 17:14:21 +00:00
alexveebee
3b45f4a897 remove button onclick hrefs 2025-04-24 17:13:15 +00:00
alexveebee
58c275472f use tab indents 2025-04-24 17:10:56 +00:00
alexveebee
416ac88407 wrap button in <a> tag 2025-04-24 17:04:29 +00:00
alexveebee
cb06845cc7 update port conflict with podman cockpit 2025-04-23 22:03:30 +00:00
Alex
21d573809b
Merge pull request #4 from AlexVeeBee/master
Quick PR: change text to Running Containerized
2025-04-23 21:12:13 +00:00
alexveebee
ce2deeb9cf Running Containerized 2025-04-23 21:10:14 +00:00
deffcolony
7eab6b0b6c
Merge pull request #3 from AlexVeeBee/master
Quck PR: add running in docker label
2025-04-23 21:03:03 +02:00
Alex
a28db68dd2
Merge branch 'deffcolony:master' into master 2025-04-23 19:01:33 +00:00
alexveebee
8360bf0ca7 sohw "running in docker" in the footer 2025-04-23 16:01:19 +00:00
deffcolony
64edc11a23
Merge pull request #2 from AlexVeeBee/master
Update installer and cache config
2025-04-23 17:34:22 +02:00
alexveebee
ffb8759fb1 remove logger 2025-04-23 15:31:49 +00:00
alexveebee
d35b435e7e update env for compose 2025-04-23 15:13:16 +00:00
alexveebee
240bb247f9 update config and remove check for container in cache.php 2025-04-23 15:13:07 +00:00
alexveebee
0a0cf68d64 fix enable php extentions 2025-04-22 22:37:12 +00:00
alexveebee
37fec1b82f update is_docker 2025-04-22 20:23:10 +00:00
alexveebee
38d96b80a5 Add Redis cache configuration and temp logging functionality 2025-04-22 20:22:08 +00:00
Alex
ec2f55b88f
Merge branch 'deffcolony:master' into master 2025-04-22 18:04:51 +00:00
deffcolony
7013f26eb2 corrected compose.yml and add podman docs 2025-04-22 17:12:36 +02:00
alexveebee
1671ec36c7 use tab indendation
https://github.com/vichan-devel/vichan/pull/930#discussion_r2052987496
2025-04-22 02:17:29 +00:00
Alex
b30232f773
Merge branch 'deffcolony:master' into master 2025-04-22 02:07:50 +00:00
alexveebee
d3f49bfd04 undo line 687 in install.php 2025-04-22 02:02:03 +00:00
deffcolony
292ce42cd7 environment variable handling and better configuration options in Docker setup 2025-04-21 20:47:08 +02:00
deffcolony
3a50da7d28
Merge pull request #1 from AlexVeeBee/master
Add php.ini with info in the installed
2025-04-21 13:01:42 +02:00
alexveebee
7e674103a7 remove env 2025-04-20 21:51:49 +00:00
alexveebee
64419af5f9 add php.ini to /docker/php 2025-04-20 21:51:07 +00:00
deffcolony
d3f36e48f7 Enhance Docker setup and installation process
- Updated Docker Compose configuration for web, PHP, and database services.
- Added Redis service with health checks and environment variables.
- Improved error handling and user prompts in installation scripts.
- Introduced example environment variables for easier configuration.
- Updated Nginx and PHP Docker images to latest versions.
2025-04-20 22:46:12 +02:00
23 changed files with 605 additions and 101 deletions

60
.env.example Normal file
View File

@ -0,0 +1,60 @@
# Example environment variables for the vichan imageboard Docker Compose setup.
# Copy this file to `.env` and customize values as needed.
# Do not commit `.env` with sensitive data to version control.
# General Settings
INSTANCE=0
# Web Service (Nginx) Settings
# SSL_CERT_PATH=/path/to/cert.pem
# SSL_KEY_PATH=/path/to/key.pem
# PHP Service Settings
## Database settings
VICHAN_MYSQL_HOST=db
VICHAN_MYSQL_USER=vichan
VICHAN_MYSQL_NAME=vichan
VICHAN_MYSQL_PASSWORD=vichan!
## Security
VICHAN_SECURE_LOGIN_ONLY=0
## Cookies
VICHAN_COOKIES_MOD=mod
## Flood Control
VICHAN_FLOOD_TIME=30
VICHAN_FLOOD_TIME_IP=120
VICHAN_FLOOD_TIME_SAME=3600
VICHAN_MAX_BODY=1800
VICHAN_REPLY_LIMIT=250
VICHAN_MAX_LINKS=20
## Images
VICHAN_IMAGES_MAX_FILESIZE=10485760
VICHAN_IMAGES_THUMB_WIDTH=250
VICHAN_IMAGES_THUMB_HEIGHT=250
VICHAN_IMAGES_MAX_WIDTH=10000
VICHAN_IMAGES_MAX_HEIGHT=10000
## Display
VICHAN_DISPLAY_THREADS_PER_PAGE=10
VICHAN_DISPLAY_MAX_PAGES=11
VICHAN_DISPLAY_THREADS_PREVIEW=5
## Directories
VICHAN_DIRECTORIES_ROOT=/
# Database Service (MariaDB) Settings
MYSQL_DATABASE=vichan
MYSQL_USER=vichan
MYSQL_PASSWORD=vichan!
MYSQL_ROOT_PASSWORD=vichan!!
# Cache Settings
VICHAN_CACHE_ENGINE=redis
VICHAN_CACHE_HOST=redis
VICHAN_CACHE_PORT=6379
VICHAN_CACHE_PASSWORD=redis!

1
.gitignore vendored
View File

@ -29,6 +29,7 @@
thumbs.db
Icon?
Thumbs.db
.env
*.patch
*.diff
*.rej

View File

@ -1,8 +1,10 @@
Vichan has reached its end of life. many of us have lost interest in the project, and the current direction of the internet has not been good for imageboards, whether its ID verification laws, big social media companies killing competition, or Google being hostile towards smaller sites. There are other imageboard engines out there but even if you use them, these are still issues you will need to think about if you start an imageboard or UGC website. You can still install or fork vichan, but do so at your own risk.
**In Memory of Fredrick Brennan (1994-2026).**
vichan - A lightweight and full featured PHP imageboard.
========================================================
**Please do not contact Fredrick Brennan in regards to vichan issues.**
As of 29 August 2022 it supports PHP8.1.
About
@ -82,7 +84,9 @@ To migrate from a Kusaba X board, use http://github.com/vichan-devel/Tinyboard-M
Demo
--------
Demo with the most updated version of [Vichan](https://vichan.27chan.org).
Demo with the most updated version of [Vichan](https://demo.vichan.info).
This version of vichan has admin, janitor, and moderator access on it, with the usernames being admin, mod, and janny respectfully and the password being password. This test instance resets hourly.
1. PHP 8.1
2. MySQL 5.7

View File

@ -1,18 +1,22 @@
services:
#nginx webserver + php 8.x
web:
build:
context: .
dockerfile: ./docker/nginx/Dockerfile
ports:
- "9090:80"
depends_on:
- db
container_name: vichan_web
restart: unless-stopped
volumes:
- ./local-instances/${INSTANCE:-0}/www:/var/www/html
- ./docker/nginx/vichan.conf:/etc/nginx/conf.d/default.conf
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
- ./docker/nginx/proxy.conf:/etc/nginx/conf.d/proxy.conf
# - ./docker/nginx/ssl:/etc/nginx/ssl # optional For SSL
ports:
- "9080:80"
# - "9081:443" # optional for SSL
depends_on:
- db
- php
links:
- php
@ -20,21 +24,77 @@ services:
build:
context: .
dockerfile: ./docker/php/Dockerfile
container_name: vichan_php
restart: unless-stopped
volumes:
- ./local-instances/${INSTANCE:-0}/www:/var/www
- ./docker/php/www.conf:/usr/local/etc/php-fpm.d/www.conf
- ./docker/php/jit.ini:/usr/local/etc/php/conf.d/jit.ini
#MySQL Service
db:
image: mysql:8.0.35
container_name: db
restart: unless-stopped
tty: true
ports:
- "3306:3306"
- ./docker/php/php.ini:/usr/local/etc/php/php.ini
environment:
MYSQL_DATABASE: vichan
MYSQL_ROOT_PASSWORD: password
# Database settings
VICHAN_MYSQL_HOST: ${VICHAN_MYSQL_HOST}
VICHAN_MYSQL_USER: ${VICHAN_MYSQL_USER}
VICHAN_MYSQL_NAME: ${VICHAN_MYSQL_NAME}
VICHAN_MYSQL_PASSWORD: ${VICHAN_MYSQL_PASSWORD}
# Security
VICHAN_SECURE_LOGIN_ONLY: ${VICHAN_SECURE_LOGIN_ONLY}
# Cache settings
VICHAN_CACHE_ENGINE: ${VICHAN_CACHE_ENGINE}
VICHAN_CACHE_HOST: ${VICHAN_CACHE_HOST}
VICHAN_CACHE_PORT: ${VICHAN_CACHE_PORT}
VICHAN_CACHE_PASSWORD: ${VICHAN_CACHE_PASSWORD}
# Cookies
VICHAN_COOKIES_MOD: ${VICHAN_COOKIES_MOD}
# Flood Control
VICHAN_FLOOD_TIME: ${VICHAN_FLOOD_TIME}
VICHAN_FLOOD_TIME_IP: ${VICHAN_FLOOD_TIME_IP}
VICHAN_FLOOD_TIME_SAME: ${VICHAN_FLOOD_TIME_SAME}
VICHAN_MAX_BODY: ${VICHAN_MAX_BODY}
VICHAN_REPLY_LIMIT: ${VICHAN_REPLY_LIMIT}
VICHAN_MAX_LINKS: ${VICHAN_MAX_LINKS}
# Images
VICHAN_IMAGES_MAX_FILESIZE: ${VICHAN_IMAGES_MAX_FILESIZE}
VICHAN_IMAGES_THUMB_WIDTH: ${VICHAN_IMAGES_THUMB_WIDTH}
VICHAN_IMAGES_THUMB_HEIGHT: ${VICHAN_IMAGES_THUMB_HEIGHT}
VICHAN_IMAGES_MAX_WIDTH: ${VICHAN_IMAGES_MAX_WIDTH}
VICHAN_IMAGES_MAX_HEIGHT: ${VICHAN_IMAGES_MAX_HEIGHT}
# Display
VICHAN_DISPLAY_THREADS_PER_PAGE: ${VICHAN_DISPLAY_THREADS_PER_PAGE}
VICHAN_DISPLAY_MAX_PAGES: ${VICHAN_DISPLAY_MAX_PAGES}
VICHAN_DISPLAY_THREADS_PREVIEW: ${VICHAN_DISPLAY_THREADS_PREVIEW}
# Directories
VICHAN_DIRECTORIES_ROOT: ${VICHAN_DIRECTORIES_ROOT}
depends_on:
- db
db:
image: mysql:lts
# image: mariadb:lts # optional for more higher performance
container_name: vichan_db
restart: unless-stopped
volumes:
- ./local-instances/${INSTANCE:-0}/mysql:/var/lib/mysql
- ./local-instances/${INSTANCE:-0}/db:/var/lib/mysql
# ports:
# - "9082:3306" # optional for external access
environment:
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
redis:
image: redis:latest
container_name: vichan_redis
restart: unless-stopped
volumes:
- ./local-instances/${INSTANCE:-0}/redis:/data
environment:
REDIS_PASSWORD: ${VICHAN_CACHE_PASSWORD}
command: redis-server --requirepass ${VICHAN_CACHE_PASSWORD}
healthcheck:
test: ["CMD", "redis-cli", "-a", "${VICHAN_CACHE_PASSWORD}", "ping"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s

View File

@ -1,20 +1,160 @@
The `php-fpm` process runs containerized.
The php application always uses `/var/www` as it's work directory and home folder, and if `/var/www` is bind mounted it
is necessary to adjust the path passed via FastCGI to `php-fpm` by changing the root directory to `/var/www`.
This can achieved in nginx by setting the `fastcgi_param SCRIPT_FILENAME` to `/var/www/$fastcgi_script_name;`
# Vichan Docker Setup
The default docker compose settings are intended for development and testing purposes.
The folder structure expected by compose is as follows
The `php-fpm` process runs containerized.
The PHP application always uses `/var/www` as its work directory and home folder. If `/var/www` is bind mounted, you must adjust the path passed via FastCGI to `php-fpm`.
To fix this:
1. **Adjust the root path**: Set `fastcgi_param SCRIPT_FILENAME` to `/var/www/$fastcgi_script_name;` in your nginx config.
The default Docker Compose settings are meant for development and testing.
Expected folder structure:
```
<vichan-project>
└── local-instances
└── 1
├── mysql
├── db
└── www
```
The vichan container is by itself much less rigid.
To run the app:
1. **Start all containers**: Run `docker compose up -d --build` at the root of vichan directory
2. **Rebuild just the PHP container**: Run `docker compose up -d --build php` (useful during development)
---
## PHP File Size Limit
To upload larger files, increase the default PHP file size limit (2MB). Since this setup uses Docker, follow these steps:
1. **Open the config file**: Edit `./docker/php/php.ini` in your project directory.
2. **Add or update these lines** to increase the file size limit to 10MB:
```ini
upload_max_filesize = 10M
post_max_size = 10M
```
3. **Restart your containers** to apply the changes:
```bash
docker compose restart
```
---
By default, PHP limits file uploads to **2MB** — so increasing this is often required when uploading images or documents.
---
## Using the `.env` File
Environment variables for the Docker Compose setup can be managed easily using a `.env` file.
### Steps to Use It:
1. **Copy the example**: Start by copying `.env.example` to `.env`
```bash
cp .env.example .env
```
2. **Edit `.env`**: Please make sure to change the default passwords for your setup.
### What It Controls:
- Instance folder reference (e.g. `local-instances/0`)
- Database credentials
- Redis connection details
- Secure login
- Optional SSL certificate paths for nginx
Use `docker compose up --build` to start the docker compose.
Use `docker compose up --build -d php` to rebuild just the vichan container while the compose is running. Useful for development.
# Vichan Podman Setup (Docker alternative)
**Podman** offers a daemonless, rootless alternative for running Vichan in containers. Podman is API-compatible with Docker, allowing you to use the existing `compose.yml` file with minimal changes, while providing a more secure and lightweight environment.
This tutorial is for administrators who prefer to avoid Docker, addressing security concerns and ensuring a robust Vichan install.
---
## Why Podman?
- **Daemonless**: Unlike Docker, Podman doesnt require a central daemon, reducing the attack surface and eliminating the need for a privileged process.
- **Rootless**: Podman runs containers as a non-root user by default, improving security by limiting the impact of potential container escapes.
- **Lightweight**: Podman has a smaller footprint and is better suited for environments where simplicity and security are priorities.
- **Docker Compatibility**: Podman supports Docker Compose files via Podman Compose, making it easy to adapt the existing Vichan setup.
Learn more at: https://podman.io
---
## Prerequisites
**Install Podman**
The official installation tutorial can be found at: https://podman.io/docs/installation
**Configure the `.env` file** as described in the main setup guide (copy `.env.example` to `.env` and update passwords).
---
## Steps to Run Vichan with Podman
### 1. Prepare File Permissions
Since Podman runs rootless, ensure the `local-instances/1/db` and `local-instances/1/www` directories are writable by your user:
```bash
chmod -R u+rw local-instances/1
```
If using SELinux (e.g., on Fedora), you may need to set the correct context:
```bash
chcon -R -t container_file_t local-instances/1
```
### 2. Start Containers with Podman Compose
Run the following command from the root of the Vichan project directory to build and start all containers:
```bash
podman-compose up -d --build
```
This command mirrors `docker compose up -d --build` but uses Podmans container engine.
### 3. Rebuild Specific Containers
To rebuild only the PHP container (e.g., during development):
```bash
podman-compose up -d --build php
```
---
## Managing Podman Containers
**List running containers:**
```bash
podman ps
```
**Stop all containers:**
```bash
podman-compose down
```
**View logs for a specific service (e.g., PHP):**
```bash
podman logs vichan_php
```
## Troubleshooting
### unqualified-search-registries for Docker.io
1. Edit the config file with `nano /etc/containers/registries.conf`
2. Add the registry for `docker.io` with `unqualified-search-registries = ["docker.io"]`
3. Save and exit
4. Run `podman-compose up -d`

View File

@ -1,4 +1,4 @@
FROM nginx:1.25.3-alpine
FROM nginx:1.27.5-alpine-slim
COPY . /code
RUN adduser --system www-data \

View File

@ -1,7 +1,7 @@
# Based on https://github.com/dead-guru/devichan/blob/master/php-fpm/Dockerfile
FROM composer:lts AS composer
FROM php:8.1-fpm-alpine
FROM php:8.3-fpm-alpine
RUN apk add --no-cache \
zlib \
@ -47,7 +47,7 @@ RUN apk add --no-cache \
&& pecl install -o -f igbinary \
&& pecl install redis \
&& pecl install imagick \
$$ docker-php-ext-enable \
&& docker-php-ext-enable \
igbinary \
redis \
imagick \

3
docker/php/php.ini Normal file
View File

@ -0,0 +1,3 @@
post_max_size=10M
upload_max_filesize=10M
max_file_uploads=5

View File

@ -1,47 +1,65 @@
<?php
namespace Vichan\Data\Driver;
// Prevent direct access to this file for security
defined('TINYBOARD') or exit;
// Handles caching using Redis, a fast in-memory data store
class RedisCacheDriver implements CacheDriver {
private string $prefix;
private \Redis $inner;
public function __construct(string $prefix, string $host, int $port, ?string $password, string $database) {
// Sets up the Redis connection
public function __construct(string $prefix, string $host, int $port, ?string $password, int $database) {
$this->inner = new \Redis();
$this->inner->connect($host, $port);
if ($password) {
$this->inner->auth($password);
}
if (!$this->inner->select($database)) {
throw new \RuntimeException('Unable to connect to Redis!');
throw new \RuntimeException('Unable to select Redis database ' . $database);
}
$$this->prefix = $prefix;
$this->prefix = $prefix;
}
// Retrieves a value from the cache by key
public function get(string $key): mixed {
$ret = $this->inner->get($this->prefix . $key);
if ($ret === false) {
// Return null if the key doesn't exist
return null;
}
return \json_decode($ret, true);
}
// Stores a value in the cache with an optional expiration time
public function set(string $key, mixed $value, mixed $expires = false): void {
if ($expires === false) {
$this->inner->set($this->prefix . $key, \json_encode($value));
// Convert the value to JSON for storage
$encodedValue = \json_encode($value);
if ($expires === false || !is_numeric($expires) || $expires <= 0) {
// Store the value without an expiration
$this->inner->set($this->prefix . $key, $encodedValue);
} else {
$expires = $expires * 1000; // Seconds to milliseconds.
$this->inner->setex($this->prefix . $key, $expires, \json_encode($value));
// Store the value with an expiration time (in seconds)
$ttl_seconds = (int)$expires;
$this->inner->setex($this->prefix . $key, $ttl_seconds, $encodedValue);
}
}
// Deletes a specific key from the cache
public function delete(string $key): void {
// Remove the key from Redis
$this->inner->del($this->prefix . $key);
}
// Clears all data in the current Redis database
public function flush(): void {
$this->inner->flushDB();
}

View File

@ -208,4 +208,24 @@ class Api {
return $apiCatalog;
}
public function translateBoard($board) {
$apiBoard = [];
foreach ($boards as $board) {
$apiBoard['uri'] = $board['uri'];
$apiBoard['title'] = $board['title'];
$apiBoard['subtitle'] = $board['subtitle'];
}
return $apiBoard;
}
public function translateBoards($boards) {
$apiBoards = [];
foreach ($boards as $board) {
$apiBoards[] = $this->translateBoard($board);
}
return $apiBoards;
}
}

View File

@ -12,20 +12,32 @@ defined('TINYBOARD') or exit;
class Cache {
private static function buildCache(): CacheDriver {
global $config;
// Determine if the cache engine is configured via environment variables.
$engine = \getenv('VICHAN_CACHE_ENGINE') ?: $config['cache']['enabled'];
switch ($config['cache']['enabled']) {
switch ($engine) {
case 'memcached':
return new MemcachedCacheDriver(
$config['cache']['prefix'],
$config['cache']['memcached']
);
case 'redis':
$host = $config['cache']['redis']["host"] ?? 'localhost';
$port = $config['cache']['redis']["port"] ?? 6379;
$password = $config['cache']['redis']["password"] ?? '';
$database = $config['cache']['redis']["database"] ?? 1;
$host = getenv('VICHAN_CACHE_HOST') ?: $host;
$port = getenv('VICHAN_CACHE_PORT') ?: $port;
$password = getenv('VICHAN_CACHE_PASSWORD') ?: $password;
$database = getenv('VICHAN_CACHE_DATABASE') ?: $database;
return new RedisCacheDriver(
$config['cache']['prefix'],
$config['cache']['redis'][0],
$config['cache']['redis'][1],
$config['cache']['redis'][2],
$config['cache']['redis'][3]
$host,
$port,
$password,
$database
);
case 'apcu':
return new ApcuCacheDriver;

View File

@ -146,6 +146,7 @@
*/
// Uses a PHP array. MUST NOT be used in multiprocess environments.
// This will be ignored if a environment variable ( VICHAN_CACHE_ENGINE ) is set.
$config['cache']['enabled'] = 'php';
// The recommended in-memory method of caching. Requires the extension. Due to how APCu works, this should be
// disabled when you run tools from the cli.
@ -161,20 +162,23 @@
// $config['cache']['enabled'] = 'none';
// Timeout for cached objects such as posts and HTML.
$config['cache']['timeout'] = 60 * 60 * 48; // 48 hours
// Optional prefix if you're running multiple vichan instances on the same machine.
$config['cache']['prefix'] = '';
// Memcached servers to use. Read more: http://www.php.net/manual/en/memcached.addservers.php
$config['cache']['memcached'] = array(
array('localhost', 11211)
$config['cache']['redis'] = array(
'host' => 'localhost',
'port' => 6379,
'password' => '',
'database' => 1
);
// Redis server to use. Location, port, password, database id.
// Note that vichan may clear the database at times, so you may want to pick a database id just for
// vichan to use.
$config['cache']['redis'] = array('localhost', 6379, '', 1);
// Cache timeout for cached objects
$config['cache']['timeout'] = 60 * 60 * 48; // 48 hours
// Optional prefix for multiple vichan instances
$config['cache']['prefix'] = '';
// Memcached servers (not used)
$config['cache']['memcached'] = [
['localhost', 11211]
];
// 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
@ -1271,6 +1275,7 @@
// Moderator errors
'toomanyunban' => _('You are only allowed to unban %s users at a time. You tried to unban %u users.'),
'invalid' => _('Invalid username and/or password.'),
'infotoolong' => _('Username and/or password contains too many characters.'),
'insecure' => _('Login on insecure connections is disabled.'),
'notamod' => _('You are not a mod…'),
'invalidafter' => _('Invalid username and/or password. Your user may have been deleted or changed.'),

View File

@ -432,6 +432,18 @@ function setupBoard($array) {
if (!file_exists($board['dir'] . $config['dir']['res']))
@mkdir($board['dir'] . $config['dir']['res'], 0777)
or error("Couldn't create " . $board['dir'] . $config['dir']['img'] . ". Check permissions.", true);
// json api
if ($config['api']['enabled'] && !$mod) {
$api = new Api(
$config['show_filename'],
$config['hide_email'],
$config['country_flags']
);
$json = json_encode($api->translateBoards(listBoards()));
$jsonFilename = 'boards.json';
file_write($jsonFilename, $json);
}
}
function openBoard($uri) {

View File

@ -250,7 +250,7 @@ class ImageConvert extends ImageBase {
if ($size = @getimagesize($src))
return $size;
}
$size = shell_exec_error(($this->gm ? 'gm ' : '') . 'identify -format "%w %h" ' . escapeshellarg($src . '[0]'));
$size = shell_exec_error(($this->gm ? 'gm ' : 'magick ') . 'identify -format "%w %h" ' . escapeshellarg($src . '[0]'));
if (preg_match('/^(\d+) (\d+)$/', $size, $m))
return array($m[1], $m[2]);
return false;
@ -276,13 +276,13 @@ class ImageConvert extends ImageBase {
if (!$this->temp) {
if ($config['strip_exif']) {
if($error = shell_exec_error(($this->gm ? 'gm ' : '') . 'convert ' .
if($error = shell_exec_error(($this->gm ? 'gm convert ' : 'magick ') .
escapeshellarg($this->src) . ' -auto-orient -strip ' . escapeshellarg($src))) {
$this->destroy();
error(_('Failed to redraw image!'), null, $error);
}
} else {
if($error = shell_exec_error(($this->gm ? 'gm ' : '') . 'convert ' .
if($error = shell_exec_error(($this->gm ? 'gm convert ' : 'magick ') .
escapeshellarg($this->src) . ' -auto-orient ' . escapeshellarg($src))) {
$this->destroy();
error(_('Failed to redraw image!'), null, $error);
@ -329,7 +329,7 @@ class ImageConvert extends ImageBase {
} else {
$convert_args = &$config['convert_args'];
if (($error = shell_exec_error(($this->gm ? 'gm ' : '') . 'convert ' .
if (($error = shell_exec_error(($this->gm ? 'gm convert ' : 'magick ') .
sprintf($convert_args,
$this->width,
$this->height,
@ -348,7 +348,7 @@ class ImageConvert extends ImageBase {
} else {
$convert_args = &$config['convert_args'];
if (($error = shell_exec_error(($this->gm ? 'gm ' : '') . 'convert ' .
if (($error = shell_exec_error(($this->gm ? 'gm convert ' : 'magick ') .
sprintf($convert_args,
$this->width,
$this->height,

View File

@ -103,7 +103,13 @@ function config_vars() {
continue; // This is just an alias.
if (!preg_match('/^array|\[\]|function/', $var['default']) && !preg_match('/^Example: /', trim(implode(' ', $var['comment'])))) {
$syntax_error = true;
$temp = eval('$syntax_error = false;return @' . $var['default'] . ';');
try {
$temp = $var['default'];
$syntax_error = false;
}
catch (Exception $e) {
$temp = false;
}
if ($syntax_error && $temp === false) {
error('Error parsing config.php (line ' . $line_no . ')!', null, $var);
} elseif (!isset($temp)) {

View File

@ -57,6 +57,9 @@ function mod_login(Context $ctx, $redirect = false) {
// Check if inputs are set and not empty
if (!isset($_POST['username'], $_POST['password']) || $_POST['username'] == '' || $_POST['password'] == '') {
$args['error'] = $config['error']['invalid'];
}
elseif (strlen($_POST['password']) > 128 || strlen($_POST['username']) > 128) {
$args['error'] = $config['error']['infotoolong'];
} elseif (!login($_POST['username'], $_POST['password'])) {
if ($config['syslog'])
_syslog(LOG_WARNING, 'Unauthorized login attempt!');

View File

@ -142,7 +142,8 @@ class Tinyboard extends Twig\Extension\AbstractExtension
new Twig\TwigFunction('ratio', 'twig_ratio_function'),
new Twig\TwigFunction('secure_link_confirm', 'twig_secure_link_confirm'),
new Twig\TwigFunction('secure_link', 'twig_secure_link'),
new Twig\TwigFunction('link_for', 'link_for')
new Twig\TwigFunction('link_for', 'link_for'),
new Twig\TwigFunction('check_container', 'twig_check_container')
);
}
@ -225,3 +226,19 @@ function twig_secure_link_confirm($text, $title, $confirm_message, $href) {
function twig_secure_link($href) {
return $href . '/' . make_secure_link_token($href);
}
/*
* ====================
* Container Detection
* ===================
*/
function twig_check_container() {
static $is_container = null;
if ($is_container === null) {
$is_docker = \is_file("/.dockerenv") || \is_file("/run/.containerenv");
$is_kubernetes = \is_file("/var/run/secrets/kubernetes.io/serviceaccount/namespace");
$is_container = $is_docker || $is_kubernetes;
}
return $is_container;
}

View File

@ -1,7 +1,7 @@
<?php
// Installation/upgrade file
define('VERSION', '5.2.1');
define('VERSION', '5.2.2');
require 'inc/bootstrap.php';
loadConfig();
@ -387,7 +387,7 @@ if (file_exists($config['has_installed'])) {
CHANGE `theme` `theme` VARCHAR( 40 ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL ,
CHANGE `name` `name` VARCHAR( 40 ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL ,
CHANGE `value` `value` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL ,
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;") or eror(db_error());
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;") or error(db_error());
case 'v0.9.6-dev-10':
query("ALTER TABLE `antispam`
CHANGE `board` `board` VARCHAR( 58 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;") or error(db_error());
@ -590,12 +590,12 @@ if (file_exists($config['has_installed'])) {
case '4.9.90':
case '4.9.91':
case '4.9.92':
foreach ($boards as &$board) {
query(sprintf('ALTER TABLE ``posts_%s`` ADD `slug` VARCHAR(255) DEFAULT NULL AFTER `embed`;', $board['uri'])) or error(db_error());
foreach ($boards as &$board) {
query(sprintf('ALTER TABLE ``posts_%s`` ADD `slug` VARCHAR(255) DEFAULT NULL AFTER `embed`;', $board['uri'])) or error(db_error());
}
case '4.9.93':
query('ALTER TABLE ``mods`` CHANGE `password` `password` VARCHAR(255) NOT NULL;') or error(db_error());
query('ALTER TABLE ``mods`` CHANGE `salt` `salt` VARCHAR(64) NOT NULL;') or error(db_error());
case '4.9.93':
query('ALTER TABLE ``mods`` CHANGE `password` `password` VARCHAR(255) NOT NULL;') or error(db_error());
query('ALTER TABLE ``mods`` CHANGE `salt` `salt` VARCHAR(64) NOT NULL;') or error(db_error());
case '5.0.0':
query('ALTER TABLE ``mods`` CHANGE `salt` `version` VARCHAR(64) NOT NULL;') or error(db_error());
case '5.0.1':
@ -611,9 +611,9 @@ if (file_exists($config['has_installed'])) {
UNIQUE KEY `u_pages` (`name`,`board`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;') or error(db_error());
case '5.1.1':
foreach ($boards as &$board) {
query(sprintf("ALTER TABLE ``posts_%s`` ADD `cycle` int(1) NOT NULL AFTER `locked`", $board['uri'])) or error(db_error());
}
foreach ($boards as &$board) {
query(sprintf("ALTER TABLE ``posts_%s`` ADD `cycle` int(1) NOT NULL AFTER `locked`", $board['uri'])) or error(db_error());
}
case '5.1.2':
query('CREATE TABLE IF NOT EXISTS ``nntp_references`` (
`board` varchar(60) NOT NULL,
@ -680,7 +680,7 @@ function create_config_from_array(&$instance_config, &$array, $prefix = '') {
session_start();
if ($step == 0) {
// Agreeement
// Agreement
$page['body'] = '
<textarea style="width:700px;height:370px;margin:auto;display:block;background:white;color:black" disabled>' . htmlentities(file_get_contents('LICENSE.md')) . '</textarea>
<p style="text-align:center">
@ -914,20 +914,64 @@ if ($step == 0) {
'config' => $config,
));
} elseif ($step == 2) {
// Basic config
$page['title'] = 'Configuration';
$sg = new SaltGen();
$config['cookies']['salt'] = $sg->generate();
// Initialize configuration with defaults and override with environment variables
$config['cookies'] = array(
'mod' => getenv('VICHAN_COOKIES_MOD') !== false ? getenv('VICHAN_COOKIES_MOD') : 'mod',
'salt' => $sg->generate(),
);
$config['flood_time'] = getenv('VICHAN_FLOOD_TIME') !== false ? (int)getenv('VICHAN_FLOOD_TIME') : 30;
$config['flood_time_ip'] = getenv('VICHAN_FLOOD_TIME_IP') !== false ? (int)getenv('VICHAN_FLOOD_TIME_IP') : 120;
$config['flood_time_same'] = getenv('VICHAN_FLOOD_TIME_SAME') !== false ? (int)getenv('VICHAN_FLOOD_TIME_SAME') : 3600;
$config['max_body'] = getenv('VICHAN_MAX_BODY') !== false ? (int)getenv('VICHAN_MAX_BODY') : 1800;
$config['reply_limit'] = getenv('VICHAN_REPLY_LIMIT') !== false ? (int)getenv('VICHAN_REPLY_LIMIT') : 250;
$config['max_links'] = getenv('VICHAN_MAX_LINKS') !== false ? (int)getenv('VICHAN_MAX_LINKS') : 20;
$config['max_filesize'] = getenv('VICHAN_IMAGES_MAX_FILESIZE') !== false ? (int)getenv('VICHAN_IMAGES_MAX_FILESIZE') : 10485760; // This is 10MB
$config['thumb_width'] = getenv('VICHAN_IMAGES_THUMB_WIDTH') !== false ? (int)getenv('VICHAN_IMAGES_THUMB_WIDTH') : 250;
$config['thumb_height'] = getenv('VICHAN_IMAGES_THUMB_HEIGHT') !== false ? (int)getenv('VICHAN_IMAGES_THUMB_HEIGHT') : 250;
$config['max_width'] = getenv('VICHAN_IMAGES_MAX_WIDTH') !== false ? (int)getenv('VICHAN_IMAGES_MAX_WIDTH') : 10000;
$config['max_height'] = getenv('VICHAN_IMAGES_MAX_HEIGHT') !== false ? (int)getenv('VICHAN_IMAGES_MAX_HEIGHT') : 10000;
$config['threads_per_page'] = getenv('VICHAN_DISPLAY_THREADS_PER_PAGE') !== false ? (int)getenv('VICHAN_DISPLAY_THREADS_PER_PAGE') : 10;
$config['max_pages'] = getenv('VICHAN_DISPLAY_MAX_PAGES') !== false ? (int)getenv('VICHAN_DISPLAY_MAX_PAGES') : 11;
$config['threads_preview'] = getenv('VICHAN_DISPLAY_THREADS_PREVIEW') !== false ? (int)getenv('VICHAN_DISPLAY_THREADS_PREVIEW') : 5;
$config['root'] = getenv('VICHAN_DIRECTORIES_ROOT') !== false ? getenv('VICHAN_DIRECTORIES_ROOT') : '/';
$config['secure_trip_salt'] = $sg->generate();
$config['secure_password_salt'] = $sg->generate();
// Set database configuration from Docker environment variables, leave empty if not found
$config['db'] = array(
'type' => 'mysql', // Default, required for MySQL
'server' => getenv('VICHAN_MYSQL_HOST') !== false ? getenv('VICHAN_MYSQL_HOST') : '',
'database' => getenv('VICHAN_MYSQL_NAME') !== false ? getenv('VICHAN_MYSQL_NAME') : '',
'user' => getenv('VICHAN_MYSQL_USER') !== false ? getenv('VICHAN_MYSQL_USER') : '',
'password' => getenv('VICHAN_MYSQL_PASSWORD') !== false ? getenv('VICHAN_MYSQL_PASSWORD') : '',
);
// Append secure_login_only to $_SESSION['more'] if VICHAN_SECURE_LOGIN_ONLY is set
if (getenv('VICHAN_SECURE_LOGIN_ONLY') !== false) {
$secure_login_only = (int)getenv('VICHAN_SECURE_LOGIN_ONLY');
$_SESSION['more'] .= "\n\$config['cookies']['secure_login_only'] = $secure_login_only;";
}
// Configuration notice at the top
$page['body'] = '<div class="ban"><h2>Configuration Note</h2>' .
'<p style="text-align:center;">The following settings can still be configured later. For more customization options, <a href="https://github.com/vichan-devel/vichan/wiki/config" target="_blank" rel="noopener noreferrer">check the Vichan configuration wiki.</a></p></div>';
// Append the configuration form
$page['body'] .= Element('installer/config.html', array(
'config' => $config,
'more' => $_SESSION['more'],
));
echo Element('page.html', array(
'body' => Element('installer/config.html', array(
'config' => $config,
'more' => $_SESSION['more'],
)),
'body' => $page['body'],
'title' => 'Configuration',
'config' => $config
));
@ -973,8 +1017,6 @@ if ($step == 0) {
echo Element('page.html', $page);
}
} elseif ($step == 4) {
// SQL installation
buildJavascript();
$sql = @file_get_contents('install.sql') or error("Couldn't load install.sql.");
@ -994,7 +1036,7 @@ if ($step == 0) {
$sql_err_count = 0;
foreach ($queries as $query) {
if ($mysql_version < 50503)
$query = preg_replace('/(CHARSET=|CHARACTER SET )utf8mb4/', '$1utf8', $query);
$query = preg_replace('/(CHARSET=|CHARACTER SET )utf8mb4/', '$1utf8', $query);
$query = preg_replace('/^([\w\s]*)`([0-9a-zA-Z$_\x{0080}-\x{FFFF}]+)`/u', '$1``$2``', $query);
if (!query($query)) {
$sql_err_count++;
@ -1004,10 +1046,22 @@ if ($step == 0) {
}
$page['title'] = 'Installation complete';
$page['body'] = '<p style="text-align:center">Thank you for using vichan. Please remember to report any bugs you discover. <a href="https://github.com/vichan-devel/vichan/wiki/Configuration-Basics">How do I edit the config files?</a></p>';
$page['body'] = '<p style="text-align:center">Thank you for using vichan. <a href="https://github.com/vichan-devel/vichan/issues/new/choose" target="_blank" rel="noopener noreferrer">Please report any bugs you discover.</a></p>' .
'<p style="text-align:center">If you are new to vichan, <a href="https://github.com/vichan-devel/vichan/wiki" target="_blank" rel="noopener noreferrer">please check out the documentation.</a></p>';
// Admin panel notice
$page['body'] .= '<div class="ban"><h2>Next Steps</h2>' .
'<p>You can now log in to the admin panel at <strong>/mod.php</strong> using the default credentials:</p>' .
'<p><strong>Username:</strong> admin</p>' .
'<p><strong>Password:</strong> password</p>' .
'<p><strong>Important:</strong> For security, please change the administrator password immediately after logging in.</p>' .
'<p style="text-align:center"><a href="/mod.php"><button>Go to Admin Panel</button></a></p></div>';
if (!empty($sql_errors)) {
$page['body'] .= '<div class="ban"><h2>SQL errors</h2><p>SQL errors were encountered when trying to install the database. This may be the result of using a database which is already occupied with a vichan installation; if so, you can probably ignore this.</p><p>The errors encountered were:</p><ul>' . $sql_errors . '</ul><p><a href="?step=5">Ignore errors and complete installation.</a></p></div>';
$page['body'] .= '<div class="ban"><h2>SQL errors</h2><p>SQL errors were encountered when trying to install the database. This may be the result of using a database which is already occupied with a vichan installation; if so, you can probably ignore this.</p><p>The errors encountered were:</p><ul>' . $sql_errors . '</ul>' .
'<p style="text-align:center;color:#d00"><strong>Warning:</strong> Ignoring errors is not recommended and may cause installation issues.</p>' .
'<p style="text-align:center"><a href="?step=5"><button>Next</button></a></p></div>';
} else {
$boards = listBoards();
foreach ($boards as &$_board) {
@ -1024,7 +1078,16 @@ if ($step == 0) {
echo Element('page.html', $page);
} elseif ($step == 5) {
$page['title'] = 'Installation complete';
$page['body'] = '<p style="text-align:center">Thank you for using vichan. Please remember to report any bugs you discover.</p>';
$page['body'] = '<p style="text-align:center">Thank you for using vichan. Please report any bugs you discover.</p>' .
'<p style="text-align:center">If you are new to vichan, <a href="https://github.com/vichan-devel/vichan/wiki">please check out the documentation</a>.</p>';
// Admin panel notice
$page['body'] .= '<div class="ban"><h2>Next Steps</h2>' .
'<p>You can now log in to the admin panel at <strong>/mod.php</strong> using the default credentials:</p>' .
'<p><strong>Username:</strong> admin</p>' .
'<p><strong>Password:</strong> password</p>' .
'<p><strong>Important:</strong> For security, please change the administrator password immediately after logging in.</p>' .
'<p style="text-align:center"><a href="/mod.php"><button>Go to Admin Panel</button></a></p></div>';
$boards = listBoards();
foreach ($boards as &$_board) {

1
static/banners/.gitkeep Normal file
View File

@ -0,0 +1 @@

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -1,6 +1,8 @@
<footer>
<p class="unimportant" style="margin-top:20px;text-align:center;">- Tinyboard +
<a href="https://github.com/vichan-devel/vichan">vichan</a> {{ config.version }} -
<a href="https://github.com/vichan-devel/vichan">vichan</a> {{ config.version }}
{% if check_container() %}Running Containerized{% endif %}
-
<br>Tinyboard Copyright &copy; 2010-2014 Tinyboard Development Group
<br><a href="https://github.com/vichan-devel/vichan">vichan</a> Copyright &copy; 2012-2025 vichan-devel</p>
{% for footer in config.footer %}<p class="unimportant" style="text-align:center;">{{ footer }}</p>{% endfor %}

View File

@ -17,10 +17,10 @@
<i style="font-size:11pt;color:#090" class="fa fa-check"></i>
{% else %}
{% if test.required %}
{% set errors = errors + 1 %}
{% set errors = errors + 1 %}
<i style="font-size:11pt;color:#d00" class="fa fa-exclamation"></i>
{% else %}
{% set warnings = warnings + 1 %}
{% set warnings = warnings + 1 %}
<i style="font-size:11pt;color:#f80" class="fa fa-warning"></i>
{% endif %}
{% endif %}
@ -45,12 +45,13 @@
{% endfor %}
</ul>
{% if errors %}
<p style="text-align:center"><a href="?step=2">Click here to ignore errors and attempt installing anyway (not recommended).</a></p>
<p style="text-align:center;color:#d00"><strong>Warning:</strong> Ignoring these problems is not recommended and may cause installation issues.</p>
<p style="text-align:center"><a href="?step=2"><button>Proceed Anyway</button></a></p>
{% else %}
<p style="text-align:center"><a href="?step=2">Click here to proceed with installation.</a></p>
<p style="text-align:center"><a href="?step=2"><button>Next</button></a></p>
{% endif %}
{% else %}
<p>There were no errors or warnings. Good!</p>
<p style="text-align:center"><a href="?step=2">Clik here to proceed with installation.</a></p>
<p style="text-align:center"><a href="?step=2"><button>Next</button></a></p>
{% endif %}
</div>
</div>

View File

@ -14,10 +14,7 @@
<input type="text" id="db_user" name="db[user]" value="{{ config.db.user }}">
<label for="db_pass">Password:</label>
<input type="password" id="db_pass" name="db[password]" value="">
</fieldset>
<p style="text-align:center" class="unimportant">The following is all later configurable. For more options, <a href="http://tinyboard.org/docs/?p=Config">edit your configuration files</a> after installing.</p>
<fieldset>
<input type="password" id="db_pass" name="db[password]" value="{{ config.db.password }}">
<legend>Cookies</legend>
<label for="cookies_mod">Moderator cookie:</label>
<input type="text" id="cookies_mod" name="cookies[mod]" value="{{ config.cookies.mod }}">
@ -51,7 +48,38 @@
<legend>Images</legend>
<label for="max_filesize">Maximum image filesize (bytes):</label>
<input type="text" id="max_filesize" name="max_filesize" value="{{ config.max_filesize }}">
<div class="expandable">
<legend>PHP File Size Limit</legend>
<div class="body">
<p>Configure the PHP file size limit in the <code>php.ini</code> file. If it doesn't exist, create one.</p>
<div class="expandable">
<legend>Using Docker</legend>
<div class="body">
<p>Edit or create <code>./vichan/docker/php/php.ini</code> in the project root.</p>
<p>To set the limit to 10MB, add:</p>
<pre>
upload_max_filesize = 10M
post_max_size = 10M
</pre>
<p>Then restart the containers.</p>
</div>
</div>
<div class="expandable">
<legend>Manual Configuration</legend>
<div class="body">
<p>Edit or create <code>/usr/local/etc/php/php.ini</code>.</p>
<p>To set the limit to 10MB, add:</p>
<pre>
upload_max_filesize = 10M
post_max_size = 10M
</pre>
<p>Then restart the PHP server.</p>
</div>
</div>
<hr>
<p>Default limit is 2MB if not set.</p>
</div>
</div>
<label for="thumb_width">Thumbnail width:</label>
<input type="text" id="thumb_width" name="thumb_width" value="{{ config.thumb_width }}">
@ -99,3 +127,51 @@
<input type="submit" value="Complete installation">
</p>
</form>
<script>
const expandables = document.querySelectorAll('.expandable');
expandables.forEach(expandable => {
const arrow = document.createElement('span');
arrow.innerHTML = ' &#9654;'; // Right arrow
arrow.style.cursor = 'pointer';
arrow.style.marginLeft = '5px';
expandable.querySelector('legend').appendChild(arrow);
expandable.querySelector('legend').style.cursor = 'pointer';
expandable.querySelector('legend').style.fontWeight = 'bold';
expandable.querySelector('legend').style.display = 'flex';
expandable.querySelector('legend').style.alignItems = 'center';
expandable.querySelector('legend').style.justifyContent = 'space-between';
const label = expandable.querySelector('legend');
const body = expandable.querySelector('.body');
label.addEventListener('click', () => {
if (body.style.display === 'none' || body.style.display === '') {
body.style.display = 'block';
arrow.innerHTML = ' &#9660;'; // Down arrow
} else {
body.style.display = 'none';
arrow.innerHTML = ' &#9654;'; // Up arrow
}
});
});
</script>
<style>
.expandable {
border: 1px solid #ccc;
padding: 10px;
margin: 10px 0;
}
.expandable legend {
cursor: pointer;
font-weight: bold;
}
.expandable fieldset {
border: none;
padding: 0;
margin: 0;
}
.expandable .body {
display: none; /* Ensure the body is hidden initially */
}
</style>