Move RateLimit cache dir from src/cache/ to storage/cache/rate_limit/

The default cache directory for the file-based rate limiter was
src/cache/rate_limit/, placing transient JSON files inside the source tree.
This meant:
- The directory was deployed via rsync on every deploy (wasted I/O)
- .gitignore had to track a src/-internal path
- Developers running tests could leave stale cache state in the source tree

Changes:
- src/RateLimit.php: default $cacheDir changed from __DIR__.'/cache/rate_limit'
  to dirname(__DIR__).'/storage/cache/rate_limit'; dirname(__DIR__) resolves to
  the project root regardless of how the file is loaded (with or without bootstrap)
- .gitignore: replaced 'src/cache/rate_limit/' with 'storage/cache/' (broader,
  covers any future cache subdirs under storage/)
- storage/cache/.gitkeep: added so the directory is tracked in VCS and created
  on fresh clones/deploys, but its contents are ignored
- justfile: added '--exclude storage/cache/*' to the deploy rsync recipe so
  rate-limit state is never transferred to the server
- src/cache/: removed (no longer needed)

All RateLimit unit tests pass.
This commit is contained in:
Pontoporeia
2026-04-01 16:44:07 +02:00
parent 9108c4069d
commit 8e36f98139
5 changed files with 8 additions and 8 deletions

2
.gitignore vendored
View File

@@ -10,7 +10,7 @@ storage/test.db
### Logs ###
error.log
src/cache/rate_limit/
storage/cache/
# Nix
.direnv/

10
TODO.md
View File

@@ -544,11 +544,11 @@ Goal: rename the tables and column to the canonical M2M pattern (`tags`, `thesis
- [x] Fix `fgetcsv()` deprecation warnings in `import.php` - added explicit `$escape = ''` parameter to all 5 calls
- [x] Run all pending DB migrations (001006) on `storage/posterg.db` - `tags`/`thesis_tags` tables now exist
- [ ] **`RateLimit` uses per-file JSON on disk** - reads, writes, and `glob()`s the filesystem on
every public request. For a low-traffic art-school site this is fine, but it creates a
write-on-every-hit pattern. Consider switching to APCu (if available) or SQLite (single INSERT)
to avoid filesystem churn. At minimum, move the cache dir to `/tmp` or a dedicated
`storage/cache/` path that is excluded from deploy rsync.
- [x] **`RateLimit` cache dir moved to `storage/cache/rate_limit/`** — default path changed from
`src/cache/rate_limit` (inside source tree) to `storage/cache/rate_limit` (via `dirname(__DIR__)`
relative to `src/RateLimit.php`). `.gitignore` updated to ignore `storage/cache/` instead of
the old `src/cache/rate_limit/`. `justfile` deploy rsync now excludes `storage/cache/*`.
Old `src/cache/` directory removed.
- [x] **`__wakeup()` singleton guard throws from a public method** - changed to
`trigger_error('Cannot unserialize singleton ...', E_USER_ERROR)` with explicit `void` return

View File

@@ -41,6 +41,7 @@ deploy:
--exclude '.pi' \
--exclude '.DS_Store' \
--exclude 'storage/backup_*' \
--exclude 'storage/cache/*' \
--exclude 'storage/fixtures' \
--exclude 'storage/docs' \
--exclude 'nginx' \

View File

@@ -18,7 +18,7 @@ class RateLimit {
public function __construct($maxRequests = 30, $timeWindow = 60, $cacheDir = null) {
$this->maxRequests = $maxRequests;
$this->timeWindow = $timeWindow;
$this->cacheDir = $cacheDir ?? __DIR__ . '/cache/rate_limit';
$this->cacheDir = $cacheDir ?? dirname(__DIR__) . '/storage/cache/rate_limit';
// Create cache directory if it doesn't exist
if (!is_dir($this->cacheDir)) {

View File

@@ -1 +0,0 @@
[1775039085]