꿈을 바구니에 담아 간직하다 보면!!

지금 참 힘들죠? 근데 내일은 지금보다 덜 힘들거예요

힘든 건 오늘만이 아니다. 내일도, 그리고 그 다음 날도 계속될 것이다.

PHP Tip

오버레이가 있는 반응형 이미지 갤러리(그누보드)

duaidot 2025. 12. 17. 07:22

<?php
include_once('./_common.php');              // GnuBoard 공통 초기화 파일을 로드해 DB, 상수(G5_*) 등을 사용할 수 있게 함

$bo_table = "ham_25";                       // 사용할 게시판 테이블명(보드 아이디)을 지정

$write_table = $g5['write_prefix'] . $bo_table; // 실제 DB 글 테이블 이름(예: g5_write_ham_25)을 조합

$page = isset($_GET['page']) ? (int)$_GET['page'] : 1; // GET으로 받은 page 파라미터를 정수로 캐스팅, 없으면 1로 기본값 설정
$rows = 50;                                 // 한 번에 가져올 글 개수(최신 50개)

$sql = "SELECT wr_id, wr_subject, wr_content
        FROM $write_table
        ORDER BY wr_datetime DESC
        LIMIT $rows";                        // 최신 작성일 기준으로 wr_id/제목/본문을 50개까지 조회하는 SQL
$result = sql_query($sql);                   // GnuBoard의 sql_query로 실행해 결과 핸들을 얻음
?>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/SmartPhoto/1.0.1/css/smartphoto.min.css" /> <!-- SmartPhoto 라이트박스용 CSS 로드 -->

<style>
.ham25-gallery {
  column-count: 4;       /* 기본 4칸의 CSS 멀티컬럼 레이아웃 */
  column-gap: 12px;      /* 칼럼 사이 간격 12px */
}

.ham25-item {
  display: inline-block; /* 멀티컬럼에서 줄바꿈 단위로 동작하기 위해 inline-block 사용 */
  margin-bottom: 12px;   /* 아이템 간 아래쪽 여백 */
  width: 100%;           /* 칼럼 너비에 맞춰 가로폭 100% */
}

.ham25-thumb-wrap {
  position: relative;    /* 제목 오버레이를 이미지 위에 겹치기 위한 기준 컨테이너 */
  overflow: hidden;      /* 내부 요소가 경계 밖으로 넘치지 않도록 잘라냄 */
  border-radius: 6px;    /* 모서리 둥글게 */
  border: 1px solid #eee;/* 옅은 테두리 */
  background: #fafafa;   /* 밝은 배경색(이미지 로딩 중에도 보임) */
}

.ham25-thumb-wrap img {
  width: 100%;           /* 컨테이너 너비에 맞게 이미지 확대/축소 */
  height: auto;          /* 원본 비율 유지 */
  display: block;        /* 이미지 하단 빈 공간 제거 */
  border-radius: 6px;    /* 컨테이너와 동일한 둥근 모서리 */
}

/* 제목 오버레이 */
.ham25-title {
  position: absolute;    /* 부모(.ham25-thumb-wrap)를 기준으로 절대 위치 */
  bottom: 0;             /* 아래쪽에 붙여 표시 */
  left: 0;               /* 왼쪽 기준 */
  width: 100%;           /* 가로 전체 덮기 */
  padding: 6px;          /* 안쪽 여백 */
  background: rgba(0,0,0,0.5); /* 반투명 검정 배경으로 이미지 위에 텍스트 가독성 확보 */
  color: #fff;           /* 흰색 글자 */
  text-align: center;    /* 중앙 정렬 */
  font-size: 1.2vw;      /* 뷰포트 폭 기반 폰트 크기(반응형) */
  line-height: 1.3;      /* 줄간격 약간 넓게 */
  word-break: break-word;/* 긴 단어나 연속 문자도 줄바꿈 가능하게 */
}

/* 반응형 칸 수 조정 */
@media (max-width: 1200px) {
  .ham25-gallery { column-count: 3; } /* 너비 1200px 이하: 3칸 */
}
@media (max-width: 768px) {
  .ham25-gallery { column-count: 2; } /* 너비 768px 이하: 2칸 */
}
@media (max-width: 480px) {
  .ham25-gallery { column-count: 1; } /* 너비 480px 이하: 1칸 */
  .ham25-title { font-size: 3vw; }    /* 작은 화면에서는 제목 폰트 조금 더 크게 */
}

.ham25-empty {
  width: 100%;            /* 가로 전체 사용 */
  text-align: center;     /* 텍스트 중앙 정렬 */
  color: #777;            /* 중간 톤 글자색 */
}
</style>

<div class="ham25-gallery">                 <!-- 갤러리 컨테이너: 멀티컬럼 적용 영역 -->
<?php
$i = 0;                                     // 출력된 아이템 수를 카운트할 변수 초기화
while ($row = sql_fetch_array($result)) {   // SQL 결과를 한 행씩 연관배열로 가져오는 루프 시작
    $i++;                                   // 한 행 처리 시 카운터 증가
    preg_match_all('/<img[^>]*src=["\']?([^>"\']+)["\']?[^>]*>/i', $row['wr_content'], $img_no);
                                            // 본문 HTML에서 <img ... src="..."> 패턴을 정규식으로 모두 추출
    $img_src = isset($img_no[1][0]) ? $img_no[1][0] : '';
                                            // 첫 번째 이미지의 src URL만 사용, 없으면 빈 문자열
    $href = G5_BBS_URL.'/board.php?bo_table='.$bo_table.'&wr_id='.$row['wr_id'];
                                            // 개별 글 상세 페이지 URL(현재 코드에서는 미사용이지만 참고용으로 생성)
?>
    <?php if ($img_src) { ?>                <!-- 이미지가 발견된 행만 출력 -->
    <a href="<?php echo $img_src; ?>" class="js-smartPhoto ham25-item" data-caption="<?php echo htmlspecialchars($row['wr_subject']); ?>" data-group="ham25">
                                            <!-- SmartPhoto 라이트박스 트리거: 링크 href에 원본 이미지, 캡션에 제목, 그룹 지정 -->
        <div class="ham25-thumb-wrap">      <!-- 이미지+오버레이를 감싸는 카드 컨테이너 -->
            <img src="<?php echo $img_src; ?>" alt="<?php echo htmlspecialchars($row['wr_subject']); ?>">
                                            <!-- 썸네일로 같은 이미지 사용, alt에는 제목을 HTML 이스케이프 적용 -->
            <div class="ham25-title">       <!-- 하단 오버레이 제목 영역 -->
                <?php echo cut_str($row['wr_subject'], 40); ?>
                                            <!-- 제목을 최대 40자까지 잘라 넘치는 부분을 방지(GnuBoard 유틸 함수) -->
            </div>
        </div>
    </a>
    <?php } ?>                              <!-- if 블록 종료 -->
<?php
}                                           // while 루프 종료
if ($i == 0) {                              // 루프에서 아무 아이템도 출력되지 않은 경우(이미지 없는 글만 있었거나 글이 없음)
    echo '<p class="ham25-empty">이미지가 없습니다.</p>'; // 빈 상태 메시지 출력
}
?>
</div>                                      <!-- 갤러리 컨테이너 종료 -->