회원가입 | 고객센터 |
DESIGNONEX
디자인원엑스
About
Service
Q&A
PR리그
자유게시판N
갤러리
포인트게임
공지사항N
통계
로그인 회원가입
고객센터
3.6 데이터 처리 구조

공통 함수 활용

A Administrator
2026.04.21 00:58(수정됨) 98 0

1. 공통함수 라이브러리 개요


1.1 파일 위치 및 역할

core/functions.php는 DXCMS 프레임워크 전체에서 공통으로 사용되는 순수 함수(Pure Function)들의 집합입니다.
이 파일은 HookManager, PluginRegistry, Database 클래스보다 먼저 로드되며, 클래스 인스턴스를 생성하지 않고 함수 정의만 담습니다. PHP 5.6부터 최신 PHP까지, Windows•Linux•IIS•Apache•Nginx, HTTP•HTTPS 환경을 완전히 지원합니다.

📌 로드 순서 원칙
core/functions.php 는 index.php 부팅 가장 초기에 로드됩니다.
이 파일 안에서는 Database::getInstance(), Auth::getInstance() 등 클래스 인스턴스를 직접 호출하지 않습니다.
단, dx_board_posts() 처럼 내부적으로 Database를 사용하는 함수는 반드시 클래스 로드 이후에 호출하세요.


1.2 함수 카테고리 전체 구조

카테고리 주요 함수 설명
보안 난수 dx_random_bytes(),
dx_random_hex()
PHP 버전별 자동 폴백 보안 난수 생성
경로 유틸 dx_realpath(),
dx_path_inside()
크로스 플랫폼 파일 경로 처리
HTTPS 감지 dx_is_https() 프록시•CDN 환경 포함 HTTPS 정확 감지
URL 생성 dx_base_url(),
dx_static_url()
서브디렉토리•URL Rewrite 자동 처리
요청 처리 dx_get(),
dx_post(),
dx_request()
타입 캐스팅 포함 안전 입력 처리
IP / UA dx_ip(),
dx_device(),
dx_os()
Cloudflare 포함 실제 IP•디바이스 감지
설정 관리 dx_config(),
dx_set_config()
전역 설정값 읽기/쓰기
보안 dx_esc(),
dx_safe_url(),
dx_csrf_*()
XSS 방어•CSRF 토큰 처리
응답 dx_error(),
dx_json()
HTTP 오류•JSON API 응답
플래시 메시지 dx_flash(),
dx_get_flash()
세션 기반 일회성 메시지
문자열 dx_substr(),
dx_time_ago()
UTF-8 안전 문자열•상대 시간
날짜 dx_date() 날짜 포맷 통일
파일 업로드 dx_upload_url(),
dx_upload_exists()
업로드 URL/존재 여부 확인
페이지네이션 dx_pagination() HTML 페이지 버튼 자동 생성
게시판 헬퍼 dx_board_posts(),
dx_board_latest()
홈/위젯에서 게시글 출력
에셋 출력 dx_head_assets(),
dx_font_css()
폰트•아이콘 CDN 자동 삽입
로그 dx_log() 에러/경고 파일 로그 기록
플러그인 load_plugins() 플러그인 자동 로드


2. 보안 난수 생성


2.1 dx_random_bytes($length)

PHP 버전과 서버 환경에 따라 가장 안전한 방법을 자동으로 선택하여 보안 난수 바이트를 반환합니다.
 
// PHP 7.0+ → random_bytes() 사용 (가장 안전)
// PHP 5.x + OpenSSL → openssl_random_pseudo_bytes()
// PHP 5.x + mcrypt → mcrypt_create_iv()
// 최후 폴백 → mt_rand() (저가형 호스팅 대응)

$bytes = dx_random_bytes(16);   // 16바이트 보안 난수 반환


2.2 dx_random_hex($length = 32)

보안 난수를 16진수 문자열로 반환합니다. CSRF 토큰, 세션키, 임시 비밀번호 생성에 사용합니다.
 
$token   = dx_random_hex(32);  // 32자리 16진수 토큰 생성
$tempPwd = dx_random_hex(16);  // 16자리 임시 비밀번호

// 내부적으로 dx_random_bytes((int)ceil($length/2))를 호출 후 bin2hex() 적용


3. 경로 및 URL 처리


3.1 경로 유틸리티

dx_realpath($path)

Windows 백슬래시를 슬래시로 정규화한 실제 절대 경로를 반환합니다. realpath() 실패 시 false를 반환합니다.
 
$real = dx_realpath('../data/uploads');
// 결과: '/var/www/html/data/uploads'  (\를 /로 자동 변환)


dx_path_inside($path, $base)

$path가 $base 디렉토리 내부에 있는지 확인합니다. 경로 탈출(Path Traversal) 공격 방어에 사용합니다.
 
$base = DX_DATA . '/uploads';
$file = dx_realpath($userInput);

if (!dx_path_inside($file, $base)) {
    dx_error('허용되지 않은 경로입니다.', 403);
}
// Windows 환경: 대소문자 구분 없이 stripos() 사용 (자동 처리)


3.2 HTTPS 감지

dx_is_https()

Cloudflare, AWS ALB, nginx 리버스 프록시 등 다양한 환경에서 정확하게 HTTPS를 감지합니다.
 
// 다음 헤더를 순서대로 확인:
// 1. $_SERVER['HTTPS']
// 2. HTTP_X_FORWARDED_PROTO (nginx 프록시)
// 3. HTTP_X_FORWARDED_SSL
// 4. HTTP_FRONT_END_HTTPS
// 5. SERVER_PORT === 443

if (dx_is_https()) {
    // SSL 환경에서만 실행할 코드
}


3.3 URL 생성 함수

dx_base_url($path = '')

사이트 절대 URL을 생성합니다. 내부적으로 _dx_resolve_base() 헬퍼를 통해 site_url 설정값을 확인하고, 도메인 불일치 시 자동 감지 모드로 전환합니다. 이중 슬래시(//)를 자동 제거하며 URL Rewrite 미적용 환경(IIS 등)도 지원합니다.
 
echo dx_base_url();                    // https://example.com/
echo dx_base_url('board/notice');      // https://example.com/board/notice
echo dx_base_url('admin/settings');    // https://example.com/admin/settings

// URL Rewrite 비활성화 환경 (dx_config('url_rewrite') === '0')
echo dx_base_url('board/notice');
// https://example.com/index.php?_url=/board/notice


dx_static_url($path = '')

CSS, JS, 이미지 등 정적 자산의 URL을 생성합니다. dx_base_url()과 동일한 베이스를 사용하되, URL Rewrite 영향을 받지 않습니다.
 
echo dx_static_url('assets/css/dx.css');
// https://example.com/assets/css/dx.css

echo dx_static_url('assets/js/dx.js');
// https://example.com/assets/js/dx.js


dx_request_uri() / dx_current_url()

// REQUEST_URI의 이중 슬래시(//) 정규화
$uri = dx_request_uri();       // '/board/notice/1'

// 현재 페이지 완전 URL 반환
$url = dx_current_url();
// 'https://example.com/board/notice/1?page=2'


dx_redirect($url, $code = 302) / dx_redirect_back($fallback = '/')

// 지정 URL로 리다이렉트 (기본 302)
dx_redirect(dx_base_url('member/login'));
dx_redirect(dx_base_url('board/notice'), 301);  // 영구 이동

// 이전 페이지로 돌아가기 (HTTP_REFERER 없으면 fallback)
dx_redirect_back('/board/notice');


4. 요청 데이터 처리


4.1 안전 입력 수신 함수

GET/POST/REQUEST 데이터를 수신할 때 반드시 dx_get() • dx_post() • dx_request() 를 사용합니다. 세 함수 모두 내부적으로 dx_cast() 를 거쳐 타입 변환 및 trim을 적용합니다.
 

함수 시그니처

dx_get($key, $default='', $type='string')
dx_post($key, $default='', $type='string')
dx_request($key, $default='', $type='string')


$type 파라미터 종류

$type 값 변환 방식 사용 예시
string (기본) trim() 처리된 문자열 dx_get('keyword')
int (int) 캐스팅 dx_get('page', 1, 'int')
float (float) 캐스팅 dx_post('price', 0.0, 'float')
bool (bool) 캐스팅 dx_post('agree', false, 'bool')
array (array) 캐스팅 dx_post('ids', [], 'array')
bigint 32bit PHP 오버플로우 방지 정수 문자열 dx_post('post_id', '0', 'bigint')


실전 사용 예

// 게시판 목록 파라미터
$page    = dx_get('page', 1, 'int');       // GET page, 기본값 1, 정수 변환
$keyword = dx_get('keyword', '');          // GET keyword, 기본값 빈문자열
$catId   = dx_get('cat', 0, 'int');        // GET cat, 기본값 0

// 게시글 작성 POST 데이터
$title   = dx_post('title');                // POST title, string+trim
$content = dx_post('content');              // POST content
$postId  = dx_post('post_id', '0', 'bigint'); // 큰 ID 안전 처리

// HTTP 메서드 확인
if (dx_method('POST')) {
    // POST 요청 처리
}


4.2 dx_cast($val, $type)

dx_cast()는 dx_get/post/request 내부에서 호출되지만, 직접 사용할 수도 있습니다.
$raw  = '  123  ';
$num  = dx_cast($raw, 'int');     // → 123
$str  = dx_cast($raw, 'string'); // → '123' (trim 적용)
$big  = dx_cast('9999999999', 'bigint'); // 32bit PHP에서도 안전한 정수 문자열


5. IP 주소 및 디바이스 감지


5.1 dx_ip()

Cloudflare(CF-Connecting-IP), X-Real-IP, X-Forwarded-For 등 프록시 헤더를 순서대로 확인하여 실제 클라이언트 IP를 반환합니다.
 
// 확인 우선순위:
// 1. HTTP_CF_CONNECTING_IP  (Cloudflare)
// 2. HTTP_X_REAL_IP         (nginx)
// 3. HTTP_X_FORWARDED_FOR   (일반 프록시)
// 4. HTTP_CLIENT_IP
// 5. REMOTE_ADDR            (직접 연결)

$ip = dx_ip();   // '203.0.113.45'

// 활용: 접속 로그 기록
$db->query(
    "INSERT INTO `{$db->table('access_log')}` (ip, created_at) VALUES (?, NOW())",
    [dx_ip()]
);


5.2 디바이스•OS•브라우저 감지

// 디바이스 타입: 'mobile' | 'tablet' | 'pc'
$device = dx_device();

// OS 정보: 'Windows 10/11', 'Android 13', 'iOS 17.0' 등
$os = dx_os();

// 브라우저: 'Chrome 124', 'Firefox 125', 'Edge', 'Safari' 등
$browser = dx_browser();

// 활용: 모바일 전용 레이아웃 분기
if (dx_device() === 'mobile') {
    include $skinDir . '/mobile/list.php';
} else {
    include $skinDir . '/list.php';
}

// 활용: 회원 접속 통계 저장
$db->query(
    "INSERT INTO `{$db->table('member_access')}` (member_id, device, os, browser, ip)
     VALUES (?, ?, ?, ?, ?)",
    [$memberId, dx_device(), dx_os(), dx_browser(), dx_ip()]
);


6. 설정 관리


6.1 dx_config($key, $default = '')

config.php 가 로드한 전역 $dx_config 배열에서 설정값을 읽습니다. 키가 없으면 $default를 반환합니다.
 
// 기본 읽기
$siteName = dx_config('site_name', 'DXCMS');
$adminMail = dx_config('admin_email');
$siteUrl   = dx_config('site_url', '');

// 활용: 기능 on/off 플래그 확인
if (dx_config('use_sms') === '1') {
    // SMS 기능 사용 중
}

// 활용: URL Rewrite 여부 확인
if (dx_config('url_rewrite', '1') === '0') {
    // index.php?_url= 방식 사용
}


6.2 dx_set_config($key, $value) / dx_config_set()

런타임에 설정값을 동적으로 변경합니다. dx_config_set()은 dx_set_config()의 별칭입니다.
 
// 런타임 설정 변경 (DB에는 저장되지 않음, 현재 요청에서만 유효)
dx_set_config('site_name', '테스트 사이트');
dx_config_set('debug_mode', '1');

// 플러그인에서 임시 설정 주입
dx_set_config('theme', 'dark');


7. 보안 관련 함수


7.1 dx_esc($str) — XSS 방어 출력

HTML 특수문자를 엔티티로 변환합니다. 모든 사용자 입력값은 반드시 이 함수를 거쳐 출력하세요. htmlspecialchars(ENT_QUOTES, 'UTF-8') 의 래퍼입니다.
 
// 잘못된 출력 (XSS 취약)
echo $_GET['name'];                    // 위험!

// 올바른 출력
echo dx_esc($_GET['name']);             // 안전

// 게시글 제목 출력
echo dx_esc($row['title']);

// input value 출력
echo '<input type="text" value="' . dx_esc($value) . '">';


7.2 dx_safe_url($url) — URL XSS 방어

blocked:, blocked:, data: 프로토콜을 차단하고 안전한 URL을 반환합니다. 메뉴•링크 href 출력에 사용합니다. 상대경로(/path) 는 자동으로 dx_base_url()로 변환됩니다.
 
echo dx_safe_url($menu['url']);              // 메뉴 링크 안전 출력

// 위험 URL 처리
echo dx_safe_url('blocked:alert(1)');     // → '#'  (차단)
echo dx_safe_url('data:text/html,<h1>');     // → '#'  (차단)

// 상대경로 자동 변환
echo dx_safe_url('/board/notice');
// → 'https://example.com/board/notice'

// 링크 태그 사용 예
echo '<a href="' . dx_safe_url($link) . '">' . dx_esc($label) . '</a>';


7.3 CSRF 보호 함수

내부적으로 Secure 클래스에 위임합니다. Secure 미로드 환경에서는 세션 기반 폴백으로 동작합니다.
 
// 1) 폼에 CSRF 토큰 필드 삽입
echo dx_csrf_field();
// → <input type="hidden" name="_csrf" value="abc123...">

// 2) 토큰 값만 가져오기 (Ajax 요청 헤더 등에 사용)
$token = dx_csrf_token();

// 3) POST 처리 시 검증 (실패 시 403 반환 후 exit)
dx_csrf_check();

// 폼 전체 예시
// <form method="POST" action="...">
//   <?php echo dx_csrf_field(); ?>
//   ...
// </form>

// POST 핸들러 예시
// dx_csrf_check();  // 반드시 첫 줄에 호출
// $title = dx_post('title');
// ...

⚠️ CSRF 보호 필수 적용
POST 요청을 처리하는 모든 핸들러 파일(게시글 작성/수정/삭제, 회원정보 변경 등) 상단에 반드시 dx_csrf_check()를 호출하세요.
AJAX 요청의 경우 요청 헤더에 X-CSRF-Token: <?php echo dx_csrf_token(); ?> 를 포함시켜야 합니다.


8. 응답 처리 함수


8.1 dx_error($msg, $code = 500)

HTTP 상태코드를 설정하고 오류 화면을 출력한 후 종료합니다. DX_DEBUG 상수가 true면 상세 오류 메시지를, false면 사용자 친화적 메시지를 출력합니다.
 
// 403 접근 거부
dx_error('권한이 없습니다.', 403);

// 404 not found
dx_error('페이지를 찾을 수 없습니다.', 404);

// 500 서버 오류 (기본)
dx_error('오류가 발생했습니다.');

// 권한 체크 패턴
if (!Auth::getInstance()->isLoggedIn()) {
    dx_redirect(dx_base_url('member/login'));
}
if ($post['member_id'] !== $loginUser['id']) {
    dx_error('본인 게시글만 수정할 수 있습니다.', 403);
}


8.2 dx_json($data, $code = 200) — API/Ajax 응답

Content-Type: application/json; charset=utf-8 헤더를 설정하고 데이터를 JSON으로 출력 후 종료합니다. 한글 등 유니코드를 이스케이프 없이 출력합니다.
 
// 성공 응답
dx_json(['success' => true, 'message' => '저장되었습니다.']);

// 데이터 포함 응답
dx_json([
    'success' => true,
    'data'    => ['id' => $postId, 'title' => $title],
]);

// 실패 응답 (422 Unprocessable Entity)
dx_json(['success' => false, 'message' => '제목을 입력하세요.'], 422);

// 인증 실패 (401)
if (!Auth::getInstance()->isLoggedIn()) {
    dx_json(['success' => false, 'message' => '로그인이 필요합니다.'], 401);
}


8.3 플래시 메시지 함수

세션에 일회성 메시지를 저장하고, 다음 페이지 로드 시 꺼내어 사용합니다. 리다이렉트 후 알림 표시에 활용합니다.
 
// 메시지 저장 (리다이렉트 전)
dx_flash('게시글이 저장되었습니다.', 'success');
dx_flash('삭제되었습니다.', 'warning');
dx_flash('오류가 발생했습니다.', 'error');

// dx_set_flash()는 dx_flash()의 동일한 기능 (별칭)
dx_set_flash('처리되었습니다.', 'success');

// 메시지 읽기 (읽으면 세션에서 자동 삭제)
$flash = dx_get_flash();
if ($flash) {
    echo '<div class="alert alert-' . dx_esc($flash['type']) . '">';
    echo dx_esc($flash['message']);
    echo '</div>';
}


9. 문자열•날짜•파일 유틸리티


9.1 문자열 처리

dx_substr($str, $length, $suffix = '...')

UTF-8 한글을 안전하게 지정 길이로 자르고 말줄임 문자를 붙입니다. mb_string 미설치 환경도 지원합니다.
 
$title   = '안녕하세요 반갑습니다 DXCMS 입니다';
$short   = dx_substr($title, 10);          // '안녕하세요 반갑습니다...'
$custom  = dx_substr($title, 10, ' [더보기]');  // 커스텀 suffix

// 게시판 목록 제목 자르기
echo dx_esc(dx_substr($row['title'], 30));


dx_time_ago($datetime)

DB에 저장된 datetime 문자열을 "방금 전", "5분 전", "3시간 전", "2일 전" 형태로 반환합니다.
 
echo dx_time_ago($row['created_at']);
// 결과 예: '방금 전'  |  '15분 전'  |  '3시간 전'  |  '2일 전'  |  '04/15'

// 기준: 7일 미만이면 상대시간, 이상이면 'm/d' 형식 날짜 반환


dx_array_column($arr, $columnKey, $indexKey = null)

PHP 5.4 이하 환경에서도 array_column() 기능을 사용할 수 있는 폴백 함수입니다.
 
$posts   = $db->rows("SELECT id, title FROM `{$db->table('posts')}`");
$titles  = dx_array_column($posts, 'title');         // 제목 배열 추출
$indexed = dx_array_column($posts, 'title', 'id');   // id를 키로 사용


9.2 날짜 처리

dx_date($datetime, $format = 'Y-m-d')

timestamp 또는 날짜 문자열을 지정 포맷으로 반환합니다. 유효하지 않은 값이면 빈 문자열을 반환합니다.
 
echo dx_date($row['created_at']);              // '2025-04-24'
echo dx_date($row['created_at'], 'Y년 m월 d일'); // '2025년 04월 24일'
echo dx_date($row['created_at'], 'Y-m-d H:i'); // '2025-04-24 14:30'

// timestamp도 처리 가능
echo dx_date(time(), 'H:i:s');                // '14:30:45'

// null/빈값은 빈 문자열 반환
echo dx_date(null);   // ''
echo dx_date('');     // ''


9.3 파일 크기 및 업로드

dx_filesize($bytes)

echo dx_filesize(512);         // '512B'
echo dx_filesize(2048);        // '2KB'
echo dx_filesize(1536000);     // '1.5MB'
echo dx_filesize(2147483648);  // '2GB'


dx_upload_url($path) / dx_upload_exists($path)

// 업로드 파일 URL 생성
echo dx_upload_url('2025/04/image.jpg');
// 'https://example.com/data/uploads/2025/04/image.jpg'

// 업로드 파일 존재 확인
if (dx_upload_exists('2025/04/image.jpg')) {
    echo '<img src="' . dx_upload_url('2025/04/image.jpg') . '">';
}


10. 페이지네이션


10.1 dx_pagination($total, $perPage, $current, $urlPattern, $range = 5)

전체 데이터 수, 페이지당 수, 현재 페이지, URL 패턴을 받아 HTML 페이지 버튼 문자열을 반환합니다.
 
파라미터 타입 설명
$total int 전체 데이터 수
$perPage int 페이지당 표시 수
$current int 현재 페이지 번호 (1부터 시작)
$urlPattern string {page} 플레이스홀더를 포함한 URL 패턴
$range int 표시할 페이지 버튼 수 (기본 5)
 
$total   = 253;   // 전체 게시글 수
$perPage = 20;    // 페이지당 20개
$page    = dx_get('page', 1, 'int');

// {page} 가 페이지 번호로 치환됨
$pager = dx_pagination(
    $total,
    $perPage,
    $page,
    dx_base_url('board/notice?page={page}'),
    5   // 페이지 버튼 5개 표시
);

echo '<div class="dx-pagination">' . $pager . '</div>';

// 출력 결과 HTML 예시:
// <a href="...?page=2" class="dx-page-btn">‹</a>
// <a href="...?page=1" class="dx-page-btn">1</a>
// <a href="...?page=2" class="dx-page-btn dx-page-active">2</a>
// <a href="...?page=3" class="dx-page-btn">3</a>
// <a href="...?page=3" class="dx-page-btn">›</a>


11. 게시판 데이터 헬퍼


11.1 dx_board_posts($boardKey, ...) — 게시글 배열 반환

홈페이지 메인 위젯•사이드바에서 특정 게시판의 최신 게시글을 배열로 가져옵니다.
 

파라미터

파라미터 기본값 설명
$boardKey (필수) 게시판 고유 키 (예: notice, free, gallery)
$limit 5 가져올 게시글 수
$withNotice false true이면 공지글 포함
$titleLen 0 제목 최대 글자수 (0이면 자르지 않음)
$excerptLen 100 본문 요약 글자수 (0이면 요약 없음)


반환 배열 구조

// 반환 배열 각 항목
$post = [
    'id'            => 123,           // 게시글 ID
    'title'         => '게시글 제목',   // 제목 (titleLen 적용)
    'author'        => '홍길동',        // 작성자 (익명이면 '익명')
    'date'          => '2025-04-24',   // 작성일 (Y-m-d)
    'date_short'    => '04.24',        // 작성일 짧게 (m.d)
    'url'           => 'https://...', // 게시글 상세 URL
    'board_key'     => 'notice',       // 게시판 키
    'view_count'    => 42,             // 조회수
    'comment_count' => 5,              // 댓글수
    'excerpt'       => '본문 요약...',  // 요약 (excerptLen > 0 이면)
];


사용 예

// 공지사항 최신 5개
$notices = dx_board_posts('notice');

// 자유게시판 10개 (공지 포함, 제목 30자, 요약 150자)
$posts = dx_board_posts('free', 10, true, 30, 150);

// 갤러리 6개
$gallery = dx_board_posts('gallery', 6);

// 출력
foreach ($posts as $post) {
    echo '<a href="' . dx_safe_url($post['url']) . '">';
    echo dx_esc($post['title']) . '</a>';
    echo '<span>' . dx_esc($post['date_short']) . '</span>';
}


11.2 dx_board_latest($boardKey, ...) — 스킨으로 직접 출력

게시글을 가져와 지정한 스킨 파일로 바로 렌더링합니다. dx_board_posts()와 달리 HTML을 직접 echo합니다.


스킨 파일 탐색 순서

  • 1순위: themes/{현재테마}/board_latest/{스킨명}.php
  • 2순위: themes/default/board_latest/{스킨명}.php
  • 3순위: themes/default/board_latest/list.php  (최종 폴백)


스킨 파일 내부에서 사용 가능한 변수

변수명 설명
$board_key 게시판 키 (예: notice)
$board_name DB에 저장된 게시판 이름
$title 섹션 표시 제목 (지정 없으면 board_name)
$icon 아이콘 이모지
$more_url 더보기 링크 URL
$posts dx_board_posts() 반환 배열
$show_excerpt 요약 표시 여부 (bool)


사용 예

// 기본 list 스킨으로 공지사항 5개 출력
dx_board_latest('notice');

// card 스킨, 섹션 제목과 아이콘 지정
dx_board_latest('free', 5, 'card', '자유게시판', '💬');

// 제목 25자 자르기 + 요약 포함
dx_board_latest('gallery', 6, 'simple', '갤러리', '🖼️', 25, true);

// 테마 파일(themes/default/home.php) 안에서 사용
// <?php dx_board_latest('notice', 5, 'list', '공지사항', '📢'); ?>


12. 에셋 및 폰트 출력 함수


12.1 dx_head_assets($opts = [])

모든 레이아웃 <head> 에서 호출하면 Pretendard, Space Grotesk, Font Awesome 6, dxb-css.js를 자동 삽입합니다.
 
// 기본 (모두 로드)
dx_head_assets();

// 선택적 로드
dx_head_assets([
    'pretend' => true,   // Pretendard 폰트
    'grotesk' => true,   // Space Grotesk 폰트
    'fa'      => true,   // Font Awesome 6
    'dxb'     => true,   // dxb-css.js (DXB 유틸리티 CSS 엔진)
]);

// Font Awesome 제외
dx_head_assets(['fa' => false]);

// 레이아웃 파일 head 섹션 예시
// <head>
//   <meta charset="UTF-8">
//   <?php dx_head_assets(); ?>
//   <?php dx_font_css(); ?>
// </head>


12.2 dx_font_css()

CSS 리셋 + Pretendard/Space Grotesk 폰트 변수 정의 + 스크롤바 스타일을 <style> 태그로 출력합니다.
 
// 레이아웃 <head> 또는 <style> 바로 다음에 호출
dx_font_css();

// 출력 내용:
// * 박스 모델 리셋 (box-sizing: border-box)
// * :root CSS 변수: --font-body, --font-head, --font-mono
// * body font-family 설정
// * a 기본 스타일 제거
// * img 반응형 설정
// * 스크롤바 스타일 (webkit)
// * 텍스트 선택 색상
// * .sg 클래스 (Space Grotesk 단축)


12.3 _dxAvaColor($name) — 아바타 색상 헬퍼

회원 이름을 해싱하여 8가지 고정 색상 중 하나를 반환합니다. 이미지 없는 회원의 텍스트 아바타 배경색 생성에 사용합니다.
 
$color = _dxAvaColor($member['name']);
// → '#3b82f6' (이름에 따라 항상 동일한 색상 반환)

// 아바타 출력 예시
$bg    = _dxAvaColor($member['name']);
$initial = mb_substr($member['name'], 0, 1, 'UTF-8');
echo '<div class="avatar" style="background:' . $bg . '">' . dx_esc($initial) . '</div>';


13. 로그•Ajax•플러그인 로더


13.1 dx_log($message, $level = 'info')

에러와 경고만 data/error.log 에 기록합니다. info/debug 레벨은 기록하지 않습니다. 호출 파일과 라인 번호가 자동 기록됩니다.
 
// 에러 기록 (기록됨)
dx_log('DB 쿼리 실패: ' . $e->getMessage(), 'error');

// 경고 기록 (기록됨)
dx_log('파일 업로드 실패: ' . $filename, 'warning');

// info/debug는 기록 안 됨 (성능 보호)
dx_log('게시글 조회: ' . $postId, 'info');   // 기록 안 됨

// 로그 파일 형식:
// [2025-04-24 14:30:45][ERROR][boards/handler.php:123] DB 쿼리 실패: ...


13.2 dx_is_ajax()

현재 요청이 XMLHttpRequest(Ajax) 인지 확인합니다. X-Requested-With: XMLHttpRequest 헤더를 기준으로 판단합니다.
 
if (dx_is_ajax()) {
    // Ajax 요청 → JSON 응답
    dx_json(['success' => true, 'html' => $html]);
} else {
    // 일반 요청 → 페이지 리다이렉트
    dx_redirect_back();
}


13.3 load_plugins()

DX_PLUGINS 디렉토리에서 각 플러그인의 plugin.php를 자동으로 require_once합니다. 플러그인 로드 후 DXB CSS 엔진 주입과 에디터 훅 브릿지를 자동 설정합니다.
 
// index.php 부팅 시 자동 호출됨 (직접 호출 불필요)
load_plugins();

// 플러그인 디렉토리 구조:
// plugins/
//   my_plugin/
//     plugin.php   ← 이 파일이 자동 로드됨
//   another_plugin/
//     plugin.php

// DXB CSS 엔진 자동 주입 (테마 수정 불필요):
// - dx_head 훅 (priority=1): dxb-css.js 로드 + 1차 rescan
// - dx_body_bottom 훅 (priority=1): 2차 rescan (rAF 포함)
// - dx_admin_top 훅 (priority=1): 관리자 영역 rescan


14. 포인트•경험치 훅 자동 등록


14.1 _dx_register_point_hooks()

게시글 작성, 댓글, 로그인, 가입, 좋아요 등의 이벤트에 포인트/경험치를 자동 부여하는 훅을 등록합니다. DxPoint 클래스 로드 후 자동 실행됩니다.
 
훅 이름 발동 시점 지급 포인트 종류
dx_after_write 게시글 작성 완료 write (글쓰기 포인트 + 경험치)
dx_after_comment 댓글 작성 완료 comment (댓글 포인트 + 경험치)
dx_after_login 로그인 성공 (일 1회) login (출석 포인트 + 경험치)
dx_after_register 신규 회원 가입 signup (가입 축하 포인트 + 경험치)
dx_after_like 좋아요 받음 like_recv (좋아요 받기 포인트 + 경험치)

포인트 설정
실제 지급 포인트 수량은 관리자 > 포인트 설정에서 각 항목별로 설정합니다.
함수 내 두 번째 인자 0은 설정값을 DB에서 자동으로 읽어오기 위한 플레이스홀더입니다.
로그인 포인트는 오늘 이미 받은 경우 point_log 테이블을 확인하여 중복 지급을 방지합니다.


15. 실전 통합 활용 패턴


15.1 게시글 목록 페이지 전체 패턴

<?php
// 1. 입력값 안전 수신
$page    = dx_get('page', 1, 'int');
$keyword = dx_get('keyword');
$catId   = dx_get('cat', 0, 'int');
$perPage = 20;

// 2. 데이터 조회
$db    = Database::getInstance();
$total = (int)$db->value(
    "SELECT COUNT(*) FROM posts WHERE board_id=? AND status=1",
    [$boardId]
);
$offset = ($page - 1) * $perPage;
$rows   = $db->rows(
    "SELECT * FROM posts WHERE board_id=? AND status=1
     ORDER BY id DESC LIMIT {$perPage} OFFSET {$offset}",
    [$boardId]
);

// 3. 페이지네이션 생성
$pager = dx_pagination(
    $total, $perPage, $page,
    dx_base_url($boardKey . '?page={page}&keyword=' . urlencode($keyword))
);

// 4. 날짜•제목 포맷
foreach ($rows as &$row) {
    $row['date_f']    = dx_date($row['created_at'], 'Y-m-d');
    $row['date_ago']  = dx_time_ago($row['created_at']);
    $row['title_s']   = dx_substr($row['title'], 30);
}

// 5. 출력 (스킨 파일에서)
foreach ($rows as $row) {
    echo '<a href="' . dx_safe_url(dx_base_url($boardKey.'/'.$row['id'])) . '">';
    echo dx_esc($row['title_s']);
    echo '</a> ' . dx_esc($row['date_ago']);
}
echo '<div class="pagination">' . $pager . '</div>';


15.2 Ajax POST 처리 핸들러 패턴

<?php
// Ajax 전용 핸들러 파일

// 1. CSRF 검증 (가장 먼저)
dx_csrf_check();

// 2. 로그인 확인
if (!Auth::getInstance()->isLoggedIn()) {
    dx_json(['success' => false, 'message' => '로그인이 필요합니다.'], 401);
}

// 3. 입력값 수신
$postId  = dx_post('post_id', '0', 'bigint');
$comment = dx_post('comment');

// 4. 유효성 검사
if (empty($comment)) {
    dx_json(['success' => false, 'message' => '댓글 내용을 입력하세요.'], 422);
}

// 5. DB 처리
try {
    $db = Database::getInstance();
    $id = $db->insert($db->table('comments'), [
        'post_id'    => $postId,
        'member_id'  => Auth::getInstance()->user()['id'],
        'content'    => DxSanitizer::cleanText($comment),
        'ip'         => dx_ip(),
        'created_at' => date('Y-m-d H:i:s'),
    ]);
    dx_json(['success' => true, 'comment_id' => $id]);
} catch (Exception $e) {
    dx_log('댓글 저장 실패: ' . $e->getMessage(), 'error');
    dx_json(['success' => false, 'message' => '저장 중 오류가 발생했습니다.'], 500);
}


15.3 홈페이지 메인 위젯 패턴

<?php // themes/default/home.php ?>

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <?php dx_head_assets(); ?>
  <?php dx_font_css(); ?>
</head>
<body>

<!-- 공지사항 위젯 (list 스킨) -->
<?php dx_board_latest('notice', 5, 'list', '공지사항', '📢'); ?>

<!-- 자유게시판 위젯 (card 스킨, 제목 25자, 요약 포함) -->
<?php dx_board_latest('free', 6, 'card', '자유게시판', '💬', 25, true); ?>

<!-- PHP 배열로 받아서 직접 처리 -->
<?php
$gallery = dx_board_posts('gallery', 8, false, 20);
foreach ($gallery as $p) {
    echo '<div class="card">';
    echo '  <a href="' . dx_safe_url($p['url']) . '">' . dx_esc($p['title']) . '</a>';
    echo '  <span>' . dx_esc($p['date_short']) . '</span>';
    echo '</div>';
}
?>

</body>
</html>


16. 전체 공통함수 빠른 참조표

함수명 카테고리 반환 타입 비고
dx_random_bytes($length) 보안 난수 string (bytes) PHP 5.6+ 자동 폴백
dx_random_hex($length=32) 보안 난수 string 16진수 토큰 생성
dx_realpath($path) 경로 string|false 역슬래시 → 슬래시
dx_path_inside($path, $base) 경로 bool 경로 탈출 방어
dx_is_https() HTTPS bool 프록시/CDN 포함
dx_base_url($path='') URL string URL Rewrite 자동
dx_static_url($path='') URL string 정적 자산 URL
dx_request_uri() URL string 이중슬래시 정규화
dx_current_url() URL string 현재 완전 URL
dx_redirect($url, $code=302) URL void+exit Location 헤더
dx_redirect_back($fallback='/') URL void+exit Referer 기반
dx_get($key, $default, $type) 요청 mixed $_GET 안전 수신
dx_post($key, $default, $type) 요청 mixed $_POST 안전 수신
dx_request($key, $default, $type) 요청 mixed $_REQUEST 안전 수신
dx_method($method) 요청 bool HTTP 메서드 비교
dx_cast($val, $type) 타입 mixed 타입 변환 헬퍼
dx_ip() IP string Cloudflare 포함
dx_ua() UA string UA 문자열 (500자)
dx_device() 디바이스 string mobile|tablet|pc
dx_os() 디바이스 string OS 이름
dx_browser() 디바이스 string 브라우저 이름
dx_config($key, $default) 설정 mixed $dx_config 읽기
dx_set_config($key, $value) 설정 void 런타임 설정 변경
dx_config_set($key, $value) 설정 void dx_set_config 별칭
dx_esc($str) 보안 string XSS 방어 출력
dx_safe_url($url) 보안 string URL XSS 방어
dx_csrf_token() 보안 string CSRF 토큰 반환
dx_csrf_field() 보안 string hidden input 반환
dx_csrf_check() 보안 void 검증 실패 시 403
dx_error($msg, $code=500) 응답 void+exit HTTP 오류 출력
dx_json($data, $code=200) 응답 void+exit JSON API 응답
dx_flash($msg, $type) 플래시 void 세션 메시지 저장
dx_set_flash($msg, $type) 플래시 void dx_flash 별칭
dx_get_flash() 플래시 array|null 읽고 세션 삭제
dx_substr($str, $len, $suffix) 문자열 string UTF-8 안전
dx_mb_substr($str, $start, $len) 문자열 string mb_substr 폴백
dx_time_ago($datetime) 날짜 string '방금 전' 형식
dx_date($datetime, $format) 날짜 string 날짜 포맷
dx_filesize($bytes) 파일 string B/KB/MB/GB 표시
dx_upload_url($path) 파일 string uploads URL
dx_upload_exists($path) 파일 bool 파일 존재 확인
dx_array_column($arr, $key, $idx) 배열 array PHP 5.4 폴백
dx_pagination(...) 페이지 string (HTML) 페이지 버튼 HTML
dx_board_posts($key, ...) 게시판 array 게시글 배열 반환
dx_board_latest($key, ...) 게시판 void (echo) 스킨으로 직접 출력
dx_head_assets($opts) 에셋 void (echo) CDN 폰트/아이콘
dx_font_css() 에셋 void (echo) CSS 리셋+폰트 변수
_dxAvaColor($name) 에셋 string (#hex) 아바타 색상
dx_log($message, $level) 로그 void error/warning만 기록
dx_is_ajax() Ajax bool XHR 요청 감지
load_plugins() 플러그인 void plugin.php 자동 로드
 
 
 
 

댓글0

로그인 후 댓글을 작성할 수 있습니다.
3.6 데이터 처리 구조 공통 함수 활용 2026.04.21 3.6 데이터 처리 구조 데이터 흐름 상세 기술 2026.04.21 3.6 데이터 처리 구조 DB 접근 방식 2026.04.21
30
전체 회원
269
전체 게시글
144
전체 댓글
181
오늘 방문
28,530
전체 방문
1
현재 접속
인기글 7일 이내
최신글
최신댓글
목록