placeholderDir = sys_get_temp_dir() . '/bf-placeholders-' . bin2hex(random_bytes(4)); mkdir($this->placeholderDir, 0755, true); // 1x1 red PNG $png = base64_decode( 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==', true, ); file_put_contents($this->placeholderDir . '/defender.png', $png); $this->uploadsDir = sys_get_temp_dir() . '/bf-assets-' . bin2hex(random_bytes(4)); mkdir($this->uploadsDir, 0700, true); } protected function tearDown(): void { if (is_dir($this->uploadsDir)) { foreach (glob($this->uploadsDir . '/*/*') as $file) { unlink($file); } foreach (glob($this->uploadsDir . '/*') as $dir) { rmdir($dir); } rmdir($this->uploadsDir); } if (is_dir($this->placeholderDir)) { foreach (glob($this->placeholderDir . '/*') as $file) { unlink($file); } rmdir($this->placeholderDir); } } public function testItServesAPlaceholderImageWithoutAuth(): void { $handler = new GetAssets($this->placeholderDir, $this->uploadsDir); $request = new Request([], [], [], [], [], '', 'GET', '/assets/placeholders/defender.png', null, ''); $response = $handler->handle($request, ['kind' => 'placeholders', 'filename' => 'defender.png']); self::assertSame(200, $response->status); self::assertSame('image/png', $response->headers['Content-Type'] ?? ''); self::assertGreaterThan(0, strlen($response->body)); } public function testItReturns404ForAMissingFile(): void { $handler = new GetAssets($this->placeholderDir, $this->uploadsDir); $request = new Request([], [], [], [], [], '', 'GET', '/assets/placeholders/missing.png', null, ''); $response = $handler->handle($request, ['kind' => 'placeholders', 'filename' => 'missing.png']); self::assertSame(404, $response->status); } public function testItServesAnUploadedAssetWhenTheServerTokenMatches(): void { $userToken = str_repeat('a', 64); $namespace = $this->uploadsDir . '/' . $userToken; mkdir($namespace, 0700, true); $payload = base64_decode( 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==', true, ); file_put_contents($namespace . '/demo.png', $payload); $handler = new GetAssets($this->placeholderDir, $this->uploadsDir); $request = new Request( [], [], [], [], ['__uploads_token' => $userToken], '', 'GET', '/assets/uploads/' . $userToken . '/demo.png', null, '', ); $response = $handler->handle( $request, ['kind' => 'uploads', 'userToken' => $userToken, 'filename' => 'demo.png'], ); self::assertSame(200, $response->status); self::assertSame('image/png', $response->headers['Content-Type'] ?? ''); self::assertSame($payload, $response->body); } public function testItRefusesAnUploadedAssetWhenTheServerTokenDiffers(): void { $handler = new GetAssets($this->placeholderDir, $this->uploadsDir); $request = new Request( [], [], [], [], ['__uploads_token' => str_repeat('a', 64)], '', 'GET', '/assets/uploads/abc/def.png', null, '', ); $response = $handler->handle( $request, ['kind' => 'uploads', 'userToken' => str_repeat('b', 64), 'filename' => 'def.png'], ); self::assertSame(404, $response->status); } }