회원가입 | 고객센터 |
DESIGNONEX DXCMS BOARD
로그인
DESIGNONEX
디자인원엑스
About
Service
Q&A
PR리그
자유게시판N
갤러리
포인트게임
공지사항
로그인 회원가입
고객센터
3.3 실행 흐름

초기 로딩 과정 및 공통 초기화 흐름

A Administrator
2026.04.21 00:51(수정됨) 28 0

1. 개요

DXCMS는 단일 진입점(index.php) 기반의 PHP CMS로, 별도의 무거운 프레임워크 없이 자체 제작한 DX 미니프레임워크 위에서 동작합니다. 모든 HTTP 요청은 반드시 index.php 한 곳을 통해 처리되며, 그 안에서 보안 초기화 → DB 연결 → 서비스 초기화 → 라우팅 → 렌더링 순서로 순차적으로 실행됩니다.

핵심 설계 원칙: 파일 하나(Secure.php)가 보안을 전담하고, 나머지 모든 클래스는 역할별로 분리되어 있습니다. 보안 패치가 필요할 경우 Secure.php 한 파일만 수정하면 됩니다.


1.1 설계 목표

단일 진입점 index.php 하나로 모든 요청을 수용 (Front Controller 패턴)
PHP 호환성 PHP 5.6 ~ 8.x 단일 코드베이스로 동작
서버 호환성 Apache • Nginx • IIS • 저가형 공유호스팅 완전 지원
OS 호환성 Windows • Linux 공통 동작 (백슬래시 경로 자동 정규화)
보안 집중화 CSRF • XSS • Rate Limit • 세션 보안 → Secure.php 전담
성능 최적화 세션 지연 시작, APCu 자동 감지, 파일 캐시, 출력 버퍼링


2. 전체 실행 흐름 요약

아래 표는 index.php가 실행되는 순간부터 응답이 완료될 때까지의 전체 단계를 요약한 것입니다.
 
단계 구분 주요 처리 내용
STEP 0 환경 전처리 ob_start(), URI 이중슬래시 정규화 301 리다이렉트, PHP 5.6 버전 체크
STEP 1 클래스/함수 로드 functions.php, Secure.php, DxSanitizer, Database, HookManager 등 require_once
STEP 2 보안 초기화 세션 설정 → 세션 시작 (조건부) → 보안 헤더 발행 → CSRF 토큰 선제 발급
STEP 3 DB 연결 + 설정 로드 config.php 실행 → PDO 연결 → 시크릿 키 주입
STEP 4 서비스 초기화 HookManager, PluginRegistry, DxSite, DxTheme, Auth, DxContainer 순차 초기화
STEP 5 라우팅 + 디스패치 Router::resolve() → Dispatcher::dispatch() → 핸들러 실행 → 렌더링
STEP 6 후처리 extend/bottom/ 실행, ob_end_flush() 출력 버퍼 최종 전송


3. STEP 0 — 환경 전처리


3.1 출력 버퍼링 시작

index.php의 첫 번째 실행 코드는 ob_start()입니다. 출력 버퍼링을 활성화하는 이유는 IIS, CGI, 저가형 웹호스팅 환경에서 header() 함수 호출 시 발생하는 "headers already sent" 오류를 원천 차단하기 위해서입니다. 모든 출력은 버퍼에 쌓였다가 마지막 단계에서 ob_end_flush()를 통해 한 번에 전송됩니다.


3.2 URI 이중 슬래시 정규화

브라우저 주소창에 "//board//notice"처럼 이중 슬래시가 포함된 URL이 들어오면, PHP 레벨에서 즉시 301 리다이렉트로 정규화된 URL로 이동시킵니다. 이는 SEO 중복 콘텐츠 문제를 방지하고 URL을 일관되게 유지하기 위한 처리입니다.


3.3 PHP 버전 체크

PHP 5.6 미만 환경에서 실행되면 즉시 오류 메시지를 출력하고 중단됩니다. DXCMS는 PHP 5.6부터 8.x까지 단일 코드베이스를 사용하므로, 지원 버전 미만에서는 실행 자체를 허용하지 않습니다.


3.4 핵심 상수 정의

시스템 전체에서 사용되는 경로 상수를 정의합니다.
 
DX_CMS 직접 접근 방지용 상수. 각 파일 상단에서 defined() 체크
DX_VERSION 현재 버전 (예: 8.0.3)
DX_ROOT index.php 위치의 절대 경로 (백슬래시 → 슬래시 정규화)
DX_CORE core/ 폴더 경로
DX_DATA data/ 폴더 경로 (설정, 캐시, 업로드)
DX_THEMES themes/ 폴더 경로
DX_PLUGINS plugins/ 폴더 경로
DX_START microtime(true) — 요청 시작 시각, 성능 측정 기준점


3.5 설치 여부 확인 및 미설치 처리

data/config.php 파일의 존재 여부로 설치 완료 여부를 판단합니다. 파일이 없으면 install/ 폴더로 자동 리다이렉트합니다. 설치 전에는 에러를 화면에 표시하여 디버깅을 돕고, 설치 후에는 에러를 파일(data/error.log)에만 기록합니다.


4. STEP 1 — 클래스/함수 파일 로드

이 단계에서는 실행 없이 정의만 합니다. require_once를 통해 CMS 전체에서 사용되는 클래스와 함수를 메모리에 적재합니다.


4.1 로드 순서와 의존 관계

functions.php 전역 헬퍼 함수 정의 (dx_esc, dx_csrf_*, dx_config 등)
Secure.php 보안 전담 클래스. 설치 시 생성된 고유 경로(core/security/{hash}/)에서 로드
DxSanitizer.php 입력값 정제 및 HTML 필터링
db/Database.php PDO 래퍼 싱글턴. 연결은 STEP 3에서 config.php가 담당
hook/HookManager.php 훅 시스템 (WordPress 방식의 add_action/do_action)
PluginRegistry.php 플러그인 등록 및 활성화 관리
auth/Auth.php 세션 기반 인증. 로그인 상태 관리
DxPoint.php 포인트/경험치/레벨 시스템
DxFriend.php 친구/팔로우 기능
DxShop.php 쇼핑 기능 (포인트 결제, 상품 관리)
DxSite.php 멀티사이트 엔진 (도메인별 독립 설정)
DxTheme.php 테마 엔진 (스킨 폴백 체인)
DxCache.php 파일 캐시 / APCu 자동 감지
DxSeo.php OG 태그, Twitter Card, JSON-LD, 사이트맵
DxCategory.php 카테고리 렌더링 헬퍼
DxThumb.php 이미지 썸네일 생성
DxNotification.php 알림 시스템
DxMemberMonitor.php 회원 접속 모니터링 (last_seen, 온라인 상태)
DxPopup.php 팝업 자동 출력 관리
DxBoardSkin.php 게시판 스킨 폴백 체인
DxMarket.php 마켓 (플러그인 배포)
DxSocialAuth.php 소셜 로그인 (Google, Kakao, Naver, GitHub)
DxExtend.php extend/ 폴더 자동 실행
router/Router.php URL 파싱 및 라우트 결정
router/Dispatcher.php 라우트 → 핸들러 실행
db/QueryBuilder.php 라라벨 스타일 QueryBuilder + dx_db()
DxContainer.php DI 컨테이너 (서비스 바인딩)
DxRouter.php 클래스 기반 라우터 (v6.2.0+)


4.2 Secure.php 고유 경로 로드

일반 CMS와 달리 DXCMS는 Secure.php를 고정 경로가 아닌 설치 시 생성된 16자리 해시 경로에서 로드합니다. 경로: core/security/{해시값}/Secure.php

보안 목적: 소스코드가 공개되더라도 Secure.php의 실제 위치를 예측할 수 없습니다. 파일이 손실된 경우 core/Secure.php로 자동 폴백합니다.


5. STEP 2 — 보안 초기화

Secure 클래스는 싱글턴(Singleton) 패턴으로 구현되어 있으며, Secure::getInstance()를 통해 인스턴스를 획득합니다. 이후 세션 설정 → 세션 시작 → 보안 헤더 → CSRF 토큰 순서로 초기화합니다.


5.1 세션 설정 (initSession)

session_start() 호출 전에 세션 관련 설정을 완료합니다. 주요 설정 항목은 다음과 같습니다.
  • session.cookie_httponly = 1  →  JavaScript의 document.cookie 접근 차단
  • HTTPS 환경에서 session.cookie_secure = 1  →  쿠키 HTTPS 전용
  • session.use_strict_mode = 1  →  세션 ID 고정 공격(Session Fixation) 방어
  • session.cookie_samesite 설정  →  CSRF 추가 방어


5.2 세션 지연 시작 (성능 최적화)

DXCMS는 모든 요청에서 세션을 시작하지 않습니다. 다음 조건을 모두 만족할 때만 세션 시작을 건너뜁니다.
  1. 요청 메서드가 GET
  2. 세션 쿠키가 없음 (비로그인 사용자)
  3. AJAX 요청이 아님 (HTTP_X_REQUESTED_WITH 헤더 없음)
  4. URL이 /admin, /auth, /view/, /api/, /write, /edit, /reply가 아님

효과: 세션 파일 락(file lock) 제거로 동시 접속자가 많을 때 성능이 향상됩니다. 비로그인 사용자의 목록 조회 페이지에서 세션 파일을 생성하지 않으므로 I/O 부담이 줄어듭니다.


5.3 보안 헤더 발행 (sendSecurityHeaders)

.htaccess나 nginx.conf 설정 없이도 보안 헤더를 PHP 레벨에서 발행합니다. 저가형 공유호스팅에서 서버 설정을 변경할 수 없는 환경을 커버하기 위한 설계입니다.
  • X-Content-Type-Options: nosniff
  • X-Frame-Options: SAMEORIGIN
  • X-XSS-Protection: 1; mode=block
  • Referrer-Policy: strict-origin-when-cross-origin
  • Content-Security-Policy (설정에 따라 동적 생성)


5.4 CSRF 토큰 선제 발급

세션이 시작된 경우, 매 요청 시작 시 CSRF 토큰을 미리 발급해 둡니다. 이 토큰은 폼(Form) 렌더링 시 dx_csrf_field()를 통해 hidden 필드로 삽입되고, POST 요청 시 dx_csrf_check()로 검증됩니다. 시크릿 키 기반으로 토큰 이름 자체를 동적으로 생성하므로, 소스코드가 공개되어도 토큰 이름 예측이 불가능합니다.


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


6.1 config.php 실행

data/config.php를 require_once로 실행합니다. 이 파일 안에서 Database::getInstance()->connect()가 호출되어 PDO(PHP Data Objects) 연결이 수립됩니다. config.php에는 DB 접속 정보, 사이트 기본 설정, 시크릿 키 등이 정의되어 있습니다.

config.php는 data/ 폴더 아래에 위치하며 .htaccess로 직접 접근이 차단되어 있습니다. 웹 브라우저에서 직접 열 수 없습니다.


6.2 시크릿 키 주입 (initSecretKeys)

DB 설정 로드 직후, 사이트마다 다른 64자리 랜덤 시크릿 키를 기반으로 세션 토큰, CSRF 토큰, Rate Limit 키의 이름을 동적으로 도출합니다.
 
시크릿 키 길이 64자리 랜덤 문자열 (설치 시 자동 생성)
키 이름 도출 sha256(secret + 고정 접미사) 형태로 각 기능별 키 이름 생성
보안 효과 소스코드 공개 상태에서도 세션/CSRF 키 이름 예측 불가
하위 호환 기존 설치에 DX_SECRET_KEY 없으면 자동으로 config.php에 추가


7. STEP 4 — 서비스 초기화

DB 연결이 완료된 후 CMS의 핵심 서비스들을 순서대로 초기화합니다. 각 클래스는 싱글턴 패턴이므로 getInstance() 호출 시 한 번만 생성됩니다.


7.1 HookManager — 훅 시스템

WordPress 방식의 액션/필터 훅 시스템입니다. 플러그인과 테마가 CMS 핵심 코드를 수정하지 않고도 동작을 확장할 수 있도록 합니다.
  • dx_add_hook(이름, 콜백, 우선순위) — 훅 등록
  • dx_do_hook(이름, 데이터) — 훅 실행
  • 주요 훅: dx_after_login, dx_after_logout, dx_body_bottom 등


7.2 PluginRegistry — 플러그인 로드

활성화된 플러그인 목록을 DB에서 읽어 plugins/{이름}/plugin.php를 순서대로 require합니다. 각 플러그인은 훅을 통해 기능을 확장하며, 비활성화된 플러그인은 로드되지 않습니다.

결제 플러그인 예시: 토스페이, 카카오페이, 네이버페이, KG이니시스, KCP, 다날, NicePay, PayLetter, Stripe, PayPal이 별도 플러그인으로 분리되어 있습니다.


7.3 DxSite — 멀티사이트

현재 요청의 도메인(HTTP_HOST)을 DB에서 조회하여, 도메인별 독립 설정($dx_config)을 덮어씁니다. 하나의 설치본으로 여러 도메인을 운영할 수 있는 멀티사이트 기능의 핵심입니다.


7.4 DxTheme — 테마 엔진

DxSite 초기화 이후에 실행됩니다. 사이트 설정에서 활성 테마를 읽어 DxTheme 인스턴스에 저장합니다. 이후 모든 뷰 파일 경로는 DxTheme::resolve()를 통해 현재 테마 → 기본 테마 순으로 폴백하며 결정됩니다.


7.5 Auth — 인증

세션에서 사용자 정보를 읽어 로그인 상태를 확인합니다. 세션 유효성, 세션 만료, IP 변경 감지 등을 통해 비정상 세션을 차단합니다. 이후 모든 코드에서 Auth::getInstance()->isLoggedIn(), Auth::getInstance()->get("id") 등으로 현재 사용자 정보에 접근합니다.


7.6 DxContainer — DI 컨테이너

v6.2.0에서 도입된 의존성 주입(DI) 컨테이너입니다. registerCoreServices()를 호출하여 핵심 서비스들을 컨테이너에 등록합니다. 이후 DxContainer::getInstance()->make("service")로 서비스를 주입받을 수 있습니다.

7.7 훅 등록 및 회원 모니터링

초기화의 마지막 단계로 시스템 훅을 등록합니다.
  • dx_body_bottom 훅에 DxPopup::render() 등록 — 페이지 하단에 팝업 자동 출력
  • dx_after_login 훅에 DxMemberMonitor::onLogin() 등록 — 로그인 기록
  • dx_after_logout 훅에 DxMemberMonitor::onLogout() 등록 — 로그아웃 기록
  • 로그인 상태면 DxMemberMonitor::onRequest() — last_seen 갱신


7.8 extend/top/ 실행

모든 초기화가 완료된 직후, extend/top/ 폴더의 PHP 파일을 알파벳 순으로 실행합니다. 개발자가 전역 초기화 단계에서 커스텀 코드를 삽입하는 훅 포인트입니다. 버전(DX_VERSION)과 현재 경로(path)가 인자로 전달됩니다.


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


8.1 routes/ 폴더 자동 로드

routes/ 폴더에 PHP 파일이 있으면 알파벳 순으로 자동 로드합니다. DxRouter(클래스 기반 라우터)에 라우트를 등록하는 용도로 사용됩니다.


8.2 URI 파싱 — Router::resolve()

Router 클래스는 다양한 서버 환경에서 안정적으로 URI를 파싱하기 위해 여러 서버 변수를 순서대로 시도합니다.
 
$_GET[_url] URL Rewrite 미설치 IIS 환경 폴백 (?_url=/board/notice 형태)
IIS_WasUrlRewritten IIS URL Rewrite 2.x 환경
dx_request_uri() 정규화된 REQUEST_URI (기본값)
HTTP_X_REWRITE_URL ISAPI Rewrite 호환
ORIG_PATH_INFO CGI 환경
PATH_INFO 기타 환경


8.3 라우트 타입 결정

파싱된 URI 세그먼트를 분석하여 7가지 라우트 타입 중 하나를 결정합니다.
 
home 빈 URI → 홈 페이지
admin /admin/* → 관리자 패널
auth auth/* → 로그인, 회원가입, 마이페이지
api /api/* 또는 sitemap.xml, robots.txt → API 핸들러
search /search → 통합 검색
board DB에서 board_key 일치 → 게시판 (list/view/write/edit/delete)
page DB에서 slug 일치 → 페이지
404 어디에도 해당 없음 → 404 오류

게시판과 페이지는 DB를 직접 조회하여 존재 여부를 확인합니다. 멀티사이트 환경에서는 현재 도메인과 일치하는 게시판/페이지만 응답합니다.


8.4 Dispatcher::dispatch()

라우트 타입에 따라 해당 핸들러를 실행합니다. 핸들러 실행 전에 extend/middle/ 폴더의 코드를 먼저 실행하여 라우트 정보를 기반으로 한 커스텀 미들웨어를 지원합니다.
  • Home → themes/{테마}/page/home.php → DB is_home 페이지 → pages/home.php 순으로 폴백
  • Board → boards/handler.php → DxTheme 폴백 체인으로 스킨 파일 렌더링
  • Admin → admin/{action}/index.php 실행
  • Auth → core/auth/{action}.php 실행
  • API → core/api/{action}.php 실행
  • Page → 테마 page 파일 또는 pages/ 폴더 파일 실행
  • 404 → 테마 page/404.php 렌더링 


9. 후처리 — extend/bottom/ 및 출력 전송

핸들러 실행과 렌더링이 완료된 후 마지막 처리를 수행합니다.


9.1 extend/bottom/ 실행

extend/bottom/ 폴더의 PHP 파일을 알파벳 순으로 실행합니다. 성능 로그 기록, 외부 연동 통계 전송 등 렌더링 완료 후 실행해야 하는 코드에 사용합니다. 인자로 요청 처리 소요 시간(elapsed, 밀리초)이 전달됩니다.


9.2 출력 버퍼 최종 전송

ob_end_flush()를 호출하여 ob_start()로 시작된 출력 버퍼의 내용을 클라이언트에게 전송합니다. IIS, CGI 환경에서도 안정적인 응답이 보장됩니다.


10. 전체 초기화 흐름 다이어그램 (텍스트)

 
HTTP 요청
    │
    ▼
index.php
    │
    ├── [STEP 0] ob_start() → URI 정규화 → PHP 버전 체크 → 상수 정의
    │            → 설치 확인 → HTTPS 감지 → DX_SECURITY_PATH 선취 파싱
    │
    ├── [STEP 1] require_once 클래스/함수 파일 로드 (실행 없이 정의만)
    │            functions.php → Secure.php(고유경로) → Database → HookManager
    │            → PluginRegistry → Auth → DxSite → DxTheme → ... → Router → Dispatcher
    │
    ├── [STEP 2] 보안 초기화
    │            Secure::getInstance()
    │            → initSession() : 세션 파라미터 설정
    │            → startSession() : 조건부 (GET + 비로그인 + 비API 시 생략)
    │            → sendSecurityHeaders() : 보안 헤더 발행
    │            → csrfToken() : CSRF 토큰 선제 발급
    │
    ├── [STEP 3] DB 연결 + 설정 로드
    │            require config.php → PDO 연결
    │            → initSecretKeys() : 시크릿 키 기반 동적 키 이름 생성
    │
    ├── [STEP 4] 서비스 초기화
    │            HookManager → PluginRegistry → load_plugins()
    │            → DxSite → DxTheme → Auth → DxContainer
    │            → 훅 등록 (팝업, 회원모니터) → extend/top/ 실행
    │
    ├── [STEP 5] 라우팅 + 디스패치
    │            routes/ 자동 로드 → DxRouter::dispatch()
    │            → (미매칭) Dispatcher(Router)::dispatch()
    │                → extend/middle/ → switch(타입) → 핸들러 실행
    │
    └── [STEP 6] 후처리
                 extend/bottom/ 실행 → ob_end_flush()

    ▼
HTTP 응답 전송 완료


11. extend/ — 코드 삽입 포인트

DXCMS는 core/ 코드를 직접 수정하지 않고도 커스텀 코드를 삽입할 수 있는 세 가지 실행 시점을 제공합니다.
  • extend/top/    : 모든 초기화 완료 직후. 라우팅 전 실행. 전역 변수 설정, IP 차단 등
  • extend/middle/ : 라우트 타입 확정 후, 핸들러 실행 전. 접근 제어, 로깅 등
  • extend/bottom/ : 렌더링 완료 후. 성능 측정, 외부 통계 전송, 캐시 워밍 등

각 폴더의 .php 파일은 알파벳 순으로 자동 실행됩니다. 파일명 앞에 숫자(예: 01_access_log.php)를 붙여 실행 순서를 제어합니다. .disabled 확장자를 붙이면 실행에서 제외됩니다.


12. 요약

DXCMS의 DX 미니프레임워크는 다음 세 가지 철학을 기반으로 설계되었습니다.


12.1 단순함

단일 진입점(index.php)에서 모든 것이 순서대로 실행됩니다. 복잡한 오토로딩이나 DI 컨테이너 없이도 PHP 5.6에서 동작합니다. 각 클래스는 명확한 하나의 역할만 담당합니다.


12.2 현실성

저가형 공유호스팅, IIS 환경, URL Rewrite 미설치 서버까지 모두 지원합니다. 보안 헤더를 서버 설정 없이 PHP에서 발행하고, 출력 버퍼링으로 IIS 호환성을 보장합니다. 이는 실제 에이전시 운영 경험에서 나온 현실적인 선택입니다.


12.3 보안

Secure.php 한 파일이 세션, CSRF, 보안 헤더, Rate Limit을 전담합니다. 보안 패치 시 이 파일만 업데이트하면 됩니다. 시크릿 키 기반 동적 키 이름과 고유 경로 Secure.php 로드로 소스코드 공개 환경에서도 공격면을 최소화합니다.

댓글0

로그인 후 댓글을 작성할 수 있습니다.
번호 제목 작성자 날짜 조회
Administrator
04.21 28
3.3 실행 흐름
초기 로딩 과정 및 공통 초기화 흐름
Administrator 04.21 조회 28
26
전체 회원
195
전체 게시글
88
전체 댓글
211
오늘 방문
4,343
전체 방문
3
현재 접속
인기글 7일 이내
최신글
최신댓글
목록 글쓰기