Files
HeuJung 057e002ad1 feat(core,ecommerce,ckeditor5,board,admin_basic): 공개 자산 직접 URL(CDN) 서빙 옵트인
StorageInterface::url 의 public 하드코딩을 완화하고 core.storage.filter_url 훅을
신설해, 완전 공개 자산(상품·카테고리·리뷰·에디터 이미지)의 직접 URL 서빙을 옵트인으로
열었다. 미설정 시 기존 스트리밍 100% 보존.

디스크 결정은 확장 개별 설정 > 코어 전역 > 미설정 순이며, 서빙·삭제·이동은 행에 기록된
disk 를 따라 전환 전후 자산이 혼재해도 각자 실제 저장 위치를 향한다. 고아 disk(공급
플러그인 비활성화)는 스트리밍으로 폴백해 500 이 되지 않는다.

공개 이슈 (@lyg-kaban 건의) 대응.
2026-08-14 08:05:54 +09:00

71 lines
2.4 KiB
PHP

<?php
namespace App\Extension\Storage\Concerns;
use App\Extension\HookManager;
use Illuminate\Support\Facades\Storage;
/**
* 스토리지 드라이버 공용 공개 URL 해석 trait
*
* public 디스크이거나 `filesystems.disks.{disk}.url` 이 설정된 디스크(S3+CDN 등)면
* 직접 URL 을 생성하고, 그 외에는 null 을 생성합니다. 생성 결과는 디스크 종류와 무관하게
* `core.storage.filter_url` 필터 훅을 항상 통과하므로, 확장이 URL 을 공급/수정/차단할 수 있습니다.
*/
trait ResolvesPublicUrl
{
/**
* 파일의 공개 URL을 반환합니다.
*
* @param string $category 카테고리
* @param string $path 파일 경로 (카테고리 하위 상대 경로)
* @return string|null 파일 URL (직접 URL 불가 디스크이고 훅 공급도 없으면 null)
*/
public function url(string $category, string $path): ?string
{
$fullPath = $this->resolvePath($category, $path);
$url = $this->diskSupportsDirectUrl()
? Storage::disk($this->disk)->url($fullPath)
: null;
$filtered = HookManager::applyFilters('core.storage.filter_url', $url, array_merge(
$this->urlHookContext(),
[
'disk' => $this->disk,
'category' => $category,
'path' => $path,
'full_path' => $fullPath,
]
));
return (is_string($filtered) && trim($filtered) !== '') ? $filtered : null;
}
/**
* 현재 디스크가 직접 URL 생성을 지원하는지 판정합니다.
*
* public 디스크는 항상 지원, 그 외 디스크는 `filesystems.disks.{disk}.url` 이
* 비어 있지 않은 문자열로 설정된 경우에만 지원합니다 (AWS_URL 미설정/빈값 방어).
*
* @return bool 직접 URL 지원 여부
*/
private function diskSupportsDirectUrl(): bool
{
if ($this->disk === 'public') {
return true;
}
$base = config("filesystems.disks.{$this->disk}.url");
return is_string($base) && trim($base) !== '';
}
/**
* `core.storage.filter_url` 훅 컨텍스트의 드라이버별 식별 정보를 반환합니다.
*
* @return array{scope: string, identifier: ?string} scope(core|module|plugin) + 확장 식별자(코어는 null)
*/
abstract protected function urlHookContext(): array;
}