Files
BattleForge/src/Application/ImageUploadService.php
T
Keith Solomon 61abb93e59 fix: align upload-asset URL contract end-to-end
- ImageUploadService::store() now returns /assets/uploads/<token>/<file>
  so the URL the upload handler emits matches the new GET route.
- public/index.php registers a dedicated GET /assets/uploads/{userToken}/{filename}
  route; the legacy /assets/{kind}/{filename} is kept as a fallback.
- GetAssets reads the upload token from $request->server['__uploads_token']
  (the front controller threads it that way) instead of the cookies bag.
- Adds GetAssets unit tests for the upload-token happy path and a
  token-mismatch 404, plus a FullFlowTest step that uploads and re-fetches
  the asset through the front controller.
2026-07-06 23:21:33 -05:00

39 lines
1.1 KiB
PHP

<?php
declare(strict_types=1);
namespace BattleForge\Application;
final class ImageUploadService
{
public function __construct(
private readonly string $userToken,
private readonly string $uploadsRoot,
) {
}
public function store(string $tempPath, string $declaredMime): string
{
$validated = ImageValidator::validate($tempPath, $declaredMime);
$namespace = $this->uploadsRoot . '/' . $this->userToken;
if (!is_dir($namespace)) {
mkdir($namespace, 0700, true);
}
$hash = bin2hex(random_bytes(16));
$filename = $hash . '.' . $validated->extension;
$destination = $namespace . '/' . $filename;
if (!rename($tempPath, $destination)) {
throw new InvalidImageException("Could not move upload to {$destination}.");
}
// Lock the file down: the namespace is already 0700; tighten the
// file itself to 0600 in case the server's umask is permissive.
chmod($destination, 0600);
return '/assets/uploads/' . $this->userToken . '/' . $filename;
}
}