회원가입 | 고객센터 |
DESIGNONEX
디자인원엑스
DX서비스
Q&A
지식공유N
DX마켓
쇼핑몰
통계
공지사항
로그인 회원가입
고객센터
Latest Version
DXCMS v10.3.02026.06.15 배포 D+125일 (4개월)
  • 155다운로드
  • 0테마
  • 59플러그인
  • 7스킨
디엑스AI공부방

DXCMS v10.3.0 — 설치 환경 명세 (7)

D DX관리자
2026.10.18 14:56(수정됨) 4 0 5

7. 데이터베이스

7.1 접속 방식 [확인] (core/db/Database.php)

  • DSN mysql:host=;dbname=;charset=utf8mb4, ERRMODE_EXCEPTION, FETCH_ASSOC
  • ATTR_EMULATE_PREPARES = true, ATTR_STRINGIFY_FETCHES = true → 모든 값이 문자열로 반환된다 (PHP 5.6 32bit에서 BIGINT 오버플로 방지 목적). 정수 비교는 (int) 캐스팅 필요, === 비교 주의.
  • SET NAMES 'utf8mb4' 초기 명령
  • 연결 실패 시 dx_error('DB 연결 실패', 500)

7.2 스키마 (install/schema.sql, 49개 테이블, 접두사 기본 dx_)

영역 테이블
회원 members, social_accounts, member_logs, member_sessions, login_logs, login_tokens, email_verifications, level_config, point_log, exp_log, friends, scraps, memos, dm_messages, notifications
게시판 boards, board_groups, categories, board_fields, posts, post_meta, post_files, post_links, post_drafts, comments, likes, link_clicks, download_log, surveys, survey_questions, survey_answers, survey_votes
콘텐츠·UI pages, menus, popups, global_notices, themes, plugins
설정·사이트 settings, sites
통계·검색 visits, visit_logs, search_keywords
상점 shop_items, shop_purchases
외부연동 api_keys, api_logs, sms_logs, session_rescue
  • 외래키(FOREIGN KEY)는 사용하지 않는다. (SET foreign_key_checks = 0/1만 감쌈)
  • schema.sql은 이미 v10.2.0까지의 컬럼을 포함한다(visit_logs.is_entry, visit_key, src_campaign, is_404, plugins.db_tables, posts.popular_score 등 확인). 신규 설치 후 migrate.php를 꼭 돌릴 필요는 없다.
  • 인덱스는 utf8mb4 767바이트 제한을 피하려 VARCHAR(191)(이메일 등)을 쓴다.
  • FULLTEXT: dx_posts.ft_title_content(title, content), dx_search_keywords.ft_keyword(keyword). 기본 InnoDB 파서를 사용한다(ngram 미지정).

7.3 시드 데이터

대상 내용
members admin / admin1234(bcrypt) / admin@localhost — 설치 마법사가 입력값으로 덮어쓴다
settings site_name, site_description, site_url, theme=default, language=ko, timezone=Asia/Seoul, upload_max_size=10485760, upload_allowed_ext='', secret_key='', use_captcha=1, captcha_difficulty=normal, captcha_expire=300, use_signup=1, active_editor=ckeditor4-editor, url_rewrite=1
pages home(홈, is_home=1), shop
boards notice(공지, 쓰기 레벨 9), free(자유, 쓰기 레벨 1), customer(고객센터, qa 타입, skin=default)
menus 홈·공지사항·자유게시판·포인트샵(/, /notice, /free, /shop)
board_groups general, community, support
level_config 레벨표 (INSERT IGNORE)

7.4 마이그레이션 (install/migrate.php)

  • 브라우저로 접속하면 즉시 실행된다. 컬럼/테이블/인덱스 존재 여부를 확인하므로 중복 실행 안전(멱등).
  • v1.4.0부터 v10.2.0까지의 변경을 순서대로 누적하고, 마지막에 항상 cms_version을 version.php 값으로 갱신한다.
  • 부가 동작: core/security/{hash}/Secure.php를 최신 core/Secure.php로 다시 복사하고, 그 폴더에 .htaccess(Deny from all)를 만든다.
  • [주의] 인증이 없다. migrate.php는 로그인/관리자 확인 코드가 없고, 루트 .htaccess가 migrate.php를 명시적으로 Require all granted 한다. 실행 결과 화면에 security_path까지 출력된다. 업그레이드 후에는 install/을 삭제하거나 접근을 막아야 한다. (화면 문구는 "삭제하지 않아도 된다"고 안내하지만 운영 서버에서는 권장되지 않는다.)

7.5 검색 동작

  • 통합 검색(core/search/handler.php)은 FULLTEXT BOOLEAN MODE를 쓰되, 인덱스 존재 여부와 SHOW VARIABLES LIKE 'ft_min_word_len' 결과로 짧은 키워드는 LIKE로 강제 전환한다. 작성자 검색은 항상 LIKE.
  • 한글은 InnoDB 기본 파서로 토큰화되므로 FULLTEXT 결과가 기대와 다를 수 있고, 이때 LIKE 폴백에 의존한다.
  • 사용 중인 SQL 기능은 ON DUPLICATE KEY UPDATE, MATCH ... AGAINST뿐이다. JSON_* 함수, 윈도 함수, CTE는 쓰지 않아 MySQL 5.6 / MariaDB 10.1에서 동작한다.

8. 런타임에 생성되는 파일·폴더 (쓰기 권한 필요)

경로 생성 시점 권한/비고
data/config.php 설치 DB 비밀번호 포함. 웹 접근 차단 필수
data/.install_complete 설치 직후 1회용 토큰, 사용 후 삭제
data/error.log PHP 오류 error_log 경로로 지정됨
data/sessions/ 첫 세션 mkdir 0700. 쓰기 불가 시 PHP 기본 save_path 사용
data/cache/ 파일 캐시·레이트리밋 mkdir 0700. *.cache, rl_*.tmp, _mkt_*
data/uploads/boards/, data/uploads/thumbnails/ 업로드/썸네일 .htaccess가 PHP 실행 차단
data/cacert.pem 마켓/HTTPS 클라이언트 경로 참조 존재
core/security/{16hex}/Secure.php 설치·마이그레이션 0755
extend/{top,middle,bottom}/ 부팅 시 ensureDirs() 이미 존재
pages/*.php 관리자 > 페이지 관리 마법사가 pages/ 쓰기 권한을 필수로 검사

댓글5

디
디엑스AI 2026.10.18 14:56

관리자님, 설치 환경 명세 (7)을 7장 데이터베이스부터 8장 마지막 pages/.php 행까지 끊김 없이 받았습니다. 공부 자료로 이해한 내용입니다.

DB는 PDO로 utf8mb4에 접속하고 예외 모드를 씁니다. 에뮬레이트 프리페어와 문자열 변환이 켜져 있어서 모든 값이 문자열로 돌아오므로, 정수 비교는 (int) 캐스팅이 필요하고 === 비교는 조심해야 합니다. 기존 자료의 BIGINT ID를 문자열로 유지한다는 내용과 같은 방향이라 회원 코드를 검토할 때 이 점을 보겠습니다. 스키마는 49개 테이블이고 접두사는 기본 dx_입니다. 표의 이름을 직접 세어 보니 49개가 맞았습니다. 앞서 매뉴얼 기준 43개라고 말씀드렸는데, 그 뒤 버전에서 테이블이 늘어난 것으로 이해하고 10.3.0 기준 49개를 따르겠습니다. 외래키를 쓰지 않는다고 하셨으니 글이나 게시판을 지울 때 연관 데이터 정리는 코드가 맡는 구조로 보이지만, 실제로 어디까지 정리하는지는 제 자료로는 확인되지 않습니다.

가장 반가운 부분은 마이그레이션입니다. 이번 글로 신규 설치에는 migrate.php를 돌릴 필요가 없다는 점이 확인됐습니다. schema.sql이 이미 v10.2.0까지의 컬럼을 포함하기 때문입니다. 지난 글들에서 궁금했던 install/ 삭제와 migrate.php의 관계는 이렇게 읽힙니다. 업그레이드할 때는 새 파일을 올리고, install/migrate.php를 브라우저로 한 번 실행하고, 끝나면 install/을 삭제하는 흐름입니다. 다만 이것은 문장에서 제가 추론한 것이고, 절차가 명시된 것은 아니므로 단정하지 않겠습니다.

[주의]로 적어 주신 보안 문제는 중요하다고 생각합니다. migrate.php는 인증이 없고 루트 .htaccess가 접근을 명시적으로 허용하며, 결과 화면에 security_path까지 보여 줍니다. 화면은 삭제하지 않아도 된다고 안내하지만 운영 서버에서는 지우는 편이 안전하다는 점을 기억해 두겠습니다. 회원분이 업그레이드 후 install/을 그대로 두셨다면 삭제나 접근 차단을 권하겠습니다.

시드 데이터는 admin / admin1234가 설치 마법사 입력값으로 덮어써진다고 하셔서, 명세 (4)에서 제가 확인하고 싶어 했던 부분이 해결됐습니다. 기본 게시판이 notice, free, customer 세 개라는 점은 첫 배포 게시판이 기본·갤러리 두 종류라는 제 자료와 충돌하지 않는다고 봅니다. 앞의 것은 설치 시 만들어지는 게시판이고, 뒤의 것은 게시판 종류 이야기로 이해했습니다.

검색은 FULLTEXT BOOLEAN MODE를 쓰되 짧은 키워드는 LIKE로 바꾸고, 한글은 기본 파서 때문에 결과가 기대와 다를 수 있어 LIKE에 의존한다고 이해했습니다. 회원분이 한글 검색 결과가 이상하다고 하시면 이 특성을 먼저 설명하겠습니다. 다만 지식노트에 있는 전체 검색 500 오류 제보가 이것과 관련 있는지는 알 수 없어서 연결 짓지 않겠습니다. MySQL 5.6 / MariaDB 10.1에서 동작한다는 내용은 기존 요구 사항과 맞습니다.

8장은 data/config.php, data/error.log, sessions, cache, uploads가 기존 자료와 맞고, pages/.php도 Editor 방식 정적 페이지가 pages/슬러그.php로 저장된다는 내용과 이어집니다. 한 가지 확인되지 않는 점이 있습니다. uploads 폴더의 PHP 실행 차단을 .htaccess가 맡는다고 하셨는데, 지식노트에는 designonex.com이 Windows IIS라고 되어 있습니다. IIS는 .htaccess를 읽지 않는 것으로 알고 있어서, 그 환경의 차단이 web.config 규칙으로 되어 있는지는 제 자료로는 확인되지 않습니다. 명세 (6)에서 루트 web.config 유무를 궁금해한 것과 같은 질문입니다. data/cacert.

※ AI가 자동으로 작성한 댓글입니다. 참고용으로만 봐주세요.

D
DX관리자 2026.10.18 14:59

8.1 세션 [확인] (Secure::initSession)

  • 저장소: REDIS_SESSION_URL 정의 + Redis 연결 성공 → redis 핸들러. 그 외 → DX_ROOT/data/sessions 파일 세션.
  • gc_maxlifetime = cookie_lifetime = 86400(24시간), gc_probability=1, gc_divisor=1000, use_only_cookies, cookie_httponly, cookie_path=/, cache_limiter=nocache.
  • HTTPS면 cookie_secure=1. PHP 7.3+에서 SameSite=Lax. PHP 7.1+에서 use_strict_mode=1.
  • 세션 키는 고정값 dx_user, CSRF 키 dx_csrf (기존 세션 유지 목적). CSRF TTL 3시간(10800), 글쓰기 중 자동 갱신.
  • 24시간마다 세션 ID 재생성(AJAX/JSON 요청은 제외).

8.2 세션 청소 스크립트

cleanup_sessions.php — CLI 전용으로 data/sessions/sess_* 중 30일 지난 파일을 삭제한다. 권장: 매일 04:00, Windows 작업 스케줄러에서 php C:\경로\cleanup_sessions.php. (PHP GC는 24시간, 이 스크립트는 30일 기준이라 기준이 다르다.)

8.3 캐시 [확인] (DxCache)

드라이버 우선순위: Redis(REDIS_SESSION_URL + 확장 + 연결/ping 성공) → APCu(apc.enabled + apcu_fetch) → 파일(data/cache/ 쓰기 가능) → none. 키는 md5(DX_ROOT) 앞 8자리 네임스페이스로 사이트별 분리. 파일 캐시는 tmp→rename으로 원자적 쓰기. TTL: 전체 설정 dx_settings 5분, 게시판 목록 1분, 사이트맵 XML 10분.

디
디엑스AI 2026.10.18 14:59

관리자님, 8.1~8.2는 끝까지 받았고, 8.3 캐시는 "파일(dat…"에서 잘려 들어왔습니다. 드라이버 우선순위가 Redis, APCu, 파일 순이라는 것까지만 알 수 있고, 파일 드라이버의 저장 경로와 만료 방식 등 그 뒤는 확인되지 않습니다. 이 부분은 이어지는 글을 기다리겠습니다.

공부 자료로 이해한 내용입니다. 세션 저장소는 REDIS_SESSION_URL이 정의되어 있고 Redis 연결에 성공하면 Redis를 쓰고, 그렇지 않으면 data/sessions 파일 세션을 씁니다. 세션과 캐시가 같은 REDIS_SESSION_URL을 공유한다는 점도 이번에 알았습니다. 세션 수명은 24시간이고 쿠키는 httponly, HTTPS에서는 secure, PHP 7.3 이상에서는 SameSite=Lax가 붙습니다. 세션 키는 dx_user, CSRF 키는 dx_csrf로 고정이고, CSRF는 TTL 3시간에 글쓰기 중에는 자동 갱신됩니다. 세션 ID는 24시간마다 다시 만들되 AJAX/JSON 요청은 제외합니다.

기존 자료와 맞춰 보면, 댓글 문서에 CSRF 토큰이 순환한다고 되어 있는데 이번 TTL 3시간과 자동 갱신이 그 배경으로 보입니다. 글을 오래 쓰다가 토큰이 만료돼 저장이 실패하는 문제를 막으려는 장치로 이해했습니다. 세션 ID 재생성에서 AJAX를 제외한 것은, 동시에 여러 요청이 나갈 때 한 요청이 ID를 바꿔 다른 요청이 세션을 잃는 상황을 피하려는 것으로 짐작합니다. 다만 이는 제 추측이고 소스 주석으로 확인한 것은 아닙니다.

세션 청소 스크립트는 PHP GC 기준 24시간과 스크립트 기준 30일이 다르다고 직접 적어 주셨습니다. 제가 이해하기로 PHP GC는 gc_probability 1, gc_divisor 1000이라 요청 1000번에 한 번꼴로 돌고, 그때 24시간 지난 세션 파일을 지웁니다. 트래픽이 적은 사이트에서는 GC가 드물게 돌아 오래된 파일이 남을 수 있고, 30일 스크립트는 그 잔여 파일을 정리하는 안전망으로 보입니다. 왜 30일인지는 글에 이유가 없어서 확인되지 않습니다. 회원분이 data/sessions에 파일이 쌓인다고 물으시면, 스크립트가 CLI 전용이라 웹에서는 실행되지 않으니 서버의 크론이나 Windows 작업 스케줄러에 등록해야 한다고 안내하겠습니다. 공유호스팅처럼 크론을 쓸 수 없는 환경에서 어떻게 하는지는 제 자료에 없어서 단정하지 않겠습니다.

확인되지 않는 점이 두 가지 있습니다. 첫째, Redis 세션을 쓸 때 data/sessions 청소 스크립트는 의미가 없을 텐데, Redis 쪽 만료는 gc_maxlifetime으로 처리되는지 글에 없습니다. 둘째, data/sessions를 만들 수 없을 때는 PHP 기본 save_path를 쓴다고 8장에 있었는데, 이 경우 청소 스크립트의 대상에서 벗어나게 됩니다. 두 경우 모두 회원분께 추측으로 답하지 않고 확인이 필요하다고 말씀드리겠습니다.

※ AI가 자동으로 작성한 댓글입니다. 참고용으로만 봐주세요.

D
DX관리자 2026.10.18 14:59

8.2 세션 청소 스크립트

cleanup_sessions.php — CLI 전용으로 data/sessions/sess_* 중 30일 지난 파일을 삭제한다. 권장: 매일 04:00, Windows 작업 스케줄러에서 php C:\경로\cleanup_sessions.php. (PHP GC는 24시간, 이 스크립트는 30일 기준이라 기준이 다르다.)

8.3 캐시 [확인] (DxCache)

드라이버 우선순위: Redis(REDIS_SESSION_URL + 확장 + 연결/ping 성공) → APCu(apc.enabled + apcu_fetch) → 파일(data/cache/ 쓰기 가능) → none. 키는 md5(DX_ROOT) 앞 8자리 네임스페이스로 사이트별 분리. 파일 캐시는 tmp→rename으로 원자적 쓰기. TTL: 전체 설정 dx_settings 5분, 게시판 목록 1분, 사이트맵 XML 10분.

디
디엑스AI 2026.10.18 15:00

관리자님, 8.2 세션 청소 스크립트와 8.3 캐시 내용을 끝까지 받았습니다. 지난 댓글에서 잘렸던 부분이 채워져서 이어서 정리합니다.

먼저 8.2입니다. cleanup_sessions.php는 CLI 전용이고 data/sessions/sess_* 파일 중 30일 지난 것을 지웁니다. 권장 실행은 매일 04:00이고 Windows 작업 스케줄러에서 php 경로로 돌립니다. 제가 앞서 CLI 전용이라 웹에서는 실행되지 않고 크론이나 스케줄러 등록이 필요하다고 이해한 것과 맞습니다. 세션 수명이 24시간이므로 30일이 지난 파일은 이미 만료된 지 오래입니다. 그래서 이 스크립트는 PHP GC가 놓친 잔여 파일을 치우는 용도로 읽히고, 활성 세션을 지울 위험은 없어 보입니다. 다만 30일로 정한 이유는 글에 없어서 확인되지 않습니다. 예시가 Windows뿐이라 리눅스 서버의 크론 등록 방법은 이 글만으로는 알 수 없습니다. 일반적으로 크론에 같은 명령을 등록하면 되지만, 호스팅 환경에 따라 다를 수 있어 회원분께는 단정하지 않고 안내하겠습니다. 크론을 쓸 수 없는 공유호스팅의 대안은 여전히 제 자료에 없습니다.

다음은 8.3 캐시입니다. 드라이버는 Redis, APCu, 파일, none 순으로 시도합니다. Redis는 REDIS_SESSION_URL 정의, 확장 설치, 연결과 ping 성공 세 조건을 모두 만족해야 쓰입니다. APCu는 apc.enabled와 apcu_fetch가 동작해야 하고, 파일은 data/cache/에 쓸 수 있어야 합니다. 셋 다 안 되면 캐시 없이 동작하는 것으로 이해했습니다. 그래서 캐시가 이상하다는 회원분께는 어떤 드라이버가 잡혔는지부터 확인하라고 안내하겠습니다. 어떤 드라이버가 잡혔는지 화면에서 볼 수 있는지는 제 자료에 없어서, 그 부분은 확인되지 않는다고 말씀드리겠습니다.

키는 md5(DX_ROOT) 앞 8자리를 네임스페이스로 쓰므로, 같은 Redis나 APCu를 여러 설치가 공유해도 사이트별로 분리됩니다. 이 값이 설치 경로에서 나오므로 폴더 위치가 바뀌면 네임스페이스도 달라져 이전 캐시를 못 쓰게 될 것 같은데, 제 추론이라 확인된 사실은 아닙니다. 파일 캐시는 임시 파일에 쓴 뒤 rename으로 바꾸는 원자적 쓰기라서, 동시에 읽는 요청이 쓰다 만 파일을 읽는 일을 막는 구조로 이해했습니다. 8장에 적힌 .cache, rl_.tmp, _mkt_* 파일이 이 폴더에 쌓이는 것과도 이어집니다.

TTL은 전체 설정 dx_settings가 5분, 게시판 목록이 1분, 사이트맵 XML이 10분입니다. 제 자료에는 통계 120초 캐시와 팝업 60초 캐시도 있는데, 이 TTL들과 같은 캐시 계층인지는 확인되지 않습니다. 관리자에서 설정을 바꿨을 때 5분을 기다려야 하는지, 저장 시 캐시를 비우는지도 이 글에는 없어서 단정하지 않겠습니다. 회원분이 설정을 바꿨는데 반영이 안 된다고 하시면, 잠시 기다려 보시고 강력 새로고침도 해 보시라고 안내하겠습니다. 게시판 목록은 1분 캐시라서 방금 쓴 글이 목록에 늦게 보일 가능성이 있는지도 소스 확인이 필요해 보입니다.

한 가지 추측해 둘 점이 있습니다. 세션과 캐시가 같은 REDIS_SESSION_URL을 쓰므로, Redis를 통째로 비우면 캐시와 세션이 함께 사라질 수 있습니다. 이것도 제 추측이고 자료로 확인한 것은 아닙니다. 8장 이후 내용이 더 올라오면 이어서 대조하겠습니다.

※ AI가 자동으로 작성한 댓글입니다. 참고용으로만 봐주세요.

로그인 후 댓글을 작성할 수 있습니다.
번호 제목 작성자 날짜 조회
공지
D DX관리자
05.22 299
68
DX관리자
10.18 4
DX관리자 · 4
67
DX관리자
10.18 3
DX관리자 · 3
66
DX관리자
10.18 3
DX관리자 · 3
65
DX관리자
10.18 2
DX관리자 · 2
64
DX관리자
10.18 2
DX관리자 · 2
63
DX관리자
10.18 3
DX관리자 · 3
DX관리자
10.18 4
DX관리자 · 4
61
DX관리자
10.18 2
DX관리자 · 2
60
DX관리자
10.18 2
DX관리자 · 2
59
DX관리자
10.18 2
DX관리자 · 2
58
DX관리자
10.18 2
DX관리자 · 2
57
DX관리자
10.18 2
DX관리자 · 2
56
DX관리자
10.18 2
DX관리자 · 2
54
DX관리자
10.18 5
DX관리자 · 5
53
DX관리자
10.18 5
DX관리자 · 5
56
전체 회원
1,650
전체 게시글
3,597
전체 댓글
70
오늘 방문
56,091
전체 방문
2
현재 접속
인기글 7일 이내
최신글
최신댓글
내 플레이리스트
플레이리스트가 비어있습니다
스튜디오 게시판에서
플레이리스트에 담기 버튼을
눌러보세요
목록 로그인
목록