kappa 1b319b60c3 refactor: 화이트리스트 기반 파일 검증으로 전환
- 블랙리스트(위험 확장자 차단) → 화이트리스트(허용 타입만 통과)
- 미디어/문서/압축 파일만 허용 (40+ 확장자)
- MIME 타입과 확장자 매핑으로 정확한 검증
- 이미지는 getimagesize()로 추가 검증
- 이중 확장자 탐지 유지 (test.php.jpg 차단)
- 동적 허용 타입 추가 기능 (addAllowedType)

보안 향상: 알려지지 않은 공격 벡터도 자동 차단

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 15:14:53 +09:00

Gnuboard5 Cloudflare R2 Storage Module

그누보드5를 위한 Cloudflare R2 파일 스토리지 모듈입니다.

주요 기능

  • Cloudflare R2 S3 호환 API를 통한 파일 업로드/다운로드
  • 유저별 경로 분리 (users/{member_id}/...)
  • Presigned URL을 통한 보안 다운로드
  • 대용량 파일 멀티파트 업로드 지원 (100MB+)
  • 로컬 스토리지 폴백 지원
  • 기존 파일 R2 마이그레이션 도구

디렉토리 구조

gnuboard-r2-storage/
├── extend/
│   ├── r2_hooks.php              # 그누보드 자동 로드 훅
│   └── r2-storage/
│       ├── composer.json
│       ├── r2_config.php         # R2 설정 파일
│       ├── src/
│       │   ├── R2StorageAdapter.php
│       │   └── R2FileHandler.php
│       └── migrations/
│           ├── 001_add_r2_columns.sql
│           └── 002_rollback.sql
└── README.md

설치 방법

1. Cloudflare R2 설정

  1. Cloudflare Dashboard 접속
  2. R2 Object Storage > Create bucket
  3. 버킷 이름: gnuboard-files (또는 원하는 이름)
  4. Manage R2 API Tokens > Create API token
    • Permissions: Object Read & Write
    • Specify bucket: 생성한 버킷 선택
  5. Access Key ID와 Secret Access Key 저장

2. 모듈 설치

# 그누보드 extend 디렉토리에 복사
cp -r gnuboard-r2-storage/extend/* /path/to/gnuboard/extend/

# Composer 의존성 설치
cd /path/to/gnuboard/extend/r2-storage
composer install

3. 설정 파일 수정

extend/r2-storage/r2_config.php 파일을 열고 R2 인증 정보 입력:

define('R2_ACCOUNT_ID', 'your_account_id');
define('R2_ACCESS_KEY_ID', 'your_access_key');
define('R2_SECRET_ACCESS_KEY', 'your_secret_key');
define('R2_BUCKET_NAME', 'gnuboard-files');

4. 데이터베이스 마이그레이션

# MySQL에서 실행
mysql -u username -p database_name < extend/r2-storage/migrations/001_add_r2_columns.sql

사용 방법

기본 업로드

// 파일 업로드
$result = r2_upload_file($_FILES['bf_file'][0], $bo_table, $member['mb_no']);

if ($result['success']) {
    $r2Key = $result['r2_key'];
    $downloadUrl = $result['url'];
}

다운로드 URL 생성

$downloadUrl = r2_get_download_url($r2Key);

파일 삭제

r2_delete_file($r2Key);

연결 테스트

$test = r2_test_connection();
var_dump($test);

그누보드 통합

write_update.php 수정 예시

// 기존 파일 업로드 코드 전에 추가
if (is_r2_enabled()) {
    $r2Result = r2_before_upload($file, $bo_table, $member['mb_no']);
    if ($r2Result && $r2Result['storage_type'] === 'r2') {
        // R2 업로드 성공 - DB에 r2_key 저장
        $bf_r2_key = $r2Result['r2_key'];
        $bf_storage_type = 'r2';
        // 로컬 move_uploaded_file 스킵
    }
}

get_file() 결과 확장

$files = get_file($bo_table, $wr_id);
$files = r2_extend_files($files);

마이그레이션 도구

기존 로컬 파일을 R2로 마이그레이션:

// 특정 게시판의 파일 100개 마이그레이션
$result = r2_migrate_board_files('free', 100);
print_r($result);
// ['migrated' => 95, 'failed' => 2, 'skipped' => 3, 'errors' => [...]]

저장 경로 구조

bucket/
├── users/{member_id}/
│   ├── board/{bo_table}/{filename}     # 게시판 첨부파일
│   ├── editor/{date}/{filename}        # 에디터 이미지
│   └── profile/{filename}              # 프로필 이미지
└── public/
    └── board/{bo_table}/{filename}     # 비회원 업로드

설정 옵션

상수 기본값 설명
R2_ENABLED true R2 스토리지 활성화
R2_USE_PRESIGNED_URL true Presigned URL 사용
R2_PRESIGNED_EXPIRY 3600 URL 만료 시간 (초)
R2_MULTIPART_THRESHOLD 100MB 멀티파트 업로드 임계값
R2_FALLBACK_TO_LOCAL true R2 실패 시 로컬 저장

요구사항

  • PHP 7.4+
  • Composer
  • AWS SDK for PHP 3.x
  • 그누보드 5.x

라이선스

MIT License

Description
Gnuboard5 Cloudflare R2 Storage Module
Readme MIT 136 KiB
Languages
PHP 100%