bare-site/README.md

183 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# bare-site
**A zero-dependency PHP micro-framework for content websites. No database. No Composer. No build step. Just files on disk.**
---
## The Story
This framework wasn't built by a developer. It was built by a solutions architect who spent 25 years watching the industry overcomplicate simple things.
In the early 2000s, I was a webmaster. PHP files with inline HTML. It worked. Then the industry decided that every website needed a CMS, a database, an ORM, a build pipeline, and 847 npm dependencies. I watched startups spend $500/month on cloud infrastructure for a 5-page brochure site. I watched enterprise sales demos fail because "composer install" hung during the client meeting.
So I kept doing what worked: a single `index.php` that routes URLs, language files that *are* the content store, and an nginx config that blocks everything except the entry point. For 8 years, this pattern has powered:
- **lohmar.co.uk** — a multi-language company website (7 languages, served from Forgejo)
- **A guesthouse booking site** — with e-commerce via Beds24 iframe integration
- **Enterprise IDV demos** — for Jumio, Keyless Go, and Jaguar Land Rover
- **Multi-brand landing pages** — where the language routing system was repurposed to switch CSS per brand
When JLR's legal team discovered this little framework predated our engagement by years, they were not happy. Previous art. It wasn't theirs.
The philosophy is simple: **you don't need a hammer drill to punch a hole in cardboard. Most websites are cardboard.** Use the right tool.
---
## What It Is
| Feature | Implementation |
|---------|---------------|
| **Router** | 80-line array-driven URL mapper in `start.php` |
| **Templates** | Raw `.phtml` files — HTML with optional inline PHP |
| **Languages** | File-based: `lng/{lang}/menu.php` + `.phtml` per page |
| **Security** | nginx isolates PHP — only `index.php` executes |
| **Bot detection** | 30+ UA patterns + browser heuristic bypass |
| **Rate limiting** | CSV-based velocity tracking, blocks at 5 req/s |
| **Logging** | Structured JSON, weekly rotation (`errors_2026-W26.log`) |
| **Sessions** | httponly, SameSite=Lax, strict_mode, UUIDv4 correlation IDs |
| **Optional** | Geo-location (ipgeolocation.io), Telegram visitor alerts |
## What It's NOT
- A WordPress alternative (no admin panel, no users, no plugins)
- A headless CMS (no content API, no editing interface)
- A Laravel competitor (no ORM, no migrations, no queues, no Artisan)
- A general-purpose framework (no database abstraction, no routing DSL, no middleware)
If you need any of those things, this is the wrong tool. If you have a 5-20 page website that needs to exist in multiple languages and never break, this is exactly the right tool.
---
## Quick Start
### ⚠️ Step 1: Configure your web server (NOT optional)
bare-site's entire security model depends on the web server blocking direct access to PHP files. The framework *will not work* without these rules.
**nginx (recommended)** — copy `nginx/default.conf`:
```nginx
# Only index.php can execute PHP
location = /index.php {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~ \.php$ { return 404; } # ← blocks config.php, functions.php, etc.
# Everything routes through index.php
location / { try_files $uri $uri/ /index.php?$query_string; }
```
**Apache (.htaccess)**:
```apache
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
RewriteCond %{REQUEST_URI} !^/index\.php$
RewriteRule \.php$ - [R=404,L]
```
**Caddy**:
```
your-domain.com {
root * /var/www/html
php_fastcgi unix//run/php/php8.4-fpm.sock
file_server
@blockedPhp path_regexp /(?!index\.php$).*\.php$
respond @blockedPhp 404
}
```
### Step 2: Drop the files
```bash
git clone https://git.lohmar.co.uk/cclohmar/bare-site.git /var/www/html/
```
### Step 3: Edit your config
Open `html/class/config.php` and set:
- `SITE_NAME` — your site title
- `SITE_DESCRIPTION` — meta description
- Page slugs (`PAGE_00_SLUG` through `PAGE_05_SLUG`)
- Supported languages in `$languages` array
- Optional: `GEO_KEY` (ipgeolocation.io), `TELEGRAM_BOT_TOKEN` + `TELEGRAM_CHAT_ID`
### Step 4: Create your pages
```
lng/en/
├── menu.php # navigation labels + error messages
├── home.phtml # your content — raw HTML, no template engine
├── about.phtml # another page
└── ...
```
Content files are plain HTML inside a `<section>`. Use inline PHP if needed: `<?php echo date('Y'); ?>`.
### Step 5: Add a language
```bash
# 1. Add to config.php:
$languages = ['en' => 'English', 'de' => 'Deutsch'];
# 2. Create the directory and copy files:
mkdir lng/de/ && cp lng/en/* lng/de/
# 3. Translate menu.php + .phtml files
# Done — appears in the nav dropdown automatically.
```
---
## Architecture
```
html/
├── index.php # Entry point: session → route
├── class/
│ ├── config.php # Site constants, env detection, API keys, security
│ ├── functions.php # Logging, bot detection, geo-location, rate limiting
│ └── site.php # Session bootstrap, language detection
├── app/
│ ├── controler/
│ │ ├── start.php # URL router (80 lines, 6 slugs, sub-page support)
│ │ └── request.php # POST/GET form handler
│ ├── model/menu.php # Dynamic nav builder from language constants
│ └── view/
│ ├── _header.phtml # HTML head, navbar, Bootstrap CDN
│ ├── _footer.phtml # Footer, JS, debug block
│ └── _error.phtml # HTTP error page renderer (400504)
└── lng/{en,de,fr,...}/
├── menu.php # Language-specific text constants
└── {slug}.phtml # Page content templates
```
---
## Optional Features
| Feature | How to enable |
|---------|--------------|
| **Geo-location** | Set `GEO_KEY` in config.php (free at ipgeolocation.io) |
| **Telegram alerts** | Set `TELEGRAM_BOT_TOKEN` + `TELEGRAM_CHAT_ID` |
| **Weekly logs** | Auto-rotated: `logs/errors_2026-W26.log` |
| **Article sub-pages** | Create `lng/en/{slug}/{article}.phtml` — routed at `/{slug}/{article}` |
| **Multi-language** | Add to `$languages` array, create directory, translate |
---
## Requirements
- PHP 8.1+ (uses `FILTER_SANITIZE_FULL_SPECIAL_CHARS`, named arguments not required)
- nginx, Apache, or Caddy with the isolation rules above
- No database
- No Composer
- No npm
- No build step
## License
MIT — use it, fork it, ship it. If this saves you from deploying WordPress for a 5-page site, we've already won.