Remove a bunch of trailing whitespace.
This commit is contained in:
parent
93bfe14d4f
commit
a3a6471ced
@ -39,7 +39,7 @@ RewriteCond %{REQUEST_URI} !^/css/custom/
|
|||||||
RewriteRule ^css/tkr\.css$ public/css/tkr.css [L]
|
RewriteRule ^css/tkr\.css$ public/css/tkr.css [L]
|
||||||
|
|
||||||
# 404 all other static files (images, js, fonts, etc.)
|
# 404 all other static files (images, js, fonts, etc.)
|
||||||
# so those requests don't hit the PHP app
|
# so those requests don't hit the PHP app
|
||||||
# (this is to reduce load on the PHP app from bots and scanners)
|
# (this is to reduce load on the PHP app from bots and scanners)
|
||||||
RewriteRule \.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$ - [R=404,L]
|
RewriteRule \.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$ - [R=404,L]
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ A lightweight, HTML-only status feed for self-hosted personal websites. Written
|
|||||||
* PHP 8.2+ with the PDO and PDO_SQLITE extensions
|
* PHP 8.2+ with the PDO and PDO_SQLITE extensions
|
||||||
* The PDO and PDO_SQLITE extensions are usually included by default
|
* The PDO and PDO_SQLITE extensions are usually included by default
|
||||||
* This might work with earlier PHP versions, but I've only tested 8.2
|
* This might work with earlier PHP versions, but I've only tested 8.2
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
1. Download the latest tkr archive from https://subcultureofone.org/files/tkr/tkr.0.6.0.zip
|
1. Download the latest tkr archive from https://subcultureofone.org/files/tkr/tkr.0.6.0.zip
|
||||||
|
@ -18,12 +18,12 @@ define('DB_FILE', DATA_DIR . '/tkr.sqlite');
|
|||||||
// Define an exception for validation errors
|
// Define an exception for validation errors
|
||||||
class SetupException extends Exception {
|
class SetupException extends Exception {
|
||||||
private $setupIssue;
|
private $setupIssue;
|
||||||
|
|
||||||
public function __construct(string $message, string $setupIssue = '', int $code = 0, Throwable $previous = null) {
|
public function __construct(string $message, string $setupIssue = '', int $code = 0, Throwable $previous = null) {
|
||||||
parent::__construct($message, $code, $previous);
|
parent::__construct($message, $code, $previous);
|
||||||
$this->setupIssue = $setupIssue;
|
$this->setupIssue = $setupIssue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSetupIssue(): string {
|
public function getSetupIssue(): string {
|
||||||
return $this->setupIssue;
|
return $this->setupIssue;
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ RewriteCond %{REQUEST_URI} !^/css/custom/
|
|||||||
RewriteRule ^css/tkr\.css$ public/css/tkr.css [L]
|
RewriteRule ^css/tkr\.css$ public/css/tkr.css [L]
|
||||||
|
|
||||||
# 404 all other static files (images, js, fonts, etc.)
|
# 404 all other static files (images, js, fonts, etc.)
|
||||||
# so those requests don't hit the PHP app
|
# so those requests don't hit the PHP app
|
||||||
# (this is to reduce load on the PHP app from bots and scanners)
|
# (this is to reduce load on the PHP app from bots and scanners)
|
||||||
RewriteRule \.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$ - [R=404,L]
|
RewriteRule \.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$ - [R=404,L]
|
||||||
|
|
||||||
|
@ -9,13 +9,13 @@
|
|||||||
# Replace localhost with your subdomain, e.g. tkr.my-domain.com
|
# Replace localhost with your subdomain, e.g. tkr.my-domain.com
|
||||||
ServerName localhost
|
ServerName localhost
|
||||||
DocumentRoot /var/www/tkr/public
|
DocumentRoot /var/www/tkr/public
|
||||||
|
|
||||||
# Security headers
|
# Security headers
|
||||||
Header always set X-Frame-Options "SAMEORIGIN"
|
Header always set X-Frame-Options "SAMEORIGIN"
|
||||||
Header always set X-XSS-Protection "1; mode=block"
|
Header always set X-XSS-Protection "1; mode=block"
|
||||||
Header always set X-Content-Type-Options "nosniff"
|
Header always set X-Content-Type-Options "nosniff"
|
||||||
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
||||||
|
|
||||||
# Block access to sensitive directories
|
# Block access to sensitive directories
|
||||||
<Directory "/var/www/tkr/storage">
|
<Directory "/var/www/tkr/storage">
|
||||||
Require all denied
|
Require all denied
|
||||||
@ -44,7 +44,7 @@
|
|||||||
Alias /css/tkr.css /var/www/tkr/public/css/tkr.css
|
Alias /css/tkr.css /var/www/tkr/public/css/tkr.css
|
||||||
|
|
||||||
# 404 all non-css static files (images, js, fonts, etc.)
|
# 404 all non-css static files (images, js, fonts, etc.)
|
||||||
# so those requests don't hit the PHP app
|
# so those requests don't hit the PHP app
|
||||||
# (this is to reduce load on the PHP app from bots and scanners)
|
# (this is to reduce load on the PHP app from bots and scanners)
|
||||||
<LocationMatch "\.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$">
|
<LocationMatch "\.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$">
|
||||||
<RequireAll>
|
<RequireAll>
|
||||||
@ -69,7 +69,7 @@
|
|||||||
RewriteCond %{REQUEST_URI} !^/css/custom/
|
RewriteCond %{REQUEST_URI} !^/css/custom/
|
||||||
RewriteRule ^css/tkr\.css$ css/tkr.css [L]
|
RewriteRule ^css/tkr\.css$ css/tkr.css [L]
|
||||||
|
|
||||||
# Everything else to front controller
|
# Everything else to front controller
|
||||||
RewriteCond %{REQUEST_FILENAME} !-f
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
RewriteCond %{REQUEST_FILENAME} !-d
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
RewriteRule ^(.*)$ index.php [L]
|
RewriteRule ^(.*)$ index.php [L]
|
||||||
|
@ -24,13 +24,13 @@
|
|||||||
# Replace with the actual paths to your cert and key
|
# Replace with the actual paths to your cert and key
|
||||||
SSLCertificateFile /etc/letsencrypt/live/tkr.my-domain.com/fullchain.pem
|
SSLCertificateFile /etc/letsencrypt/live/tkr.my-domain.com/fullchain.pem
|
||||||
SSLCertificateKeyFile /etc/letsencrypt/live/tkr.my-domain.com/privkey.pem
|
SSLCertificateKeyFile /etc/letsencrypt/live/tkr.my-domain.com/privkey.pem
|
||||||
|
|
||||||
# Security headers
|
# Security headers
|
||||||
Header always set X-Frame-Options "SAMEORIGIN"
|
Header always set X-Frame-Options "SAMEORIGIN"
|
||||||
Header always set X-XSS-Protection "1; mode=block"
|
Header always set X-XSS-Protection "1; mode=block"
|
||||||
Header always set X-Content-Type-Options "nosniff"
|
Header always set X-Content-Type-Options "nosniff"
|
||||||
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
||||||
|
|
||||||
# Block access to sensitive directories
|
# Block access to sensitive directories
|
||||||
<Directory "/var/www/tkr/storage">
|
<Directory "/var/www/tkr/storage">
|
||||||
Require all denied
|
Require all denied
|
||||||
@ -59,7 +59,7 @@
|
|||||||
Alias /css/tkr.css /var/www/tkr/public/css/tkr.css
|
Alias /css/tkr.css /var/www/tkr/public/css/tkr.css
|
||||||
|
|
||||||
# 404 all non-css static files (images, js, fonts, etc.)
|
# 404 all non-css static files (images, js, fonts, etc.)
|
||||||
# so those requests don't hit the PHP app
|
# so those requests don't hit the PHP app
|
||||||
# (this is to reduce load on the PHP app from bots and scanners)
|
# (this is to reduce load on the PHP app from bots and scanners)
|
||||||
<LocationMatch "\.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$">
|
<LocationMatch "\.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$">
|
||||||
<RequireAll>
|
<RequireAll>
|
||||||
@ -84,7 +84,7 @@
|
|||||||
RewriteCond %{REQUEST_URI} !^/css/custom/
|
RewriteCond %{REQUEST_URI} !^/css/custom/
|
||||||
RewriteRule ^css/tkr\.css$ css/tkr.css [L]
|
RewriteRule ^css/tkr\.css$ css/tkr.css [L]
|
||||||
|
|
||||||
# Everything else to front controller
|
# Everything else to front controller
|
||||||
RewriteCond %{REQUEST_FILENAME} !-f
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
RewriteCond %{REQUEST_FILENAME} !-d
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
RewriteRule ^(.*)$ index.php [L]
|
RewriteRule ^(.*)$ index.php [L]
|
||||||
|
@ -9,18 +9,18 @@
|
|||||||
# Replace localhost with your subdomain, e.g. tkr.my-domain.com
|
# Replace localhost with your subdomain, e.g. tkr.my-domain.com
|
||||||
ServerName localhost
|
ServerName localhost
|
||||||
DocumentRoot /var/www/html
|
DocumentRoot /var/www/html
|
||||||
|
|
||||||
# Security headers
|
# Security headers
|
||||||
Header always set X-Frame-Options "SAMEORIGIN"
|
Header always set X-Frame-Options "SAMEORIGIN"
|
||||||
Header always set X-XSS-Protection "1; mode=block"
|
Header always set X-XSS-Protection "1; mode=block"
|
||||||
Header always set X-Content-Type-Options "nosniff"
|
Header always set X-Content-Type-Options "nosniff"
|
||||||
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
||||||
|
|
||||||
# tkr Application at /tkr
|
# tkr Application at /tkr
|
||||||
# NOTE: If you change the directory name,
|
# NOTE: If you change the directory name,
|
||||||
# remember to update all instances of /var/www/tkr in this file to match
|
# remember to update all instances of /var/www/tkr in this file to match
|
||||||
Alias /tkr /var/www/tkr/public
|
Alias /tkr /var/www/tkr/public
|
||||||
|
|
||||||
# Block access to sensitive TKR directories
|
# Block access to sensitive TKR directories
|
||||||
<Directory "/var/www/tkr/storage">
|
<Directory "/var/www/tkr/storage">
|
||||||
Require all denied
|
Require all denied
|
||||||
@ -34,28 +34,28 @@
|
|||||||
<Directory "/var/www/tkr/config">
|
<Directory "/var/www/tkr/config">
|
||||||
Require all denied
|
Require all denied
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
# 404 all non-css static files in /tkr (images, js, fonts, etc.)
|
# 404 all non-css static files in /tkr (images, js, fonts, etc.)
|
||||||
# so those requests don't hit the PHP app
|
# so those requests don't hit the PHP app
|
||||||
# (this is to reduce load on the PHP app from bots and scanners)
|
# (this is to reduce load on the PHP app from bots and scanners)
|
||||||
<LocationMatch "^/tkr/.*\.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$">
|
<LocationMatch "^/tkr/.*\.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$">
|
||||||
<RequireAll>
|
<RequireAll>
|
||||||
Require all denied
|
Require all denied
|
||||||
</RequireAll>
|
</RequireAll>
|
||||||
</LocationMatch>
|
</LocationMatch>
|
||||||
|
|
||||||
# tkr application directory
|
# tkr application directory
|
||||||
<Directory "/var/www/tkr/public">
|
<Directory "/var/www/tkr/public">
|
||||||
Options -Indexes
|
Options -Indexes
|
||||||
AllowOverride None
|
AllowOverride None
|
||||||
Require all granted
|
Require all granted
|
||||||
|
|
||||||
RewriteEngine On
|
RewriteEngine On
|
||||||
|
|
||||||
# Block direct PHP access
|
# Block direct PHP access
|
||||||
RewriteCond %{THE_REQUEST} \s/[^?\s]*\.php[\s?] [NC]
|
RewriteCond %{THE_REQUEST} \s/[^?\s]*\.php[\s?] [NC]
|
||||||
RewriteRule ^.*$ - [R=404,L]
|
RewriteRule ^.*$ - [R=404,L]
|
||||||
|
|
||||||
# Serve the one static file that exists: css/tkr.css
|
# Serve the one static file that exists: css/tkr.css
|
||||||
# (Pass requests to css/custom/ through to the PHP app)
|
# (Pass requests to css/custom/ through to the PHP app)
|
||||||
RewriteCond %{REQUEST_URI} !^/tkr/css/custom/
|
RewriteCond %{REQUEST_URI} !^/tkr/css/custom/
|
||||||
@ -66,7 +66,7 @@
|
|||||||
RewriteCond %{REQUEST_FILENAME} !-d
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
RewriteRule ^(.*)$ index.php [L]
|
RewriteRule ^(.*)$ index.php [L]
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
# Error and access logs
|
# Error and access logs
|
||||||
ErrorLog ${APACHE_LOG_DIR}/my-domain_error.log
|
ErrorLog ${APACHE_LOG_DIR}/my-domain_error.log
|
||||||
CustomLog ${APACHE_LOG_DIR}/my-domain_access.log combined
|
CustomLog ${APACHE_LOG_DIR}/my-domain_access.log combined
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
# Replace localhost with your subdomain, e.g. tkr.my-domain.com
|
# Replace localhost with your subdomain, e.g. tkr.my-domain.com
|
||||||
ServerName localhost
|
ServerName localhost
|
||||||
DocumentRoot /var/www/html
|
DocumentRoot /var/www/html
|
||||||
|
|
||||||
# SSL Configuration
|
# SSL Configuration
|
||||||
SSLEngine on
|
SSLEngine on
|
||||||
|
|
||||||
@ -25,18 +25,18 @@
|
|||||||
# Replace with the actual paths to your cert and key
|
# Replace with the actual paths to your cert and key
|
||||||
SSLCertificateFile /etc/letsencrypt/live/my-domain.com/fullchain.pem
|
SSLCertificateFile /etc/letsencrypt/live/my-domain.com/fullchain.pem
|
||||||
SSLCertificateKeyFile /etc/letsencrypt/live/my-domain.com/privkey.pem
|
SSLCertificateKeyFile /etc/letsencrypt/live/my-domain.com/privkey.pem
|
||||||
|
|
||||||
# Security headers
|
# Security headers
|
||||||
Header always set X-Frame-Options "SAMEORIGIN"
|
Header always set X-Frame-Options "SAMEORIGIN"
|
||||||
Header always set X-XSS-Protection "1; mode=block"
|
Header always set X-XSS-Protection "1; mode=block"
|
||||||
Header always set X-Content-Type-Options "nosniff"
|
Header always set X-Content-Type-Options "nosniff"
|
||||||
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
||||||
|
|
||||||
# tkr Application at /tkr
|
# tkr Application at /tkr
|
||||||
# NOTE: If you change the directory name,
|
# NOTE: If you change the directory name,
|
||||||
# remember to update all instances of /var/www/tkr in this file to match
|
# remember to update all instances of /var/www/tkr in this file to match
|
||||||
Alias /tkr /var/www/tkr/public
|
Alias /tkr /var/www/tkr/public
|
||||||
|
|
||||||
# Block access to sensitive TKR directories
|
# Block access to sensitive TKR directories
|
||||||
<Directory "/var/www/tkr/storage">
|
<Directory "/var/www/tkr/storage">
|
||||||
Require all denied
|
Require all denied
|
||||||
@ -50,28 +50,28 @@
|
|||||||
<Directory "/var/www/tkr/config">
|
<Directory "/var/www/tkr/config">
|
||||||
Require all denied
|
Require all denied
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
# 404 all non-css static files in /tkr (images, js, fonts, etc.)
|
# 404 all non-css static files in /tkr (images, js, fonts, etc.)
|
||||||
# so those requests don't hit the PHP app
|
# so those requests don't hit the PHP app
|
||||||
# (this is to reduce load on the PHP app from bots and scanners)
|
# (this is to reduce load on the PHP app from bots and scanners)
|
||||||
<LocationMatch "^/tkr/.*\.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$">
|
<LocationMatch "^/tkr/.*\.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$">
|
||||||
<RequireAll>
|
<RequireAll>
|
||||||
Require all denied
|
Require all denied
|
||||||
</RequireAll>
|
</RequireAll>
|
||||||
</LocationMatch>
|
</LocationMatch>
|
||||||
|
|
||||||
# tkr application directory
|
# tkr application directory
|
||||||
<Directory "/var/www/tkr/public">
|
<Directory "/var/www/tkr/public">
|
||||||
Options -Indexes
|
Options -Indexes
|
||||||
AllowOverride None
|
AllowOverride None
|
||||||
Require all granted
|
Require all granted
|
||||||
|
|
||||||
RewriteEngine On
|
RewriteEngine On
|
||||||
|
|
||||||
# Block direct PHP access
|
# Block direct PHP access
|
||||||
RewriteCond %{THE_REQUEST} \s/[^?\s]*\.php[\s?] [NC]
|
RewriteCond %{THE_REQUEST} \s/[^?\s]*\.php[\s?] [NC]
|
||||||
RewriteRule ^.*$ - [R=404,L]
|
RewriteRule ^.*$ - [R=404,L]
|
||||||
|
|
||||||
# Serve the one static file that exists: css/tkr.css
|
# Serve the one static file that exists: css/tkr.css
|
||||||
# (Pass requests to css/custom/ through to the PHP app)
|
# (Pass requests to css/custom/ through to the PHP app)
|
||||||
RewriteCond %{REQUEST_URI} !^/tkr/css/custom/
|
RewriteCond %{REQUEST_URI} !^/tkr/css/custom/
|
||||||
@ -82,7 +82,7 @@
|
|||||||
RewriteCond %{REQUEST_FILENAME} !-d
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
RewriteRule ^(.*)$ index.php [L]
|
RewriteRule ^(.*)$ index.php [L]
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
# Error and access logs
|
# Error and access logs
|
||||||
ErrorLog ${APACHE_LOG_DIR}/my-domain_error.log
|
ErrorLog ${APACHE_LOG_DIR}/my-domain_error.log
|
||||||
CustomLog ${APACHE_LOG_DIR}/my-domain_access.log combined
|
CustomLog ${APACHE_LOG_DIR}/my-domain_access.log combined
|
||||||
|
@ -10,7 +10,7 @@ server {
|
|||||||
# replace localhost with your subdomain
|
# replace localhost with your subdomain
|
||||||
# e.g. tkr.my-domain.com
|
# e.g. tkr.my-domain.com
|
||||||
server_name localhost;
|
server_name localhost;
|
||||||
|
|
||||||
root /var/www/tkr/public;
|
root /var/www/tkr/public;
|
||||||
index index.php;
|
index index.php;
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ server {
|
|||||||
fastcgi_pass php:9000;
|
fastcgi_pass php:9000;
|
||||||
fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php;
|
fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php;
|
||||||
include fastcgi_params;
|
include fastcgi_params;
|
||||||
|
|
||||||
fastcgi_param REQUEST_METHOD $request_method;
|
fastcgi_param REQUEST_METHOD $request_method;
|
||||||
fastcgi_param REQUEST_URI $request_uri;
|
fastcgi_param REQUEST_URI $request_uri;
|
||||||
fastcgi_param QUERY_STRING $query_string;
|
fastcgi_param QUERY_STRING $query_string;
|
||||||
@ -73,7 +73,7 @@ server {
|
|||||||
# (these are bots and scanners)
|
# (these are bots and scanners)
|
||||||
location ~ ^/.+\.php$ {
|
location ~ ^/.+\.php$ {
|
||||||
return 404;
|
return 404;
|
||||||
}
|
}
|
||||||
|
|
||||||
# forward other requests to the fallback block,
|
# forward other requests to the fallback block,
|
||||||
# which sends them to php-fpm for handling
|
# which sends them to php-fpm for handling
|
||||||
@ -88,7 +88,7 @@ server {
|
|||||||
fastcgi_pass php:9000;
|
fastcgi_pass php:9000;
|
||||||
fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php;
|
fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php;
|
||||||
include fastcgi_params;
|
include fastcgi_params;
|
||||||
|
|
||||||
fastcgi_param REQUEST_METHOD $request_method;
|
fastcgi_param REQUEST_METHOD $request_method;
|
||||||
fastcgi_param REQUEST_URI $request_uri;
|
fastcgi_param REQUEST_URI $request_uri;
|
||||||
fastcgi_param QUERY_STRING $query_string;
|
fastcgi_param QUERY_STRING $query_string;
|
||||||
|
@ -17,7 +17,7 @@ server {
|
|||||||
# Replace with the actual paths to your cert and key
|
# Replace with the actual paths to your cert and key
|
||||||
ssl_certificate /etc/letsencrypt/live/tkr.my-domain.com/fullchain.pem;
|
ssl_certificate /etc/letsencrypt/live/tkr.my-domain.com/fullchain.pem;
|
||||||
ssl_certificate_key /etc/letsencrypt/live/tkr.my-domain.com/privkey.pem;
|
ssl_certificate_key /etc/letsencrypt/live/tkr.my-domain.com/privkey.pem;
|
||||||
|
|
||||||
root /var/www/tkr/public;
|
root /var/www/tkr/public;
|
||||||
index index.php;
|
index index.php;
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ server {
|
|||||||
fastcgi_pass php:9000;
|
fastcgi_pass php:9000;
|
||||||
fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php;
|
fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php;
|
||||||
include fastcgi_params;
|
include fastcgi_params;
|
||||||
|
|
||||||
fastcgi_param REQUEST_METHOD $request_method;
|
fastcgi_param REQUEST_METHOD $request_method;
|
||||||
fastcgi_param REQUEST_URI $request_uri;
|
fastcgi_param REQUEST_URI $request_uri;
|
||||||
fastcgi_param QUERY_STRING $query_string;
|
fastcgi_param QUERY_STRING $query_string;
|
||||||
@ -71,7 +71,7 @@ server {
|
|||||||
# (these are bots and scanners)
|
# (these are bots and scanners)
|
||||||
location ~ ^/.+\.php$ {
|
location ~ ^/.+\.php$ {
|
||||||
return 404;
|
return 404;
|
||||||
}
|
}
|
||||||
|
|
||||||
# forward other requests to the fallback block,
|
# forward other requests to the fallback block,
|
||||||
# which sends them to php-fpm for handling
|
# which sends them to php-fpm for handling
|
||||||
@ -86,7 +86,7 @@ server {
|
|||||||
fastcgi_pass php:9000;
|
fastcgi_pass php:9000;
|
||||||
fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php;
|
fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php;
|
||||||
include fastcgi_params;
|
include fastcgi_params;
|
||||||
|
|
||||||
fastcgi_param REQUEST_METHOD $request_method;
|
fastcgi_param REQUEST_METHOD $request_method;
|
||||||
fastcgi_param REQUEST_URI $request_uri;
|
fastcgi_param REQUEST_URI $request_uri;
|
||||||
fastcgi_param QUERY_STRING $query_string;
|
fastcgi_param QUERY_STRING $query_string;
|
||||||
|
@ -12,7 +12,7 @@ server {
|
|||||||
# replace localhost with your subdomain
|
# replace localhost with your subdomain
|
||||||
# e.g. tkr.my-domain.com
|
# e.g. tkr.my-domain.com
|
||||||
server_name localhost;
|
server_name localhost;
|
||||||
|
|
||||||
root /var/www/html;
|
root /var/www/html;
|
||||||
index index.html;
|
index index.html;
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ server {
|
|||||||
fastcgi_pass php:9000;
|
fastcgi_pass php:9000;
|
||||||
fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php;
|
fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php;
|
||||||
include fastcgi_params;
|
include fastcgi_params;
|
||||||
|
|
||||||
fastcgi_param REQUEST_METHOD $request_method;
|
fastcgi_param REQUEST_METHOD $request_method;
|
||||||
fastcgi_param REQUEST_URI $request_uri;
|
fastcgi_param REQUEST_URI $request_uri;
|
||||||
fastcgi_param QUERY_STRING $query_string;
|
fastcgi_param QUERY_STRING $query_string;
|
||||||
@ -75,7 +75,7 @@ server {
|
|||||||
# (these are bots and scanners)
|
# (these are bots and scanners)
|
||||||
location ~ ^/tkr/.+\.php$ {
|
location ~ ^/tkr/.+\.php$ {
|
||||||
return 404;
|
return 404;
|
||||||
}
|
}
|
||||||
|
|
||||||
# forward other requests to the fallback block,
|
# forward other requests to the fallback block,
|
||||||
# which sends them to php-fpm for handling
|
# which sends them to php-fpm for handling
|
||||||
@ -87,7 +87,7 @@ server {
|
|||||||
fastcgi_pass php:9000;
|
fastcgi_pass php:9000;
|
||||||
fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php;
|
fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php;
|
||||||
include fastcgi_params;
|
include fastcgi_params;
|
||||||
|
|
||||||
fastcgi_param REQUEST_METHOD $request_method;
|
fastcgi_param REQUEST_METHOD $request_method;
|
||||||
fastcgi_param REQUEST_URI $request_uri;
|
fastcgi_param REQUEST_URI $request_uri;
|
||||||
fastcgi_param QUERY_STRING $query_string;
|
fastcgi_param QUERY_STRING $query_string;
|
||||||
|
@ -8,11 +8,11 @@
|
|||||||
server {
|
server {
|
||||||
listen 443 ssl;
|
listen 443 ssl;
|
||||||
listen [::]:443 ssl;
|
listen [::]:443 ssl;
|
||||||
|
|
||||||
# Replace localhost with your domain
|
# Replace localhost with your domain
|
||||||
# e.g. my-domain.com
|
# e.g. my-domain.com
|
||||||
server_name localhost;
|
server_name localhost;
|
||||||
|
|
||||||
root /var/www/html;
|
root /var/www/html;
|
||||||
index index.html;
|
index index.html;
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ server {
|
|||||||
fastcgi_pass php:9000;
|
fastcgi_pass php:9000;
|
||||||
fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php;
|
fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php;
|
||||||
include fastcgi_params;
|
include fastcgi_params;
|
||||||
|
|
||||||
fastcgi_param REQUEST_METHOD $request_method;
|
fastcgi_param REQUEST_METHOD $request_method;
|
||||||
fastcgi_param REQUEST_URI $request_uri;
|
fastcgi_param REQUEST_URI $request_uri;
|
||||||
fastcgi_param QUERY_STRING $query_string;
|
fastcgi_param QUERY_STRING $query_string;
|
||||||
@ -66,7 +66,7 @@ server {
|
|||||||
# (these are bots and scanners)
|
# (these are bots and scanners)
|
||||||
location ~ ^/tkr/.+\.php$ {
|
location ~ ^/tkr/.+\.php$ {
|
||||||
return 404;
|
return 404;
|
||||||
}
|
}
|
||||||
|
|
||||||
# forward other requests to the fallback block,
|
# forward other requests to the fallback block,
|
||||||
# which sends them to php-fpm for handling
|
# which sends them to php-fpm for handling
|
||||||
@ -78,7 +78,7 @@ server {
|
|||||||
fastcgi_pass php:9000;
|
fastcgi_pass php:9000;
|
||||||
fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php;
|
fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php;
|
||||||
include fastcgi_params;
|
include fastcgi_params;
|
||||||
|
|
||||||
fastcgi_param REQUEST_METHOD $request_method;
|
fastcgi_param REQUEST_METHOD $request_method;
|
||||||
fastcgi_param REQUEST_URI $request_uri;
|
fastcgi_param REQUEST_URI $request_uri;
|
||||||
fastcgi_param QUERY_STRING $query_string;
|
fastcgi_param QUERY_STRING $query_string;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
--color-primary-light: #bae6fd;
|
--color-primary-light: #bae6fd;
|
||||||
--color-primary-lighter: #ebf8ff;
|
--color-primary-lighter: #ebf8ff;
|
||||||
--color-primary-lightest: #f0f9ff;
|
--color-primary-lightest: #f0f9ff;
|
||||||
|
|
||||||
/* Text colors */
|
/* Text colors */
|
||||||
--color-text-primary: #374151;
|
--color-text-primary: #374151;
|
||||||
--color-text-secondary: #1e40af;
|
--color-text-secondary: #1e40af;
|
||||||
@ -16,25 +16,25 @@
|
|||||||
--color-text-muted: gray;
|
--color-text-muted: gray;
|
||||||
--color-text-black: black;
|
--color-text-black: black;
|
||||||
--color-text-dark: #333;
|
--color-text-dark: #333;
|
||||||
|
|
||||||
/* Background colors */
|
/* Background colors */
|
||||||
--color-bg-body: whitesmoke;
|
--color-bg-body: whitesmoke;
|
||||||
--color-bg-white: white;
|
--color-bg-white: white;
|
||||||
--color-bg-light: #fefefe;
|
--color-bg-light: #fefefe;
|
||||||
--color-bg-file: #f8fafc;
|
--color-bg-file: #f8fafc;
|
||||||
|
|
||||||
/* Border colors */
|
/* Border colors */
|
||||||
--color-border-light: #e5e7eb;
|
--color-border-light: #e5e7eb;
|
||||||
--color-border-medium: #d1d5db;
|
--color-border-medium: #d1d5db;
|
||||||
--color-border-file: #cbd5e0;
|
--color-border-file: #cbd5e0;
|
||||||
|
|
||||||
/* State colors */
|
/* State colors */
|
||||||
--color-required: #dc2626;
|
--color-required: #dc2626;
|
||||||
--color-hover-light: #dbeafe;
|
--color-hover-light: #dbeafe;
|
||||||
--color-hover-medium: #bfdbfe;
|
--color-hover-medium: #bfdbfe;
|
||||||
--color-emoji-bg: #ddeeff;
|
--color-emoji-bg: #ddeeff;
|
||||||
--color-emoji-border: #339;
|
--color-emoji-border: #339;
|
||||||
|
|
||||||
/* Shadow colors */
|
/* Shadow colors */
|
||||||
--shadow-primary: rgba(66, 153, 225, 0.1);
|
--shadow-primary: rgba(66, 153, 225, 0.1);
|
||||||
--shadow-primary-strong: rgba(66, 153, 225, 0.3);
|
--shadow-primary-strong: rgba(66, 153, 225, 0.3);
|
||||||
@ -108,9 +108,9 @@ h1.site-description {
|
|||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="text"],
|
input[type="text"],
|
||||||
input[type="number"],
|
input[type="number"],
|
||||||
input[type="password"],
|
input[type="password"],
|
||||||
textarea,
|
textarea,
|
||||||
select {
|
select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -124,9 +124,9 @@ select {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="text"]:focus,
|
input[type="text"]:focus,
|
||||||
input[type="number"]:focus,
|
input[type="number"]:focus,
|
||||||
input[type="password"]:focus,
|
input[type="password"]:focus,
|
||||||
textarea:focus,
|
textarea:focus,
|
||||||
select:focus {
|
select:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
@ -205,14 +205,14 @@ label.description {
|
|||||||
|
|
||||||
.navbar {
|
.navbar {
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
background: var(--color-bg-white);
|
background: var(--color-bg-white);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar a {
|
.navbar a {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: var(--color-text-secondary);
|
color: var(--color-text-secondary);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 14px 16px;
|
padding: 14px 16px;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
@ -229,9 +229,9 @@ label.description {
|
|||||||
box-shadow: 0 0 0 2px var(--shadow-primary);
|
box-shadow: 0 0 0 2px var(--shadow-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Using details/summary tags to build dropdowm nmenus.
|
Using details/summary tags to build dropdowm nmenus.
|
||||||
They have to be clicked open and closed, but they allow
|
They have to be clicked open and closed, but they allow
|
||||||
me to have semantically appropriate pure HTML dropdowms
|
me to have semantically appropriate pure HTML dropdowms
|
||||||
that work on mobile devices.
|
that work on mobile devices.
|
||||||
*/
|
*/
|
||||||
@ -241,7 +241,7 @@ label.description {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.dropdown summary.dropbtn {
|
.dropdown summary.dropbtn {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0px;
|
border-radius: 0px;
|
||||||
outline: none;
|
outline: none;
|
||||||
@ -424,13 +424,13 @@ label.description {
|
|||||||
|
|
||||||
/* Styling for flash messages */
|
/* Styling for flash messages */
|
||||||
.flash-messages {
|
.flash-messages {
|
||||||
background: var(--color-bg-white);
|
background: var(--color-bg-white);
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 2px 10px var(--shadow-primary);
|
box-shadow: 0 2px 10px var(--shadow-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.flash-message {
|
.flash-message {
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
margin: 5px 0;
|
margin: 5px 0;
|
||||||
@ -462,7 +462,7 @@ label.description {
|
|||||||
border-left-color: var(--color-flash-info-border-left);
|
border-left-color: var(--color-flash-info-border-left);
|
||||||
color: var(--color-flash-info);
|
color: var(--color-flash-info);
|
||||||
}
|
}
|
||||||
|
|
||||||
.fieldset-items {
|
.fieldset-items {
|
||||||
margin-bottom: 14px;
|
margin-bottom: 14px;
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -532,7 +532,7 @@ label.description {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tick-time {
|
.tick-time {
|
||||||
color: var(--color-text-muted);
|
color: var(--color-text-muted);
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
margin-bottom: 0.4em;
|
margin-bottom: 0.4em;
|
||||||
}
|
}
|
||||||
@ -543,9 +543,9 @@ label.description {
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tick-pagination a {
|
.tick-pagination a {
|
||||||
margin: 0 5px;
|
margin: 0 5px;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.emoji-option input {
|
.emoji-option input {
|
||||||
@ -616,7 +616,7 @@ label.description {
|
|||||||
box-shadow: 0 0 0 2px var(--shadow-primary);
|
box-shadow: 0 0 0 2px var(--shadow-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Responsive layout - adjusts from 1 to 2 columns based on screen width
|
Responsive layout - adjusts from 1 to 2 columns based on screen width
|
||||||
- min-width makes the mobile (stacked) view the default
|
- min-width makes the mobile (stacked) view the default
|
||||||
- 600px covers most mobile devices in portrait mode
|
- 600px covers most mobile devices in portrait mode
|
||||||
@ -633,7 +633,7 @@ label.description {
|
|||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-container {
|
.home-container {
|
||||||
grid-template-columns: 1fr 2fr;
|
grid-template-columns: 1fr 2fr;
|
||||||
grid-gap: 2em;
|
grid-gap: 2em;
|
||||||
@ -646,7 +646,7 @@ label.description {
|
|||||||
gap: 16px;
|
gap: 16px;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-info {
|
.file-info {
|
||||||
grid-column: 2;
|
grid-column: 2;
|
||||||
}
|
}
|
||||||
@ -654,7 +654,7 @@ label.description {
|
|||||||
.navbar {
|
.navbar {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-menu {
|
.dropdown-menu {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 1em;
|
left: 1em;
|
||||||
|
@ -51,13 +51,13 @@ class AdminController extends Controller {
|
|||||||
// handle form submission
|
// handle form submission
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
$errors = [];
|
$errors = [];
|
||||||
|
|
||||||
// UserModel profile
|
// UserModel profile
|
||||||
$username = trim($_POST['username'] ?? '');
|
$username = trim($_POST['username'] ?? '');
|
||||||
$displayName = trim($_POST['display_name'] ?? '');
|
$displayName = trim($_POST['display_name'] ?? '');
|
||||||
$about = trim($_POST['about'] ?? '');
|
$about = trim($_POST['about'] ?? '');
|
||||||
$website = trim($_POST['website'] ?? '');
|
$website = trim($_POST['website'] ?? '');
|
||||||
|
|
||||||
// Site settings
|
// Site settings
|
||||||
$siteTitle = trim($_POST['site_title']) ?? '';
|
$siteTitle = trim($_POST['site_title']) ?? '';
|
||||||
$siteDescription = trim($_POST['site_description']) ?? '';
|
$siteDescription = trim($_POST['site_description']) ?? '';
|
||||||
@ -68,7 +68,7 @@ class AdminController extends Controller {
|
|||||||
// Password
|
// Password
|
||||||
$password = $_POST['password'] ?? '';
|
$password = $_POST['password'] ?? '';
|
||||||
$confirmPassword = $_POST['confirm_password'] ?? '';
|
$confirmPassword = $_POST['confirm_password'] ?? '';
|
||||||
|
|
||||||
// Validate user profile
|
// Validate user profile
|
||||||
if (!$username) {
|
if (!$username) {
|
||||||
$errors[] = "Username is required.";
|
$errors[] = "Username is required.";
|
||||||
@ -87,7 +87,7 @@ class AdminController extends Controller {
|
|||||||
$errors[] = "URL must start with http:// or https://.";
|
$errors[] = "URL must start with http:// or https://.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate site settings
|
// Validate site settings
|
||||||
if (!$siteTitle) {
|
if (!$siteTitle) {
|
||||||
$errors[] = "Site title is required.";
|
$errors[] = "Site title is required.";
|
||||||
@ -98,12 +98,12 @@ class AdminController extends Controller {
|
|||||||
if ($itemsPerPage < 1 || $itemsPerPage > 50) {
|
if ($itemsPerPage < 1 || $itemsPerPage > 50) {
|
||||||
$errors[] = "Items per page must be a number between 1 and 50.";
|
$errors[] = "Items per page must be a number between 1 and 50.";
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a password was sent, make sure it matches the confirmation
|
// If a password was sent, make sure it matches the confirmation
|
||||||
if ($password && !($password === $confirmPassword)){
|
if ($password && !($password === $confirmPassword)){
|
||||||
$errors[] = "Passwords do not match";
|
$errors[] = "Passwords do not match";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validation complete
|
// Validation complete
|
||||||
if (empty($errors)) {
|
if (empty($errors)) {
|
||||||
// Update site settings
|
// Update site settings
|
||||||
@ -112,21 +112,21 @@ class AdminController extends Controller {
|
|||||||
$config->baseUrl = $baseUrl;
|
$config->baseUrl = $baseUrl;
|
||||||
$config->basePath = $basePath;
|
$config->basePath = $basePath;
|
||||||
$config->itemsPerPage = $itemsPerPage;
|
$config->itemsPerPage = $itemsPerPage;
|
||||||
|
|
||||||
// Save site settings and reload config from database
|
// Save site settings and reload config from database
|
||||||
// TODO - raise and handle exception on failure
|
// TODO - raise and handle exception on failure
|
||||||
$config = $config->save();
|
$config = $config->save();
|
||||||
|
|
||||||
// Update user profile
|
// Update user profile
|
||||||
$user->username = $username;
|
$user->username = $username;
|
||||||
$user->displayName = $displayName;
|
$user->displayName = $displayName;
|
||||||
$user->about = $about;
|
$user->about = $about;
|
||||||
$user->website = $website;
|
$user->website = $website;
|
||||||
|
|
||||||
// Save user profile and reload user from database
|
// Save user profile and reload user from database
|
||||||
// TODO - raise and handle exception on failure
|
// TODO - raise and handle exception on failure
|
||||||
$user = $user->save();
|
$user = $user->save();
|
||||||
|
|
||||||
// Update the password if one was sent
|
// Update the password if one was sent
|
||||||
// TODO - raise and handle exception on failure
|
// TODO - raise and handle exception on failure
|
||||||
if($password){
|
if($password){
|
||||||
|
@ -19,13 +19,13 @@ class AuthController extends Controller {
|
|||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
$username = $_POST['username'] ?? '';
|
$username = $_POST['username'] ?? '';
|
||||||
$password = $_POST['password'] ?? '';
|
$password = $_POST['password'] ?? '';
|
||||||
|
|
||||||
// TODO: move into user model
|
// TODO: move into user model
|
||||||
global $db;
|
global $db;
|
||||||
$stmt = $db->prepare("SELECT id, username, password_hash FROM user WHERE username = ?");
|
$stmt = $db->prepare("SELECT id, username, password_hash FROM user WHERE username = ?");
|
||||||
$stmt->execute([$username]);
|
$stmt->execute([$username]);
|
||||||
$user = $stmt->fetch();
|
$user = $stmt->fetch();
|
||||||
|
|
||||||
if ($user && password_verify($password, $user['password_hash'])) {
|
if ($user && password_verify($password, $user['password_hash'])) {
|
||||||
session_regenerate_id(true);
|
session_regenerate_id(true);
|
||||||
// TODO: move into session.php
|
// TODO: move into session.php
|
||||||
|
@ -24,5 +24,5 @@ class Controller {
|
|||||||
|
|
||||||
extract($vars, EXTR_SKIP);
|
extract($vars, EXTR_SKIP);
|
||||||
include $templatePath;
|
include $templatePath;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -76,7 +76,7 @@ class CssController extends Controller {
|
|||||||
http_response_code(400);
|
http_response_code(400);
|
||||||
exit("Cannot delete default theme");
|
exit("Cannot delete default theme");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the data for the selected CSS file
|
// Get the data for the selected CSS file
|
||||||
$cssId = $_POST['selectCssFile'];
|
$cssId = $_POST['selectCssFile'];
|
||||||
$cssModel = new CssModel();
|
$cssModel = new CssModel();
|
||||||
@ -87,7 +87,7 @@ class CssController extends Controller {
|
|||||||
http_response_code(400);
|
http_response_code(400);
|
||||||
exit("No entry found for css id $cssId");
|
exit("No entry found for css id $cssId");
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the filename
|
// get the filename
|
||||||
$cssFilename = $cssRow["filename"];
|
$cssFilename = $cssRow["filename"];
|
||||||
|
|
||||||
@ -151,7 +151,7 @@ class CssController extends Controller {
|
|||||||
// Validate file extension
|
// Validate file extension
|
||||||
$filename = $file['name'];
|
$filename = $file['name'];
|
||||||
$fileExtension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
|
$fileExtension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
|
||||||
|
|
||||||
if ($fileExtension !== 'css') {
|
if ($fileExtension !== 'css') {
|
||||||
throw new Exception('File must have a .css extension');
|
throw new Exception('File must have a .css extension');
|
||||||
}
|
}
|
||||||
@ -186,7 +186,7 @@ class CssController extends Controller {
|
|||||||
// Add upload to database
|
// Add upload to database
|
||||||
$cssModel = new CssModel();
|
$cssModel = new CssModel();
|
||||||
$cssModel->save($safeFilename, $description);
|
$cssModel->save($safeFilename, $description);
|
||||||
|
|
||||||
// Set success flash message
|
// Set success flash message
|
||||||
Session::setFlashMessage('success', 'Theme uploaded as ' . $safeFilename);
|
Session::setFlashMessage('success', 'Theme uploaded as ' . $safeFilename);
|
||||||
|
|
||||||
@ -200,11 +200,11 @@ class CssController extends Controller {
|
|||||||
private function validateCssContent($content) {
|
private function validateCssContent($content) {
|
||||||
// Remove comments
|
// Remove comments
|
||||||
$content = preg_replace('/\/\*.*?\*\//s', '', $content);
|
$content = preg_replace('/\/\*.*?\*\//s', '', $content);
|
||||||
|
|
||||||
// Basic CSS validation - check for balanced braces
|
// Basic CSS validation - check for balanced braces
|
||||||
$openBraces = substr_count($content, '{');
|
$openBraces = substr_count($content, '{');
|
||||||
$closeBraces = substr_count($content, '}');
|
$closeBraces = substr_count($content, '}');
|
||||||
|
|
||||||
if ($openBraces !== $closeBraces) {
|
if ($openBraces !== $closeBraces) {
|
||||||
throw new Exception('Invalid CSS: Unbalanced braces detected');
|
throw new Exception('Invalid CSS: Unbalanced braces detected');
|
||||||
}
|
}
|
||||||
@ -261,7 +261,7 @@ class CssController extends Controller {
|
|||||||
// Remove path information and dangerous characters
|
// Remove path information and dangerous characters
|
||||||
$fileName = basename($originalName);
|
$fileName = basename($originalName);
|
||||||
$fileName = preg_replace('/[^a-zA-Z0-9._-]/', '_', $fileName);
|
$fileName = preg_replace('/[^a-zA-Z0-9._-]/', '_', $fileName);
|
||||||
|
|
||||||
return $fileName;
|
return $fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
'config' => $config,
|
'config' => $config,
|
||||||
'moodPicker' => $moodPicker,
|
'moodPicker' => $moodPicker,
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->render("mood.php", $vars);
|
$this->render("mood.php", $vars);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,7 +33,7 @@
|
|||||||
// set or clear the mood
|
// set or clear the mood
|
||||||
$user->mood = $mood;
|
$user->mood = $mood;
|
||||||
$user = $user->save();
|
$user = $user->save();
|
||||||
|
|
||||||
// go back to the index and show the updated mood
|
// go back to the index and show the updated mood
|
||||||
header('Location: ' . $config->basePath);
|
header('Location: ' . $config->basePath);
|
||||||
exit;
|
exit;
|
||||||
|
@ -4,7 +4,7 @@ class TickController extends Controller{
|
|||||||
// every tick is identified by its timestamp
|
// every tick is identified by its timestamp
|
||||||
public function index(string $year, string $month, string $day, string $hour, string $minute, string $second){
|
public function index(string $year, string $month, string $day, string $hour, string $minute, string $second){
|
||||||
$model = new TickModel();
|
$model = new TickModel();
|
||||||
$tick = $model->get($year, $month, $day, $hour, $minute, $second);
|
$tick = $model->get($year, $month, $day, $hour, $minute, $second);
|
||||||
$this->render('tick.php', $tick);
|
$this->render('tick.php', $tick);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -24,7 +24,7 @@ class Util {
|
|||||||
},
|
},
|
||||||
$text
|
$text
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For relative time display, compare the stored time to the current time
|
// For relative time display, compare the stored time to the current time
|
||||||
// and display it as "X seconds/minutes/hours/days etc." ago
|
// and display it as "X seconds/minutes/hours/days etc." ago
|
||||||
@ -59,6 +59,6 @@ class Util {
|
|||||||
[$year, $month, $day] = $dateParts;
|
[$year, $month, $day] = $dateParts;
|
||||||
[$hour, $minute, $second] = $timeParts;
|
[$hour, $minute, $second] = $timeParts;
|
||||||
|
|
||||||
return "$year/$month/$day/$hour/$minute/$second";
|
return "$year/$month/$day/$hour/$minute/$second";
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -36,11 +36,11 @@ class ConfigModel {
|
|||||||
if (empty($this->cssId)) {
|
if (empty($this->cssId)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch filename from css table using cssId
|
// Fetch filename from css table using cssId
|
||||||
$cssModel = new CssModel();
|
$cssModel = new CssModel();
|
||||||
$cssRecord = $cssModel->getById($this->cssId);
|
$cssRecord = $cssModel->getById($this->cssId);
|
||||||
|
|
||||||
return $cssRecord ? $cssRecord['filename'] : null;
|
return $cssRecord ? $cssRecord['filename'] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ class TickModel {
|
|||||||
// split the path to the current file into the date components
|
// split the path to the current file into the date components
|
||||||
$pathParts = explode('/', str_replace('\\', '/', $file));
|
$pathParts = explode('/', str_replace('\\', '/', $file));
|
||||||
|
|
||||||
// assign the different components to the appropriate part of the date
|
// assign the different components to the appropriate part of the date
|
||||||
$year = $pathParts[count($pathParts) - 3];
|
$year = $pathParts[count($pathParts) - 3];
|
||||||
$month = $pathParts[count($pathParts) - 2];
|
$month = $pathParts[count($pathParts) - 2];
|
||||||
$day = pathinfo($pathParts[count($pathParts) - 1], PATHINFO_FILENAME);
|
$day = pathinfo($pathParts[count($pathParts) - 1], PATHINFO_FILENAME);
|
||||||
@ -75,18 +75,18 @@ class TickModel {
|
|||||||
$content = $time . "|" . $tick . "\n";
|
$content = $time . "|" . $tick . "\n";
|
||||||
file_put_contents($filename, $content, FILE_APPEND);
|
file_put_contents($filename, $content, FILE_APPEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function get(string $y, string $m, string $d, string $H, string $i, string $s): array{
|
public static function get(string $y, string $m, string $d, string $H, string $i, string $s): array{
|
||||||
$tickTime = new DateTime("$y-$m-$d $H:$i:$s");
|
$tickTime = new DateTime("$y-$m-$d $H:$i:$s");
|
||||||
$timestamp = "$H:$i:$s";
|
$timestamp = "$H:$i:$s";
|
||||||
$file = TICKS_DIR . "/$y/$m/$d.txt";
|
$file = TICKS_DIR . "/$y/$m/$d.txt";
|
||||||
|
|
||||||
if (!file_exists($file)) {
|
if (!file_exists($file)) {
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
echo "Tick not found: $file.";
|
echo "Tick not found: $file.";
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$lines = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
$lines = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||||
foreach ($lines as $line) {
|
foreach ($lines as $line) {
|
||||||
if (str_starts_with($line, $timestamp)) {
|
if (str_starts_with($line, $timestamp)) {
|
||||||
|
@ -46,7 +46,7 @@ class UserModel {
|
|||||||
// loading the password into memory
|
// loading the password into memory
|
||||||
public function set_password(string $password): void {
|
public function set_password(string $password): void {
|
||||||
global $db;
|
global $db;
|
||||||
|
|
||||||
$hash = password_hash($password, PASSWORD_DEFAULT);
|
$hash = password_hash($password, PASSWORD_DEFAULT);
|
||||||
$stmt = $db->prepare("UPDATE user SET password_hash=? WHERE id=1");
|
$stmt = $db->prepare("UPDATE user SET password_hash=? WHERE id=1");
|
||||||
$stmt->execute([$hash]);
|
$stmt->execute([$hash]);
|
||||||
|
@ -12,7 +12,7 @@ echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
|
|||||||
<channel>
|
<channel>
|
||||||
<title><?php echo Util::escape_xml($config->siteTitle . 'RSS Feed') ?></title>
|
<title><?php echo Util::escape_xml($config->siteTitle . 'RSS Feed') ?></title>
|
||||||
<link><?php echo Util::escape_xml($config->baseUrl . $config->basePath)?></link>
|
<link><?php echo Util::escape_xml($config->baseUrl . $config->basePath)?></link>
|
||||||
<atom:link href="<?php echo Util::escape_xml($config->baseUrl . $config->basePath. 'feed/rss')?>"
|
<atom:link href="<?php echo Util::escape_xml($config->baseUrl . $config->basePath. 'feed/rss')?>"
|
||||||
rel="self"
|
rel="self"
|
||||||
type="application/rss+xml" />
|
type="application/rss+xml" />
|
||||||
<description><?php echo Util::escape_xml($config->siteDescription) ?></description>
|
<description><?php echo Util::escape_xml($config->siteDescription) ?></description>
|
||||||
|
@ -18,11 +18,11 @@
|
|||||||
<link rel="alternate"
|
<link rel="alternate"
|
||||||
type="application/rss+xml"
|
type="application/rss+xml"
|
||||||
title="<?php echo Util::escape_html($config->siteTitle) ?> RSS Feed"
|
title="<?php echo Util::escape_html($config->siteTitle) ?> RSS Feed"
|
||||||
href="<?php echo Util::escape_html($config->baseUrl . $config->basePath)?>feed/rss/">
|
href="<?php echo Util::escape_html($config->baseUrl . $config->basePath)?>feed/rss/">
|
||||||
<link rel="alternate"
|
<link rel="alternate"
|
||||||
type="application/atom+xml"
|
type="application/atom+xml"
|
||||||
title="<?php echo Util::escape_html($config->siteTitle) ?> Atom Feed"
|
title="<?php echo Util::escape_html($config->siteTitle) ?> Atom Feed"
|
||||||
href="<?php echo Util::escape_html($config->baseUrl . $config->basePath)?>feed/atom/">
|
href="<?php echo Util::escape_html($config->baseUrl . $config->basePath)?>feed/atom/">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<?php include TEMPLATES_DIR . '/partials/navbar.php'?>
|
<?php include TEMPLATES_DIR . '/partials/navbar.php'?>
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<h1><?php if ($isSetup): ?>Setup<?php else: ?>Admin<?php endif; ?></h1>
|
<h1><?php if ($isSetup): ?>Setup<?php else: ?>Admin<?php endif; ?></h1>
|
||||||
<div>
|
<div>
|
||||||
<form
|
<form
|
||||||
action="<?php echo $config->basePath . ($isSetup ? 'setup' : 'admin') ?>"
|
action="<?php echo $config->basePath . ($isSetup ? 'setup' : 'admin') ?>"
|
||||||
method="post">
|
method="post">
|
||||||
<input type="hidden" name="csrf_token" value="<?= Util::escape_html($_SESSION['csrf_token']) ?>">
|
<input type="hidden" name="csrf_token" value="<?= Util::escape_html($_SESSION['csrf_token']) ?>">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
@ -16,7 +16,7 @@
|
|||||||
value="<?= Util::escape_html($user->username) ?>"
|
value="<?= Util::escape_html($user->username) ?>"
|
||||||
required>
|
required>
|
||||||
<label>Display name <span class=required>*</span></label>
|
<label>Display name <span class=required>*</span></label>
|
||||||
<input type="text"
|
<input type="text"
|
||||||
name="display_name"
|
name="display_name"
|
||||||
value="<?= Util::escape_html($user->displayName) ?>"
|
value="<?= Util::escape_html($user->displayName) ?>"
|
||||||
required>
|
required>
|
||||||
@ -36,7 +36,7 @@
|
|||||||
<label>Title <span class=required>*</span></label>
|
<label>Title <span class=required>*</span></label>
|
||||||
<input type="text"
|
<input type="text"
|
||||||
name="site_title"
|
name="site_title"
|
||||||
value="<?= Util::escape_html($config->siteTitle) ?>"
|
value="<?= Util::escape_html($config->siteTitle) ?>"
|
||||||
required>
|
required>
|
||||||
<label>Description <span class=required>*</span></label>
|
<label>Description <span class=required>*</span></label>
|
||||||
<input type="text"
|
<input type="text"
|
||||||
@ -47,7 +47,7 @@
|
|||||||
name="base_url"
|
name="base_url"
|
||||||
value="<?= Util::escape_html($config->baseUrl) ?>"
|
value="<?= Util::escape_html($config->baseUrl) ?>"
|
||||||
required>
|
required>
|
||||||
<label>Base path <span class=required>*</span></label>
|
<label>Base path <span class=required>*</span></label>
|
||||||
<input type="text"
|
<input type="text"
|
||||||
name="base_path"
|
name="base_path"
|
||||||
value="<?= Util::escape_html($config->basePath) ?>"
|
value="<?= Util::escape_html($config->basePath) ?>"
|
||||||
@ -62,7 +62,7 @@
|
|||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Change password</legend>
|
<legend>Change password</legend>
|
||||||
<div class="fieldset-items">
|
<div class="fieldset-items">
|
||||||
<label>New password
|
<label>New password
|
||||||
<?php if($isSetup): ?><span class=required>*</span><?php endif; ?>
|
<?php if($isSetup): ?><span class=required>*</span><?php endif; ?>
|
||||||
</label>
|
</label>
|
||||||
<input type="password"
|
<input type="password"
|
||||||
|
@ -11,14 +11,14 @@
|
|||||||
<select id="selectCssFile" name="selectCssFile" value=<?= $config->cssId ?>>
|
<select id="selectCssFile" name="selectCssFile" value=<?= $config->cssId ?>>
|
||||||
<option value="">Default</option>
|
<option value="">Default</option>
|
||||||
<?php foreach ($customCss as $cssFile): ?>
|
<?php foreach ($customCss as $cssFile): ?>
|
||||||
<?php
|
<?php
|
||||||
if ($cssFile['id'] == $config->cssId){
|
if ($cssFile['id'] == $config->cssId){
|
||||||
$cssDescription = $cssFile['description'];
|
$cssDescription = $cssFile['description'];
|
||||||
$selected = "selected";
|
$selected = "selected";
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<option value=<?= $cssFile['id'] ?>
|
<option value=<?= $cssFile['id'] ?>
|
||||||
<?= isset($selected) ? $selected : ""?>>
|
<?= isset($selected) ? $selected : ""?>>
|
||||||
<?=Util::escape_html($cssFile['filename'])?>
|
<?=Util::escape_html($cssFile['filename'])?>
|
||||||
</option>
|
</option>
|
||||||
@ -40,9 +40,9 @@
|
|||||||
<div class="fieldset-items">
|
<div class="fieldset-items">
|
||||||
<input type="hidden" name="csrf_token" value="<?= Util::escape_html($_SESSION['csrf_token']) ?>">
|
<input type="hidden" name="csrf_token" value="<?= Util::escape_html($_SESSION['csrf_token']) ?>">
|
||||||
<label for="uploadCssFile">Select File to Upload</label>
|
<label for="uploadCssFile">Select File to Upload</label>
|
||||||
<input type="file"
|
<input type="file"
|
||||||
id="uploadCssFile"
|
id="uploadCssFile"
|
||||||
name="uploadCssFile"
|
name="uploadCssFile"
|
||||||
accept=".css">
|
accept=".css">
|
||||||
<div class="file-info">
|
<div class="file-info">
|
||||||
<strong>File Requirements:</strong><br>
|
<strong>File Requirements:</strong><br>
|
||||||
@ -51,8 +51,8 @@
|
|||||||
• Will be scanned for malicious content
|
• Will be scanned for malicious content
|
||||||
</div>
|
</div>
|
||||||
<label for="description">Description (optional)</label>
|
<label for="description">Description (optional)</label>
|
||||||
<textarea id="description"
|
<textarea id="description"
|
||||||
name="description"
|
name="description"
|
||||||
placeholder="Describe this CSS file..."></textarea>
|
placeholder="Describe this CSS file..."></textarea>
|
||||||
<div></div>
|
<div></div>
|
||||||
<button type="submit" name="action" value="upload">Upload CSS File</button>
|
<button type="submit" name="action" value="upload">Upload CSS File</button>
|
||||||
|
@ -31,9 +31,9 @@
|
|||||||
<div class="fieldset-items">
|
<div class="fieldset-items">
|
||||||
<?php foreach ($emojiList as $emojiItem): ?>
|
<?php foreach ($emojiList as $emojiItem): ?>
|
||||||
<div class="emoji-checkbox-item">
|
<div class="emoji-checkbox-item">
|
||||||
<input type="checkbox"
|
<input type="checkbox"
|
||||||
id="delete_emoji_<?= Util::escape_html($emojiItem['id']) ?>"
|
id="delete_emoji_<?= Util::escape_html($emojiItem['id']) ?>"
|
||||||
name="delete_emoji_ids[]"
|
name="delete_emoji_ids[]"
|
||||||
value="<?= Util::escape_html($emojiItem['id']) ?>">
|
value="<?= Util::escape_html($emojiItem['id']) ?>">
|
||||||
<label for="delete_emoji_<?= Util::escape_html($emojiItem['id']) ?>">
|
<label for="delete_emoji_<?= Util::escape_html($emojiItem['id']) ?>">
|
||||||
<span class="emoji-display"><?= Util::escape_html($emojiItem['emoji']) ?></span>
|
<span class="emoji-display"><?= Util::escape_html($emojiItem['emoji']) ?></span>
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
<input type="hidden" name="csrf_token" value="<?= Util::escape_html($_SESSION['csrf_token']) ?>">
|
<input type="hidden" name="csrf_token" value="<?= Util::escape_html($_SESSION['csrf_token']) ?>">
|
||||||
<textarea name="tick"
|
<textarea name="tick"
|
||||||
placeholder="What's ticking?"
|
placeholder="What's ticking?"
|
||||||
minlength="1"
|
minlength="1"
|
||||||
maxlength="200"
|
maxlength="200"
|
||||||
rows="3"></textarea>
|
rows="3"></textarea>
|
||||||
<button type="submit" class="submit-btn">Tick</button>
|
<button type="submit" class="submit-btn">Tick</button>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user