회원가입 | 고객센터 |
DESIGNONEX
dxcms.kr
로그인 회원가입
고객센터
3.10 모듈 로딩 구조

자동 로딩 구조

D DX
2026.04.21 01:03(수정됨) 140 0

1. 개요

DXCMS v8.1.0은 단일 진입점(index.php) 기반의 PHP 프레임워크로, PHP 5.6부터 8.x까지의 광범위한 버전 호환성을 유지하면서 모던 CMS 기능을 제공합니다. 모든 HTTP 요청은 index.php를 통과하며, 이 과정에서 엄격히 순서화된 자동 로딩 메커니즘이 동작합니다.


📌  자동 로딩의 핵심 철학

  • 단일 진입점(Single Entry Point): 모든 요청이 index.php를 통해 처리됩니다.
  • 순서 보장(Ordered Loading): 의존성 순서대로 클래스/함수가 로드됩니다.
  • 격리(Isolation): 플러그인•확장 오류가 전체 시스템에 영향을 주지 않습니다.
  • 보안 우선(Security First): 보안 클래스가 다른 모든 초기화보다 먼저 실행됩니다.


2. 전체 부트스트랩 흐름

index.php는 요청을 처리하기 위해 아래 5단계를 순서대로 실행합니다. 각 단계는 이전 단계가 완료된 이후에만 실행됩니다.
 
단계 이름 주요 작업
STEP 1 클래스/함수 정의 로드 functions.php, DxCache, Secure.php, DxSanitizer, Database, HookManager, PluginRegistry, Auth 및 핵심 클래스 파일들을 require_once로 로드
STEP 2 보안 초기화 세션 설정 → 세션 시작(조건부) → 보안 헤더 발행 → CSRF 토큰 발급
STEP 3 DB 연결 + 설정 로드 data/config.php 로드 → DB 연결 → 시크릿 키 주입
STEP 4 DB 연결 후 초기화 HookManager → PluginRegistry → 플러그인 로드 → DxSite → DxTheme → Auth → DI 컨테이너 → DxExtend → extend/top/ 실행
STEP 5 라우팅 + 디스패치 routes/*.php 자동 로드 → DxRouter 매칭 시도 → 폴백: 파일 기반 Dispatcher → extend/bottom/ 실행


3. STEP 1 — 클래스/함수 정의 로드

STEP 1은 실행 없이 정의만 메모리에 올리는 단계입니다. 실제 동작은 STEP 2~4에서 이루어지며, STEP 1에서는 어떤 로직도 실행되지 않습니다.


3.1 로딩 순서

# 파일 역할 / 우선 로딩 이유
1 core/functions.php 전역 헬퍼 함수 정의 (dx_config, dx_log, load_plugins 등) — 다른 클래스가 이 함수들에 의존하므로 최우선 로드
2 core/DxCache.php 성능 최적화 우선 로드 — config.php 캐싱에 필요하여 DB 연결 전에 반드시 로드
3 core/security/{hash}/Secure.php 보안 전담 클래스 — 고유 해시 경로로 위치 예측 불가, 설치 시 생성된 경로에서 로드 (폴백: core/Secure.php)
4 core/DxSanitizer.php 입력값 정제(Sanitize) 클래스
5 core/db/Database.php DB 연결 클래스 (config.php 로드 전 클래스 정의만)
6 core/hook/HookManager.php 훅 시스템 (dx_add_hook, dx_run_hook 함수 정의)
7 core/PluginRegistry.php 플러그인 타입 등록소
8 core/auth/Auth.php 인증 클래스 (세션 검증 로직)
9 core/DxPoint.php ~ DxBoardSkin.php 각종 기능 클래스 (포인트, 친구, 샵, 사이트, 테마, SEO, 카테고리, 썸네일, 알림, 회원모니터, 팝업, 게시판스킨, 마켓)
10 core/DxSocialAuth.php 소셜 로그인 클래스 (파일 존재 시에만 로드)
11 core/DxExtend.php extend/ 폴더 자동 실행 엔진
12 core/router/Router.php 기존 파일 기반 라우터
13 core/router/Dispatcher.php 기존 디스패처
14 core/db/QueryBuilder.php QueryBuilder + dx_db() 헬퍼 (v6.2.0+)
15 core/DxContainer.php DI 컨테이너 (v6.2.0+)
16 core/DxRouter.php 클래스 기반 라라벨 스타일 라우터 (v6.2.0+)


3.2 보안 경로 해시 메커니즘

Secure.php는 설치 시 생성된 16자리 랜덤 해시를 경로로 사용합니다. 이 구조는 파일 경로 예측을 통한 직접 접근 공격을 방어합니다.
 
// data/config.php에 정의된 보안 경로 예시
define('DX_SECURITY_PATH', 'a1b2c3d4e5f6a7b8');  // 16자리 랜덤 해시

// 실제 로드 경로
// core/security/a1b2c3d4e5f6a7b8/Secure.php

// 폴백 처리 (파일 손실 또는 신규 설치 시)
if (!file_exists($_dxSecurePath)) {
    $_dxSecurePath = DX_CORE . '/Secure.php';
}

💡  DxCache 최우선 로드의 이유
DxCache는 STEP 1에서 가장 먼저 로드되는 비-함수 클래스입니다. 이는 다음 STEP 3에서 data/config.php를 로드할 때 설정 값을 파일 캐시로 빠르게 읽어오는 기능이 필요하기 때문입니다. DxCache가 없으면 매 요청마다 config.php를 파싱해야 합니다.

 
경로 패턴 세션 필요 이유
/admin 관리자 인증 상태 확인
/auth 로그인/로그아웃/회원가입 처리
/view/ 조회수 중복 방지 (같은 사용자가 새로고침해도 조회수 증가 방지)
/api/ 로그인 여부 확인이 필요한 AJAX API
/write 게시글 작성 권한 확인
/edit 게시글 수정 권한 확인
/reply 답글 작성 권한 확인


4.2 보안 헤더 자동 발행

Secure::sendSecurityHeaders()는 .htaccess나 web.config 없이도 저가형 공유 호스팅 환경에서 보안 헤더를 보장합니다.
  • Content-Security-Policy (CSP)
  • X-Frame-Options: SAMEORIGIN
  • X-Content-Type-Options: nosniff
  • Referrer-Policy
  • Permissions-Policy


5. STEP 3 — DB 연결 및 설정 로드

data/config.php를 require_once로 로드합니다. config.php 내부에서 DB 연결($db->connect())이 실행되므로, 이 시점부터 데이터베이스 쿼리가 가능해집니다.


5.1 시크릿 키 주입 (STEP 3-B)

DB 연결 직후, secret_key 기반으로 세션/CSRF/RateLimit 키 이름을 동적으로 도출합니다. 소스코드를 공개해도 키 이름을 예측할 수 없는 구조입니다.
 
// data/config.php에서 로드되는 핵심 상수들
define('DB_HOST',          'localhost');
define('DB_NAME',          'my_database');
define('DX_SITE_URL',      'https://example.com');
define('DX_SECURITY_PATH', 'a1b2c3d4e5f6a7b8');  // 보안 경로 해시
define('DX_SECRET_KEY',    '랜덤64자리키...');     // 시크릿 키

// Secure 클래스가 secret_key로 키 이름을 동적 생성
$_dxSecure->initSecretKeys($_dxSecretVal);


6. STEP 4 — 플러그인 및 확장 자동 로딩

가장 복잡한 단계입니다. DB 연결 완료 후 CMS의 확장 시스템이 순서대로 초기화됩니다.


6.1 초기화 순서

# 호출 이름 설명
1 HookManager::getInstance() 훅 시스템 인스턴스 생성 훅은 플러그인 로딩 전에 반드시 준비되어 있어야 합니다.
2 PluginRegistry::getInstance() 플러그인 타입 등록소 인스턴스 생성 editor, payment, captcha, sms 등의 타입 정의 초기화
3 load_plugins() 플러그인 자동 로드 ★ plugins/**/plugin.php 파일을 모두 require_once
4 _dx_register_point_hooks() 포인트 훅 등록 게시글 작성/삭제/댓글 등 포인트 지급 훅 일괄 등록
5 DxSite::getInstance() 멀티사이트 설정 적용 도메인별 설정을 $dx_config에 덮어씁니다.
6 DxTheme::getInstance() 테마 엔진 초기화 DxSite 이후 실행 (테마 확정 후 초기화)
7 Auth::getInstance() 인증 초기화 DB 연결 후 세션 검증, 로그인 상태 확인
8 DxContainer::getInstance()->registerCoreServices() DI 컨테이너 핵심 서비스 등록 db, auth, secure, cache, hook, seo, site, theme 등록
9 DxExtend::getInstance()->ensureDirs() extend/ 폴더 자동 생성 top/, middle/, bottom/ 폴더 없으면 자동 생성
10 dx_add_hook(팝업/모니터링) 시스템 훅 등록 팝업 자동출력, 로그인/로그아웃 모니터링, last_seen 갱신 훅 등록
11 DxExtend::runTop() extend/top/ 파일 자동 실행 사용자 커스텀 코드 실행 (점검모드, IP차단 등)

6.2 플러그인 자동 로드 (load_plugins)

load_plugins() 함수는 plugins/ 디렉터리의 모든 서브폴더를 탐색하여 plugin.php 파일을 자동으로 로드합니다.
 
function load_plugins()
{
    if (!defined('DX_PLUGINS') || !is_dir(DX_PLUGINS)) return;
    $dirs = glob(DX_PLUGINS . '/*', GLOB_ONLYDIR);
    if (!$dirs) return;
    foreach ($dirs as $dir) {
        $f = $dir . '/plugin.php';
        if (file_exists($f)) {
            require_once $f;  // 각 플러그인의 진입점 로드
        }
    }
    // DXB CSS 엔진 자동 주입
    _dx_inject_dxb_css();
    // 에디터 훅 브릿지 등록
    dx_add_hook('dx_editor_init', function($args) { ... }, 10);
}


플러그인 디렉터리 구조:

plugins/
  my-editor/
    plugin.php          ← load_plugins()가 자동 로드하는 진입점
    editor.js
    style.css
  kg-inicis/
    plugin.php
    inicis.php


6.3 PluginRegistry — 플러그인 타입 등록소

각 플러그인은 plugin.php 내에서 dx_register_plugin()을 호출하여 자신의 "타입"을 등록합니다. 관리자 설정 화면에 해당 타입의 선택 박스가 자동으로 나타납니다.
 
타입 ID 라벨 설정 키 용도
editor 에디터 active_editor TinyMCE, CKEditor, Quill 등 게시글 편집기
payment 결제 모듈 active_payment KG이니시스, 토스페이 등 PG사 연동
captcha CAPTCHA active_captcha reCAPTCHA v2/v3, hCaptcha, Turnstile
sms SMS 발송 active_sms 알리고, 네이버 클라우드 SMS 등
social_login 소셜 로그인 active_social_login 카카오, 네이버, 구글, GitHub OAuth
socket 실시간 소켓 active_socket WebSocket 기반 실시간 채팅·모니터링


6.4 DxContainer — 경량 DI 컨테이너

DxContainer는 Laravel의 Service Container와 동일한 철학으로 설계된 PHP 5.6 호환 경량 DI 컨테이너입니다. 기존 getInstance() 싱글턴 패턴을 유지하면서 추가적인 의존성 주입을 지원합니다.


자동 등록되는 핵심 서비스

서비스 키 클래스 별칭 / 설명
db Database::getInstance() 별칭: database — 쿼리빌더, 직접 쿼리 모두 지원
auth Auth::getInstance() 로그인 상태, 회원 정보 접근
secure Secure::getInstance() 보안 헤더, CSRF, 세션 관리
cache DxCache (클래스명) static 메서드 기반 파일 캐시
hook HookManager::getInstance() 별칭: hooks — 훅 등록/실행
seo DxSeo (클래스명) title, description, OG 태그 등
site DxSite::getInstance() 멀티사이트 설정 관리
theme DxTheme::getInstance() 테마 경로, 변수 관리


컨트롤러 자동 로드 경로

DxContainer::call()로 컨트롤러를 호출할 때, 클래스가 없으면 다음 경로를 순서대로 탐색합니다.
  • controllers/{ClassName}.php
  • controllers/{lowercase_name}.php (예: BoardController → board.php)
  • core/controllers/{ClassName}.php
  • plugins/*/controllers/{ClassName}.php (플러그인 컨트롤러)
// 컨트롤러 자동 의존성 주입 사용 예시
dx_app()->call('BoardController@index', ['slug' => 'free']);

// 서비스 바인딩 (플러그인에서)
dx_app()->singleton('mailer', function() {
    return new MyMailer(dx_config('smtp_host'));
});

// 서비스 꺼내기
$mailer = dx_make('mailer');


6.5 DxExtend — extend/ 폴더 자동 실행 엔진

DxExtend는 파일을 지정된 폴더에 넣는 것만으로 코드를 자동 실행할 수 있는 노-코드 확장 시스템입니다. 훅(Hook)이 개발자 코드에서 등록하는 방식인 것과 달리, DxExtend는 파일 배치만으로 동작합니다.
 
슬롯 실행 시점 주요 용도
extend/top/ 모든 초기화(DB·세션·Auth) 완료 직후, 라우팅 전 점검 모드, IP 차단, 커스텀 인증, 글로벌 변수 주입, 방문자 제한
extend/middle/ 라우트 확정 직후, 실제 핸들러 실행 전 방문자 로그, A/B 테스트, 접근 로그, 라우트별 처리 ($GLOBALS['dx_route'] 사용 가능)
extend/bottom/ 렌더링 완료 후, ob_end_flush() 직전 캐시 저장, 성능 로그, 정리 작업


파일 수집 및 실행 규칙

  • 폴더 내 *.php 파일을 파일명 오름차순으로 자동 수집
  • 파일명으로 실행 순서 제어 가능: 01_init.php → 02_log.php → 03_custom.php
  • 하위 폴더도 1단계까지 재귀 탐색
  • 에러 발생해도 다른 파일 계속 실행 (set_error_handler로 격리)
  • 보안: extend/ 내부 파일만 실행 (realpath 검증으로 경로 탈출 방지)
extend/
  top/
    01_maintenance.php   // 점검 모드 체크
    02_ip_block.php      // IP 차단
    03_custom_auth.php   // 커스텀 인증
  middle/
    01_access_log.php    // 방문자 로그
  bottom/
    01_cache_save.php    // 캐시 저장
    02_perf_log.php      // 성능 로그


7. STEP 5 — 라우팅 및 디스패치

모든 초기화가 완료된 후 요청 URL에 맞는 핸들러를 찾아 실행합니다. DXCMS는 두 가지 라우팅 방식을 지원하며, DxRouter(클래스 기반) → Dispatcher(파일 기반) 순으로 폴백됩니다.


7.1 routes/ 폴더 자동 로드

routes/ 폴더의 모든 .php 파일을 파일명 오름차순으로 자동 로드합니다.
 
$_dxRouteDir   = DX_ROOT . '/routes';
$_dxRouteFiles = glob($_dxRouteDir . '/*.php');
sort($_dxRouteFiles);  // 파일명 오름차순 정렬
foreach ($_dxRouteFiles as $_dxRouteFile) {
    require_once $_dxRouteFile;
}

// routes/web.php 예시
DxRouter::get('/mypage/dashboard', 'MemberController@dashboard')
         ->middleware('auth');
DxRouter::post('/api/update', 'MemberController@update')
         ->middleware(['auth', 'csrf']);


7.2 이중 라우팅 폴백 구조

라우터 동작 방식 설명
DxRouter (1순위) routes/*.php에서 등록된 URI 패턴 매칭 Laravel 스타일 — GET/POST/PUT/PATCH/DELETE, 그룹, 미들웨어, 리소스 라우트 지원 (v6.2.0+)
Dispatcher (폴백) URI를 파일 경로로 변환하여 해당 PHP 파일 실행 기존 파일 기반 라우팅 유지 — DxRouter에 매칭 라우트가 없을 때만 실행


7.3 DxRouter 지원 HTTP 메서드

메서드 함수 설명
GET DxRouter::get($uri, $action) 조회 요청
POST DxRouter::post($uri, $action) 생성 요청
PUT DxRouter::put($uri, $action) 전체 수정
PATCH DxRouter::patch($uri, $action) 부분 수정
DELETE DxRouter::delete($uri, $action) 삭제 요청
GET+POST DxRouter::any($uri, $action) GET과 POST 동시 등록
REST DxRouter::resource($uri, $controller) index/show/store/update/destroy 자동 등록


8. HookManager — 훅 시스템

HookManager는 WordPress 스타일의 훅/필터 시스템을 구현합니다. 플러그인과 테마가 CMS 동작을 수정할 수 있는 핵심 확장 메커니즘입니다.


8.1 훅 유형

유형 함수 설명
Action dx_add_hook() / dx_run_hook() 반환값 없이 동작을 수행. 예: 로그인 후 포인트 지급, 게시글 저장 후 알림 발송
Filter dx_add_filter() / dx_apply_filter() 값을 변형하여 반환. 예: 게시글 내용 필터링, URL 변환, HTML 정제


8.2 표준 훅 포인트

각 페이지 렌더링 시 dx_hook_top(), dx_hook_middle(), dx_hook_bottom() 함수가 자동으로 호출됩니다. 이 함수들은 전역 훅 외에 페이지 타입별, 슬러그별 훅도 연쇄 실행합니다.
 
함수 실행되는 훅 예시
dx_hook_top($context) dx_top dx_{type}_top dx_page_{slug}_top dx_top, dx_board_top, dx_page_free_top — 전역→타입별→슬러그별 순으로 실행
dx_hook_middle($context) dx_middle dx_{type}_middle dx_page_{slug}_middle dx_middle, dx_board_middle, dx_page_free_middle
dx_hook_bottom($context) dx_bottom dx_{type}_bottom dx_page_{slug}_bottom dx_bottom, dx_board_bottom, dx_page_free_bottom


8.3 우선순위 정렬

dx_add_hook()의 세 번째 파라미터로 priority를 지정합니다. 숫자가 낮을수록 먼저 실행됩니다. 기본값은 10입니다.
 
// 우선순위 예시
dx_add_hook('dx_after_login', function($args) {
    // priority 5: 다른 훅보다 먼저 실행
    record_login_log($args['user']['id']);
}, 5);

dx_add_hook('dx_after_login', function($args) {
    // priority 20: 나중에 실행
    DxMemberMonitor::onLogin($args['user']['id']);
}, 20);


9. 자동 로딩 구조 전체 요약

아래 다이어그램은 HTTP 요청부터 응답까지의 전체 자동 로딩 흐름을 요약합니다.
 
HTTP 요청
    │
    ▼
┌─────────────────────────────────────────────────────────┐
│  index.php (단일 진입점)                                │
│                                                         │
│  [STEP 1] 클래스/함수 정의 로드                         │
│    functions.php → DxCache → Secure → DxSanitizer       │
│    → Database → HookManager → PluginRegistry → Auth     │
│    → 기능 클래스들 → DxExtend → Router → DxContainer    │
│                                                         │
│  [STEP 2] 보안 초기화                                   │
│    Secure::initSession() → startSession() → 보안헤더    │
│    → CSRF 토큰 발급                                     │
│                                                         │
│  [STEP 3] DB 연결 + 설정 로드                           │
│    data/config.php 로드 → DB 연결 → 시크릿키 주입       │
│                                                         │
│  [STEP 4] DB 연결 후 초기화                             │
│    HookManager → PluginRegistry → load_plugins()        │
│    → DxSite → DxTheme → Auth → DxContainer              │
│    → DxExtend::ensureDirs() → extend/top/ 실행          │
│                                                         │
│  [STEP 5] 라우팅 + 디스패치                             │
│    routes/*.php 로드 → DxRouter::dispatch()             │
│    → 매칭 실패 시: Dispatcher::dispatch() (폴백)        │
│    → extend/bottom/ 실행                                │
│    → ob_end_flush()                                     │
└─────────────────────────────────────────────────────────┘
    │
    ▼
HTTP 응답

✅  핵심 설계 원칙 요약
  1) 보안 우선: Secure.php는 DB 연결보다 먼저, 고유 해시 경로에서 로드
  2) 성능 최적화: DxCache 최우선 로드, GET 요청 조건부 세션 생략
  3) 확장성: 플러그인(plugin.php), 훅(HookManager), 확장(extend/) 세 가지 계층
  4) 하위 호환: 파일 기반 라우팅(Dispatcher)은 유지, DxRouter가 먼저 시도
  5) 격리: DxExtend의 safeExec()으로 확장 파일 오류가 시스템에 전파되지 않음


10. 자동 로딩 관련 전역 헬퍼 함수

함수 정의 파일 설명
dx_app() DxContainer.php DxContainer 인스턴스 반환
dx_make($abstract) DxContainer.php 컨테이너에서 서비스 꺼내기
dx_bind($abstract, $factory) DxContainer.php 팩토리 바인딩 등록
dx_singleton($abstract, $factory) DxContainer.php 싱글턴 바인딩 등록
dx_add_hook($name, $cb, $priority) HookManager.php 훅 Action 등록
dx_run_hook($name, $args) HookManager.php 훅 Action 실행
dx_add_filter($name, $cb, $priority) HookManager.php 훅 Filter 등록
dx_apply_filter($name, $value) HookManager.php 훅 Filter 실행
dx_remove_hook($name, $callback) HookManager.php 훅 제거
dx_has_hook($name) HookManager.php 훅 등록 여부 확인
load_plugins() functions.php plugins/**/plugin.php 자동 로드
dx_register_plugin($info) PluginRegistry.php 플러그인 타입 등록
dx_extend_top($ctx) DxExtend.php extend/top/ 수동 실행
dx_extend_middle($ctx) DxExtend.php extend/middle/ 수동 실행
dx_extend_bottom($ctx) DxExtend.php extend/bottom/ 수동 실행
dx_hook_top($context) HookManager.php 페이지 최상단 표준 훅 실행
dx_hook_middle($context) HookManager.php 페이지 중간 표준 훅 실행
dx_hook_bottom($context) HookManager.php 페이지 최하단 표준 훅 실행

댓글0

로그인 후 댓글을 작성할 수 있습니다.
3.2 폴더 구조 assets/ — 정적 자원 2026.04.21 3.2 폴더 구조 plugins/ — 플러그인 시스템 2026.04.21 3.2 폴더 구조 themes/ — 테마 시스템 2026.04.21 3.2 폴더 구조 boards/ — 게시판 시스템 2026.04.21 3.2 폴더 구조 admin/ — 관리자 패널 2026.04.21 3.2 폴더 구조 core/ — CMS 엔진 2026.04.21 3.1 엔진 개요 실행 구조 개요 2026.04.21 3.1 엔진 개요 DX 엔진 구조 설명 2026.04.21 2. 시작 가이드 설치 시 보안 경로 구조 2026.04.20 2. 시작 가이드 서버별 설정 파일 상세 2026.04.20 2. 시작 가이드 기본 폴더 구조 설명 2026.04.20 2. 시작 가이드 설치 절차 2026.04.20 2. 시작 가이드 설치 환경 (PHP 버전, 서버 환경) 2026.04.20 비전 DXCMS 비전 2026.04.20 라이선스 DXCMS 오픈소스 및 제3자 소프트웨어 저작권 공지 2026.04.20 라이선스 DXCMS 라이선스 (LGPL 3.0) 2026.04.20 1. DX 철학 / 개념 생태계 확장 전략 2026.04.20 1. DX 철학 / 개념 DXCMS가 지향하는 방향 (플랫폼 vs 단순 CMS) 2026.04.20 1. DX 철학 / 개념 프레임워크 + CMS 통합 구조의 의미 2026.04.20 1. DX 철학 / 개념 기존 CMS와의 구조적 한계 2026.04.20
31
전체 회원
503
전체 게시글
770
전체 댓글
441
오늘 방문
33,173
전체 방문
2
현재 접속
인기글 7일 이내
최신글
최신댓글
목록