고아 테이블 탐지, DB 대시보드/최적화, 비대 로그 정리, DB 백업, 테이블 점검을 한 화면에서 관리하는 라이믹스 관리자 도구
information_schema.tables에서 별칭(AS) 없이 그대로 가져온 table_name/table_rows/engine 컬럼만 문제였고, AS size_mb처럼 명시적으로 별칭을 준 컬럼은 항상 정상이었던 것으로 확인 — MySQL/MariaDB 서버 버전·설정에 따라 별칭 없는 information_schema 컬럼명이 다른 대소문자로 반환될 수 있어 PDO 접근이 어긋난 것. 같은 방식으로 테이블 목록을 얻는 DB 백업 기능도 조용히 빈 덤프를 만들었을 가능성이 있어 함께 수정.Call to a member function closeCursor() on bool 오류로 점검이 중단됨. 테이블별로 CHECK TABLE을 순차 실행하는 루프에서 특정 테이블 쿼리가 실패하면 코어 DB::query()가 내부 상태를 비정상적으로 남기는 경우가 있는 것으로 추정 — 정확한 코어 버전별 재현은 확인 못했지만, 테이블 하나의 실패가 전체 점검을 중단시켜서는 안 되므로 테이블별 호출을 try/catch로 감싸 나머지 테이블 점검은 계속 진행하도록 수정.if(!defined('__XE__')) exit(); 가드가 없었던 것을 발견 — 다른 BSplus 모듈과 달리 이 모듈만 누락. 라이믹스 루트 .htaccess가 modules/ 안의 일반 PHP 직접 실행까지는 막지 않는 구조라 전부 추가. 외부 크론 엔드포인트의 cron_key 비교도 !==에서 타이밍 공격에 안전한 hash_equals()로 교체.modules/*/schemas/*.xml만 훑어 소유 모듈을 판단하는 구조라, 애드온(addons/)이 만든 테이블은 항상 "고아"로 잘못 분류됨. 실사용 중 lef_moved_files(구버전 애드온 lua_external_file 소유 — bsplus_external_storage의 이동 기록 가져오기 기능이 아직 참조)가 고아 테이블로 표시되어 DROP 버튼이 노출되는 것을 발견. 알려진 애드온 소유 테이블 예외 목록을 추가해 고아 판정에서 제외하고 별도 "애드온 소유 테이블" 섹션으로 분리 표시(삭제 버튼 없음).Queue::addTaskAtInterval() 등록 + 외부 webcron(cron-job.org 등) 분당 1회 호출로 방문자 없이도 정확한 시각에 실행. 고유 키 기반 외부 크론 URL(procTablescannerCronRun) 신규 추가, 재발급 버튼 포함. mysqldump에 --single-transaction/--skip-lock-tables 옵션을 추가해 백업 중 서비스 락 대기 리스크 제거. 백업 경로가 files/attach/ 하위면 외부 노출 위험을 빨간 경고로 안내.DB::query()의 addPrefixes()가 FROM information_schema.tables를 FROM xe_information_schema.tables로 잘못 변환해 쿼리가 실패, 스키마 정의된 정상 테이블 120개 전부가 "미생성"으로 오판되던 문제 — SQL 키워드를 소문자로 작성해 대문자만 매칭하는 addPrefixes()를 우회하도록 수정.information_schema.tables에서 별칭 없이 그대로 셀렉트한 table_name/table_rows/engine 컬럼만 문제였고, AS size_mb처럼 명시적으로 별칭을 준 컬럼은 항상 정상 — 서버 버전·설정에 따라 별칭 없는 information_schema 컬럼명이 다른 대소문자로 반환될 수 있어 PDO::FETCH_OBJ/배열 키 접근이 대소문자 불일치로 비었던 것.model.php/admin.controller.php/class.php 전체 8곳에서 table_name/table_rows/engine에 자기 별칭(table_name as table_name 등)을 명시적으로 추가 — 서버/버전에 관계없이 항상 쿼리에 작성한 그대로의 컬럼명이 반환되도록 함.runBackup())도 같은 서버 환경에서는 조용히 빈 덤프를 만들었을 가능성이 있어 함께 수정됨.Call to a member function closeCursor() on bool 오류가 발생하며 점검이 실패함.CHECK TABLE을 순차 실행하는 루프에서, 특정 테이블(손상됐거나 접근 권한/엔진 문제가 있는 테이블)에 대한 쿼리가 실패하면 코어 DB::query()가 내부 상태를 비정상적으로 남기는 경우가 있어 다음 테이블 처리 시 죽는 것으로 보임. 정확한 코어 버전별 재현은 확인 못했지만, 테이블 하나의 실패가 전체 점검을 중단시켜서는 안 됨.CHECK TABLE 호출을 try/catch로 감싸 특정 테이블에서 예외가 나도 그 테이블만 "오류" 결과로 기록하고 나머지 테이블 점검은 계속 진행하도록 변경.if(!defined('__XE__')) exit(); 가드 누락 — 다른 BSplus 모듈들과 달리 이 모듈만 없었음. 라이믹스 루트 .htaccess가 modules/ 안의 일반 .php 직접 실행까지는 막아주지 않는 구조라(bsplus_external_storage vendor 이슈 때 확인된 것과 동일한 사정) 부트스트랩 없이 직접 실행될 위험을 막기 위해 5개 파일 모두 추가.procTablescannerCronRun(외부 스케줄러 전용 크론 엔드포인트)의 cron_key 비교를 !==에서 hash_equals()로 교체 — 타이밍 공격에 안전한 상수 시간 비교로 강화. 키 생성 자체는 이미 random_bytes(16)으로 안전했음.review_module의 "액션 파일 불일치" 경고 16건은 admin 전용 액션을 admin 파일에 분리하는 라이믹스의 정확한 관례로, 실제 문제 아닌 것으로 확인(known false-positive).modules/*/schemas/*.xml만 훑어서 테이블 소유 모듈을 판단하는데, 애드온(addons/)이 만든 테이블은 이 방식으로는 절대 찾을 수 없음 — 실제로 주인이 있는데도 "schema 없음, 모듈 불명 고아 테이블"로 잘못 분류되어 DROP 버튼이 노출됨.lef_moved_files(구버전 애드온 lua_external_file이 만든 이동 기록 테이블)가 고아 테이블로 표시됨. bsplus_external_storage 모듈의 "구버전 애드온 이동 기록 가져오기" 기능이 아직 이 테이블을 참조하므로, 여기서 DROP하면 예전 이동 기록을 영영 가져올 수 없게 됨.scanTables()에 알려진 애드온 소유 테이블 예외 목록($addon_tables) 추가 — 고아 판정에서 제외하고 새 "애드온 소유 테이블" 섹션에 별도 표시(삭제 버튼 없음, 정보 제공용).Queue::addTaskAtInterval() 등록 + 외부 webcron(cron-job.org 등) 분당 1회 호출로 방문자 없이도 설정 시각에 정확히 자동 백업 실행. 백업 예약 설정 저장 시 자동으로 Queue 태스크 등록/해제 시 취소, 등록 여부를 백업 탭 상태표에 실시간 표시.triggerAutoBackup()이 즉시 종료되도록 해 동일 시각 이중 실행 방지.procTablescannerCronRun) — 백업 탭 최초 접속 시 크론 키 자동 생성, 재발급 버튼 제공.--single-transaction(InnoDB 일관성 스냅샷, 테이블 락 없음), --skip-lock-tables, --routines --triggers.files/attach/ 하위인 경우 빨간 경고(Nginx 환경에서 .htaccess 차단이 동작하지 않아 SQL 덤프 외부 노출 위험) 표시, 웹 루트 하위(비attach)는 주황 주의, 웹 루트 외부는 안전 표시.send(true) 동기 전송으로 변경(Queue 환경에서도 즉시 발송 보장), setFrom() 추가, 본문 타입 text/plain 명시..htaccess 자동 생성, DB 비밀번호는 임시 .cnf 파일로 커맨드라인 노출 없이 처리.DB::query()의 addPrefixes()가 FROM information_schema.tables를 FROM xe_information_schema.tables로 잘못 변환해 쿼리가 실패, 스키마 정의 테이블 전체가 "missing" 판정되던 것 — SQL 키워드를 소문자(from, table 등)로 작성해 대문자 키워드만 매칭하는 addPrefixes()를 우회하도록 수정.deleted="true" 마이그레이션 삭제 마커가 붙은 테이블을 필터링하지 않아 "미생성" 오탐이 나던 문제, 스키마 XML 파일 하나에 테이블이 여러 개면 preg_match()가 첫 번째만 인식하던 문제(→ preg_match_all()로 교체), 최적화 탭에서 {number_format(...)}가 라이믹스 v1 템플릿 파서에서 함수 호출을 지원하지 않아 리터럴 문자열로 출력되던 문제(→ 모델에서 미리 포맷 후 table_rows_fmt 키로 전달) 모두 수정.$oDB->_query()/_fetch()) 전면 교체 → $oDB->query($sql, $params) + fetchAll(PDO::FETCH_OBJ), _XE_PATH_ → RX_BASEDIR 상수 교체.{@삼항연산자} 문법 대신 <!--@if--> 인라인 조건으로 교체, 스캔 탭 정상/코어 테이블 섹션 기본 접힘 처리로 이상 항목만 즉시 확인 가능하도록 개선.schemas/*.xml) 기반 고아 테이블 탐지 + DROP 기능.| PHP | 7.4 이상 (Rhymix 공식 최소 요구사항), 8.2 이상 권장. 상한선 없음. |
|---|---|
| Rhymix | 2.0.0 이상 권장. |
| DB | MySQL/MariaDB — DB 대시보드/최적화/점검 탭이 information_schema.tables 기반이라, 셸 접근이 제한된 공유 호스팅에서도 동작. mysqldump 미지원 환경은 백업이 PHP 순수 덤프로 자동 전환. |
| 라이선스 | GPLv2 (Rhymix 코어 및 다른 BSplus 모듈과 동일) |