mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-06 11:09:18 +02:00
refactor: reorganize to standard PHP structure
- Moved /lib → /src (PHP source code)
- Moved /includes → /public/includes (main site templates)
- Admin section remains self-contained in /public/admin with its own /inc
- Updated all require/include paths across codebase
- Updated config/bootstrap.php, justfile, tests, docs
- All tests passing ✅
Structure now follows PHP best practices:
/config - Configuration files
/database - SQLite database + schema
/docs - Documentation (intact)
/nginx - Server config (intact)
/public - Web-accessible files (entry point)
/admin - Self-contained admin interface
/assets - CSS, fonts, icons
/includes - Main site templates (header/footer)
/scripts - Deployment scripts (intact)
/src - PHP source classes (Database, AdminAuth, RateLimit)
/tests - Test suites
This commit is contained in:
@@ -25,7 +25,7 @@ if (php_sapi_name() === 'cli-server') {
|
||||
|
||||
// Simple helper function for including templates
|
||||
function include_template($name) {
|
||||
$path = APP_ROOT . '/includes/' . $name;
|
||||
$path = APP_ROOT . '/public/includes/' . $name;
|
||||
if (file_exists($path)) {
|
||||
include $path;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ This deploys all files to `/var/www/posterg/`:
|
||||
- `includes/` → `/var/www/posterg/includes/`
|
||||
- `config/` → `/var/www/posterg/config/`
|
||||
- `database/` → `/var/www/posterg/database/`
|
||||
- `lib/` → `/var/www/posterg/lib/`
|
||||
- `src/` → `/var/www/posterg/lib/`
|
||||
|
||||
### 3. Update Nginx Configuration
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ just fixtures
|
||||
### Create a New Page
|
||||
|
||||
1. Create `newpage.php` in root
|
||||
2. Add `require_once __DIR__ . '/lib/Database.php';`
|
||||
2. Add `require_once __DIR__ . '/src/Database.php';`
|
||||
3. Include header: `include 'inc/header.php';`
|
||||
4. Add your content
|
||||
5. Include footer: `include 'inc/footer.php';`
|
||||
@@ -138,7 +138,7 @@ just fixtures
|
||||
Example:
|
||||
```php
|
||||
<?php
|
||||
require_once __DIR__ . '/lib/Database.php';
|
||||
require_once __DIR__ . '/src/Database.php';
|
||||
include 'inc/header.php';
|
||||
?>
|
||||
|
||||
@@ -154,7 +154,7 @@ include 'inc/header.php';
|
||||
|
||||
### Add a Database Function
|
||||
|
||||
1. Edit `lib/Database.php`
|
||||
1. Edit `src/Database.php`
|
||||
2. Add your method to the `Database` class
|
||||
3. Write a test in `tests/Unit/DatabaseTest.php`
|
||||
4. Run tests: `just test-unit`
|
||||
@@ -215,7 +215,7 @@ See `tests/README.md` for complete testing guide.
|
||||
**Quick example:**
|
||||
```php
|
||||
<?php
|
||||
require_once __DIR__ . '/../../lib/Database.php';
|
||||
require_once __DIR__ . '/../../src/Database.php';
|
||||
|
||||
echo "My Test\n";
|
||||
echo "=======\n\n";
|
||||
@@ -243,7 +243,7 @@ just deploy
|
||||
This deploys:
|
||||
- Public site (root PHP files)
|
||||
- Admin panel (`admin/`)
|
||||
- Shared libraries (`lib/`)
|
||||
- Shared libraries (`src/`)
|
||||
|
||||
**Note:** `vendor/` is automatically excluded from deployment.
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ git commit -m "Pre-migration checkpoint"
|
||||
This will:
|
||||
- Move `apps/public/*` to root
|
||||
- Move `apps/admin/` to `admin/`
|
||||
- Rename `shared/` to `lib/`
|
||||
- Rename `shared/` to `src/`
|
||||
- Update all `require` paths automatically
|
||||
- Remove `apps/` directory
|
||||
- Update `.gitignore`
|
||||
@@ -149,9 +149,9 @@ just deploy-admin
|
||||
| `apps/public/assets/` | `assets/` |
|
||||
| `apps/public/inc/` | `inc/` |
|
||||
| `apps/admin/` | `admin/` |
|
||||
| `shared/Database.php` | `lib/Database.php` |
|
||||
| `shared/config.php` | `lib/config.php` |
|
||||
| `shared/cache/` | `lib/cache/` |
|
||||
| `shared/Database.php` | `src/Database.php` |
|
||||
| `shared/config.php` | `src/config.php` |
|
||||
| `shared/cache/` | `src/cache/` |
|
||||
|
||||
### Path Updates
|
||||
|
||||
|
||||
@@ -96,9 +96,9 @@ echo "vendor/" >> .gitignore
|
||||
| `apps/public/inc/header.php` | `inc/header.php` |
|
||||
| `apps/public/assets/posterg.css` | `assets/posterg.css` |
|
||||
| `apps/admin/index.php` | `admin/index.php` |
|
||||
| `shared/Database.php` | `lib/Database.php` |
|
||||
| `shared/config.php` | `lib/config.php` |
|
||||
| `shared/cache/` | `lib/cache/` |
|
||||
| `shared/Database.php` | `src/Database.php` |
|
||||
| `shared/config.php` | `src/config.php` |
|
||||
| `shared/cache/` | `src/cache/` |
|
||||
|
||||
## Deployment Changes
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ and serve files through a dedicated PHP endpoint that validates access rights.
|
||||
|
||||
### 5. Rate Limiter Vulnerable to IP Spoofing
|
||||
|
||||
**File:** `lib/RateLimit.php` — method `getClientIdentifier()`
|
||||
**File:** `src/RateLimit.php` — method `getClientIdentifier()`
|
||||
|
||||
```php
|
||||
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||
@@ -373,7 +373,7 @@ define('DATABASE_PATH', APP_ROOT . '/database/test.db');
|
||||
```
|
||||
|
||||
This constant is never used anywhere. `Database.php` uses `getDatabasePath()` from
|
||||
`lib/config.php`. The duplicate creates confusion about which configuration is
|
||||
`src/config.php`. The duplicate creates confusion about which configuration is
|
||||
authoritative and could lead to future bugs if someone uses the wrong one.
|
||||
|
||||
**Fix:** Remove the `DATABASE_PATH` define from `bootstrap.php`.
|
||||
|
||||
@@ -111,7 +111,7 @@ include APP_ROOT . '/includes/header.php';
|
||||
|---------|-------------|----------------------------|
|
||||
| Purpose | Reusable library | Single website |
|
||||
| Structure | Complex (PSR-4, namespaces) | Simple (includes, classes) |
|
||||
| Directories | `src/`, `resources/`, `var/`, `bin/` | `public/`, `includes/`, `lib/` |
|
||||
| Directories | `src/`, `resources/`, `var/`, `bin/` | `public/`, `includes/`, `src/` |
|
||||
| Autoloading | PSR-4 namespaces | Simple require statements |
|
||||
| Config | Complex bootstrap with many constants | Minimal bootstrap |
|
||||
| Caching | `var/cache/` with framework | Simple file-based if needed |
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
| 1 | No HTTPS — admin credentials exposed in transit | 🔴 CRITICAL | **TLS is terminated upstream by the reverse proxy** (outside nginx). nginx.conf does not need to handle TLS directly. |
|
||||
| 3 | Uploaded files stored inside the webroot | 🟠 HIGH | Storage moved to `STORAGE_ROOT` (`/var/www/posterg/storage/`), defined in `config/bootstrap.php`. `formulaire.php` updated. |
|
||||
| 4 | File path mismatch — media files broken and insecure | 🟠 HIGH | DB paths are now storage-relative (`theses/YEAR/ID/file`, `covers/file`). New controller `public/media.php` serves files safely. `memoire.php` and `search.php` updated to use `/media.php?path=…`. Cover recording in `formulaire.php` fixed (was never inserted into DB). |
|
||||
| 5 | Rate limiter bypassed by IP spoofing (`X-Forwarded-For`) | 🟠 HIGH | `lib/RateLimit.php` `getClientIdentifier()` now uses `REMOTE_ADDR` only. |
|
||||
| 5 | Rate limiter bypassed by IP spoofing (`X-Forwarded-For`) | 🟠 HIGH | `src/RateLimit.php` `getClientIdentifier()` now uses `REMOTE_ADDR` only. |
|
||||
| 6 | `.htaccess` security rules silently ignored by nginx | 🟠 HIGH | All rules ported to `nginx/posterg.conf` (CSP to `/admin/` block, `.log` denial, `autoindex off`). See `nginx/HTACCESS_TO_NGINX.md`. |
|
||||
| 13 | Deprecated `X-XSS-Protection` header | 🔵 LOW | **Removed** from `nginx/posterg.conf`; see `nginx/SECURITY_HEADERS.md` for rationale. |
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
|
||||
| # | Issue | Severity | Resolution |
|
||||
|---|-------|----------|------------|
|
||||
| 2 | No PHP-level authentication in admin panel | 🔴 CRITICAL | `lib/AdminAuth.php` implements a session guard with `password_verify` + `session_regenerate_id`. All admin PHP files now call `AdminAuth::requireLogin()` instead of bare `session_start()`. Credentials stored in gitignored `config/admin_credentials.php` (define `ADMIN_PASSWORD_HASH`). No-op when constant is absent (dev / cli-server). Also resolves item #8 (session cookie hardening via `session_set_cookie_params` before `session_start`). See `nginx/PHP_AUTH_LAYER.md`. |
|
||||
| 2 | No PHP-level authentication in admin panel | 🔴 CRITICAL | `src/AdminAuth.php` implements a session guard with `password_verify` + `session_regenerate_id`. All admin PHP files now call `AdminAuth::requireLogin()` instead of bare `session_start()`. Credentials stored in gitignored `config/admin_credentials.php` (define `ADMIN_PASSWORD_HASH`). No-op when constant is absent (dev / cli-server). Also resolves item #8 (session cookie hardening via `session_set_cookie_params` before `session_start`). See `nginx/PHP_AUTH_LAYER.md`. |
|
||||
| 8 | Session cookies not hardened (`Secure`, `HttpOnly`, `SameSite` missing) | 🟡 MEDIUM | **Resolved as part of item #2.** `AdminAuth::startSession()` sets `HttpOnly=true`, `SameSite=Strict`, `Secure=true` (off on cli-server), `Path=/admin`, `Lifetime=0` before every `session_start()`. |
|
||||
|
||||
---
|
||||
|
||||
6
justfile
6
justfile
@@ -160,7 +160,7 @@ syntax:
|
||||
@echo "======================"
|
||||
@find . -maxdepth 1 -name "*.php" -not -path "./vendor/*" -exec php -l {} \; | grep -v "No syntax errors"
|
||||
@find admin/ -name "*.php" -exec php -l {} \; 2>/dev/null | grep -v "No syntax errors" || true
|
||||
@find lib/ -name "*.php" -exec php -l {} \; | grep -v "No syntax errors"
|
||||
@find src/ -name "*.php" -exec php -l {} \; | grep -v "No syntax errors"
|
||||
@echo "✅ All PHP files have valid syntax"
|
||||
|
||||
# ============================================================================
|
||||
@@ -315,7 +315,7 @@ clean:
|
||||
@echo "🧹 Cleaning up development files..."
|
||||
@rm -f error.log
|
||||
@rm -f admin/error.log
|
||||
@rm -rf lib/cache/rate_limit/*
|
||||
@rm -rf src/cache/rate_limit/*
|
||||
@rm -f /tmp/posterg-*.log
|
||||
@rm -f /tmp/posterg-*.pid
|
||||
@echo "✓ Cleanup complete"
|
||||
@@ -326,7 +326,7 @@ setup-dirs:
|
||||
@mkdir -p admin/data/theses
|
||||
@mkdir -p admin/data/covers
|
||||
@mkdir -p admin/data/yaml
|
||||
@mkdir -p lib/cache/rate_limit
|
||||
@mkdir -p src/cache/rate_limit
|
||||
@touch admin/data/theses/.gitkeep
|
||||
@touch admin/data/covers/.gitkeep
|
||||
@echo "✓ Directories created"
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
[1770319036]
|
||||
@@ -1 +0,0 @@
|
||||
[1770377487]
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
// Load configuration
|
||||
require_once __DIR__ . '/../config/bootstrap.php';
|
||||
require_once APP_ROOT . '/lib/Database.php';
|
||||
require_once APP_ROOT . '/src/Database.php';
|
||||
|
||||
$pageTitle = "Liste des TFE";
|
||||
$page = isset($_GET["page"]) ? intval($_GET["page"]) : 1;
|
||||
@@ -19,7 +19,7 @@ try {
|
||||
$totalPages = 0;
|
||||
}
|
||||
|
||||
include APP_ROOT . '/includes/header.php';
|
||||
include APP_ROOT . '/public/includes/header.php';
|
||||
?>
|
||||
|
||||
<main>
|
||||
@@ -54,4 +54,4 @@ include APP_ROOT . '/includes/header.php';
|
||||
</nav>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php include APP_ROOT . '/includes/footer.php'; ?>
|
||||
<?php include APP_ROOT . '/public/includes/footer.php'; ?>
|
||||
|
||||
@@ -18,8 +18,7 @@ $root = dirname(__DIR__);
|
||||
|
||||
$watchDirs = [
|
||||
$root . '/public',
|
||||
$root . '/includes',
|
||||
$root . '/lib',
|
||||
$root . '/src',
|
||||
$root . '/config',
|
||||
];
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
require_once __DIR__ . '/../config/bootstrap.php';
|
||||
|
||||
// Load required libraries and classes
|
||||
require_once APP_ROOT . '/lib/Database.php';
|
||||
require_once APP_ROOT . '/src/Database.php';
|
||||
|
||||
// Check if an id parameter is provided in the URL
|
||||
if (isset($_GET['id'])) {
|
||||
@@ -29,7 +29,7 @@ if (isset($_GET['id'])) {
|
||||
}
|
||||
|
||||
// Include the header template
|
||||
include APP_ROOT . '/includes/header.php'; ?>
|
||||
include APP_ROOT . '/public/includes/header.php'; ?>
|
||||
<main>
|
||||
<div class="item">
|
||||
<div class="card-content">
|
||||
@@ -151,4 +151,4 @@ include APP_ROOT . '/includes/header.php'; ?>
|
||||
</main>
|
||||
|
||||
<!-- Include the footer template -->
|
||||
<?php include APP_ROOT . '/includes/footer.php'; ?>
|
||||
<?php include APP_ROOT . '/public/includes/footer.php'; ?>
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
// Bootstrap application
|
||||
require_once __DIR__ . '/../config/bootstrap.php';
|
||||
require_once APP_ROOT . '/lib/Database.php';
|
||||
require_once APP_ROOT . '/lib/RateLimit.php';
|
||||
require_once APP_ROOT . '/src/Database.php';
|
||||
require_once APP_ROOT . '/src/RateLimit.php';
|
||||
|
||||
|
||||
// Rate limiting: 30 requests per minute
|
||||
@@ -16,7 +16,7 @@ if (!$rateLimit->check()) {
|
||||
$rateLimit->sendHeaders();
|
||||
|
||||
// Display error page
|
||||
include APP_ROOT . '/includes/header.php';
|
||||
include APP_ROOT . '/public/includes/header.php';
|
||||
echo '<section class="section">';
|
||||
echo ' <div class="container">';
|
||||
echo ' <div class="notification is-danger">';
|
||||
@@ -26,7 +26,7 @@ if (!$rateLimit->check()) {
|
||||
echo ' </div>';
|
||||
echo ' </div>';
|
||||
echo '</section>';
|
||||
include APP_ROOT . '/includes/footer.php';
|
||||
include APP_ROOT . '/public/includes/footer.php';
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ try {
|
||||
$languages = [];
|
||||
}
|
||||
|
||||
include APP_ROOT . '/includes/header.php'; ?>
|
||||
include APP_ROOT . '/public/includes/header.php'; ?>
|
||||
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
@@ -415,4 +415,4 @@ include APP_ROOT . '/includes/header.php'; ?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php include APP_ROOT . '/includes/footer.php'; ?>
|
||||
<?php include APP_ROOT . '/public/includes/footer.php'; ?>
|
||||
|
||||
1
src/cache/rate_limit/ad921d60486366258809553a3db49a4a.json
vendored
Normal file
1
src/cache/rate_limit/ad921d60486366258809553a3db49a4a.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[1770894664]
|
||||
@@ -4,7 +4,7 @@
|
||||
* Tests search queries and results
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../../lib/Database.php';
|
||||
require_once __DIR__ . '/../../src/Database.php';
|
||||
|
||||
echo "Search Functionality Test\n";
|
||||
echo "=========================\n\n";
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Tests SQL injection protection and input sanitization
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../../lib/Database.php';
|
||||
require_once __DIR__ . '/../../src/Database.php';
|
||||
|
||||
echo "Security Test Suite\n";
|
||||
echo "===================\n\n";
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Tests basic database connectivity and query functionality
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../../lib/Database.php';
|
||||
require_once __DIR__ . '/../../src/Database.php';
|
||||
|
||||
echo "Database Connection Test\n";
|
||||
echo "========================\n\n";
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Tests rate limiting functionality
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../../lib/RateLimit.php';
|
||||
require_once __DIR__ . '/../../src/RateLimit.php';
|
||||
|
||||
echo "Rate Limit Test\n";
|
||||
echo "===============\n\n";
|
||||
|
||||
Reference in New Issue
Block a user