* * * * */ declare(strict_types=1); if (session_status() === PHP_SESSION_NONE) { session_start(); } // 1. 요청 방식 및 파라미터 검증 if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); exit('허용되지 않는 요청 방식입니다.'); } $memberId = trim((string)($_POST['member_id'] ?? '')); $sysCompCode = trim((string)($_POST['sys_comp_code'] ?? '')); // 필수 값이 없으면 로그인 페이지로 이동 if ($memberId === '' || $sysCompCode === '') { header("Location: /skin/login.php"); exit; } require_once __DIR__ . '/db_conn.php'; try { $pdo = db_conn(); // --- [일일 통합 동기화 체크/실행] --- // 동기화 실패가 사용자 로그인 자체를 막지 않도록 분리 처리한다. $lockAcquired = false; try { $stmtLock = $pdo->query("SELECT GET_LOCK('edu_users_daily_sync', 5)"); $lockAcquired = ((int)$stmtLock->fetchColumn() === 1); if ($lockAcquired) { $stmtCheck = $pdo->query( "SELECT EXISTS( SELECT 1 FROM edu_users_daily_logs WHERE DATE(injection_at) = CURDATE() )" ); $isDone = ((int)$stmtCheck->fetchColumn() === 1); if (!$isDone) { set_time_limit(0); $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http'; $host = $_SERVER['HTTP_HOST'] ?? 'localhost'; $syncUrl = $scheme . '://' . $host . '/ajax/get_users_info.php'; $chSync = curl_init(); curl_setopt($chSync, CURLOPT_URL, $syncUrl); curl_setopt($chSync, CURLOPT_RETURNTRANSFER, true); curl_setopt($chSync, CURLOPT_TIMEOUT, 1800); curl_setopt($chSync, CURLOPT_HTTPHEADER, ["Accept: text/html"]); $syncResponse = curl_exec($chSync); $syncHttpCode = curl_getinfo($chSync, CURLINFO_HTTP_CODE); $syncError = curl_error($chSync); curl_close($chSync); if ($syncResponse === false || $syncHttpCode !== 200) { throw new RuntimeException('daily sync API failed: http=' . $syncHttpCode . ', err=' . $syncError); } $stmtDaily = $pdo->prepare("CALL proc_edu_users_daily(?)"); $stmtDaily->execute([$memberId]); } } else { error_log('[entry.php] daily sync lock not acquired, skip sync this request.'); } } catch (Throwable $syncEx) { error_log('[entry.php] daily sync failed: ' . $syncEx->getMessage()); } finally { if ($lockAcquired) { try { $pdo->query("SELECT RELEASE_LOCK('edu_users_daily_sync')"); } catch (Throwable $unlockEx) { error_log('[entry.php] release lock failed: ' . $unlockEx->getMessage()); } } } // --- [일일 통합 동기화 체크/실행 끝] --- // 2. 사용자 조회 (member_id, sys_comp_code 기반) $stmt = $pdo->prepare( 'SELECT member_id, sys_comp_code, name, rank_name, intro_flag FROM edu_users WHERE member_id = ? AND sys_comp_code = ? LIMIT 1' ); $stmt = $pdo->prepare( " SELECT u.member_id, u.sys_comp_code, u.name, u.rank_name, u.auth_level, u.intro_flag, ec.code, ec.code_name as comp_name FROM edu_users u LEFT JOIN ( SELECT code,code_name FROM edu_codes WHERE group_code = 'CO100' ) ec ON ec.code = u.belong_comp WHERE u.member_id = ? AND u.sys_comp_code = ? LIMIT 1 " ); $stmt->execute([$memberId, $sysCompCode]); $user = $stmt->fetch(PDO::FETCH_ASSOC); // 사용자가 없으면 로그인 페이지로 이동 if (!$user) { header("Location: http://erp.baroncs.co.kr/mobile/sys/controller/Study_controller.php"); exit; } // --- [세션 초기화 단계] --- // 새로운 사용자의 정보를 담기 전에 기존 세션 변수를 모두 제거합니다. session_unset(); // 보안을 위해 세션 ID를 새로 발급합니다. (기존 세션 데이터 삭제 포함) session_regenerate_id(true); // ------------------------- // 3. 변수 정리 및 세션 저장 (요청하신 규칙 엄격 적용) $U_member_id = $user['member_id']; $U_sys_comp_code = $user['sys_comp_code']; $U_name = $user['name']; $U_rank_name = $user['rank_name']; $U_auth_level = (string)($user['auth_level'] ?? ''); $U_comp_name = $user['comp_name']; $U_intro_flag = (string)$user['intro_flag']; // '0' 또는 '1' $_SESSION['member_id'] = $U_member_id; $_SESSION['comp_name'] = $U_comp_name; $_SESSION['sys_comp_code'] = $U_sys_comp_code; $_SESSION['member_name'] = $U_name; $_SESSION['name'] = $U_name; $_SESSION['rank_name'] = $U_rank_name; $_SESSION['auth_level'] = $U_auth_level; $_SESSION['intro_flag'] = $U_intro_flag; // 2026-04-02 권오재 추가.--- [추가: 접속 이력 프로시저 호출] --- // 1. 정보 수집 $ip_address = $_SERVER['REMOTE_ADDR']; $user_agent = $_SERVER['HTTP_USER_AGENT']; // OS 및 디바이스 판별 (간단한 예시) $os_name = 'Unknown OS'; if (preg_match('/windows|win32/i', $user_agent)) $os_name = 'Windows'; else if (preg_match('/macintosh|mac os x/i', $user_agent)) $os_name = 'Mac OS'; else if (preg_match('/android/i', $user_agent)) $os_name = 'Android'; else if (preg_match('/iphone/i', $user_agent)) $os_name = 'iOS'; $device_type = (preg_match('/mobile|android|iphone|ipad/i', $user_agent)) ? 'Mobile' : 'PC'; // 브라우저명 추출 (Whale을 Chrome보다 우선 판별) $browser_name = 'Unknown Browser'; if (stripos($user_agent, 'Whale') !== false) $browser_name = 'Whale'; else if (stripos($user_agent, 'Edg') !== false || stripos($user_agent, 'Edge') !== false) $browser_name = 'Edge'; else if (stripos($user_agent, 'MSIE') !== false || stripos($user_agent, 'Trident') !== false) $browser_name = 'IE'; else if (stripos($user_agent, 'Chrome') !== false) $browser_name = 'Chrome'; else if (stripos($user_agent, 'Firefox') !== false) $browser_name = 'Firefox'; else if (stripos($user_agent, 'Safari') !== false) $browser_name = 'Safari'; // 2. 프로시저 실행 $stmtLog = $pdo->prepare("CALL proc_insert_edu_access_log(?, ?, ?, ?, ?, ?)"); $stmtLog->execute([ $_SESSION['member_id'], $_SESSION['sys_comp_code'], $ip_address, $os_name, $device_type, $browser_name ]); // 4. 리다이렉트 분기 및 DB 업데이트 if ($U_intro_flag === '1') { // 읽음 완료 상태: 메인으로 이동 header("Location: /skin/index.php"); exit; } else { // 읽지 않음(0) 상태: DB 업데이트 후 인트로로 이동 $stmtUpdate = $pdo->prepare( 'UPDATE edu_users SET intro_flag = "1" WHERE member_id = ? AND sys_comp_code = ? AND intro_flag = "0"' ); $stmtUpdate->execute([$U_member_id, $U_sys_comp_code]); // 업데이트 성공 후 세션 동기화 (인트로 이동 직전) $_SESSION['intro_flag'] = '1'; header("Location: /skin/intro.php"); exit; } } catch (Exception $e) { error_log("Entry Error: " . $e->getMessage()); exit('시스템 오류가 발생했습니다. 잠시 후 다시 시도해주세요.'); }