PHP에서 서버 시간 오차 문제 해결하기

프리터코더·2025년 6월 1일
0

php 문제 해결

목록 보기
52/79

서버 시간 설정이 잘못되거나 타임존이 맞지 않으면 로그 기록, 세션 만료, 예약 기능 등에서 문제가 발생할 수 있습니다. 정확한 시간 처리를 위한 해결책들을 알아보겠습니다.

1. 타임존 설정

<?php
// 한국 시간으로 설정
date_default_timezone_set('Asia/Seoul');

// 현재 시간 확인
echo "현재 시간: " . date('Y-m-d H:i:s') . "\n";
echo "타임존: " . date_default_timezone_get() . "\n";

// UTC 시간도 함께 표시
echo "UTC 시간: " . gmdate('Y-m-d H:i:s') . "\n";
?>

2. DateTime 클래스로 타임존 처리

<?php
// 서울 시간으로 DateTime 객체 생성
$seoul_time = new DateTime('now', new DateTimeZone('Asia/Seoul'));
echo "서울: " . $seoul_time->format('Y-m-d H:i:s') . "\n";

// 다른 타임존으로 변환
$utc_time = clone $seoul_time;
$utc_time->setTimezone(new DateTimeZone('UTC'));
echo "UTC: " . $utc_time->format('Y-m-d H:i:s') . "\n";

$ny_time = clone $seoul_time;
$ny_time->setTimezone(new DateTimeZone('America/New_York'));
echo "뉴욕: " . $ny_time->format('Y-m-d H:i:s') . "\n";
?>

3. 데이터베이스 시간 동기화

<?php
// MySQL 타임존 설정
$pdo = new PDO($dsn, $username, $password);

// 세션 타임존 설정
$pdo->exec("SET time_zone = '+09:00'"); // 한국 시간

// 또는 시스템 타임존 사용
$pdo->exec("SET time_zone = 'Asia/Seoul'");

// 현재 DB 시간 확인
$stmt = $pdo->query("SELECT NOW() as db_time, UTC_TIMESTAMP() as utc_time");
$result = $stmt->fetch();

echo "DB 시간: " . $result['db_time'] . "\n";
echo "DB UTC: " . $result['utc_time'] . "\n";
echo "PHP 시간: " . date('Y-m-d H:i:s') . "\n";
?>

4. NTP 서버로 시간 동기화 확인

<?php
function checkTimeSync($ntp_server = 'time.google.com') {
    $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
    socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, ['sec' => 5, 'usec' => 0]);
    
    // NTP 패킷 생성 (간단한 요청)
    $packet = chr(0x23) . str_repeat(chr(0), 47);
    
    if (socket_sendto($socket, $packet, 48, 0, $ntp_server, 123)) {
        $response = '';
        if (socket_recvfrom($socket, $response, 48, 0, $ntp_server, $port)) {
            // NTP 타임스탬프 파싱 (간단화)
            $ntp_time = time(); // 실제로는 복잡한 계산 필요
            $local_time = time();
            $diff = abs($ntp_time - $local_time);
            
            echo "시간 차이: {$diff}초\n";
            return $diff < 60; // 1분 이내 차이면 정상
        }
    }
    
    socket_close($socket);
    return false;
}

if (checkTimeSync()) {
    echo "시간 동기화 정상\n";
} else {
    echo "시간 동기화 필요\n";
}
?>

5. 시간 유틸리티 클래스

<?php
class TimeUtil {
    private static $default_timezone = 'Asia/Seoul';
    
    public static function now($timezone = null) {
        $tz = $timezone ?: self::$default_timezone;
        return new DateTime('now', new DateTimeZone($tz));
    }
    
    public static function toUtc($datetime) {
        if (is_string($datetime)) {
            $datetime = new DateTime($datetime);
        }
        return $datetime->setTimezone(new DateTimeZone('UTC'));
    }
    
    public static function fromUtc($utc_datetime, $target_timezone = null) {
        $tz = $target_timezone ?: self::$default_timezone;
        if (is_string($utc_datetime)) {
            $datetime = new DateTime($utc_datetime, new DateTimeZone('UTC'));
        } else {
            $datetime = clone $utc_datetime;
        }
        return $datetime->setTimezone(new DateTimeZone($tz));
    }
    
    public static function formatForDb($datetime = null) {
        $dt = $datetime ?: self::now();
        return self::toUtc($dt)->format('Y-m-d H:i:s');
    }
}

// 사용 예시
echo TimeUtil::now()->format('Y-m-d H:i:s') . "\n";
echo TimeUtil::formatForDb() . "\n";
?>

6. 세션 타임아웃 정확한 처리

<?php
session_start();

// 타임존 설정
date_default_timezone_set('Asia/Seoul');

// 세션 타임아웃 체크 (30분)
$timeout_duration = 1800;

if (isset($_SESSION['last_activity'])) {
    $elapsed_time = time() - $_SESSION['last_activity'];
    
    if ($elapsed_time > $timeout_duration) {
        session_destroy();
        echo "세션이 만료되었습니다.\n";
        echo "마지막 활동: " . date('Y-m-d H:i:s', $_SESSION['last_activity']) . "\n";
        echo "현재 시간: " . date('Y-m-d H:i:s') . "\n";
        exit;
    }
}

$_SESSION['last_activity'] = time();
echo "세션 활성화됨: " . date('Y-m-d H:i:s') . "\n";
?>

7. 로그 시간 정규화

<?php
class Logger {
    private $timezone;
    
    public function __construct($timezone = 'Asia/Seoul') {
        $this->timezone = new DateTimeZone($timezone);
    }
    
    public function log($message, $level = 'INFO') {
        $timestamp = new DateTime('now', $this->timezone);
        $log_entry = sprintf(
            "[%s] [%s] %s\n",
            $timestamp->format('Y-m-d H:i:s T'),
            $level,
            $message
        );
        
        file_put_contents('app.log', $log_entry, FILE_APPEND | LOCK_EX);
    }
    
    public function logWithUtc($message, $level = 'INFO') {
        $local_time = new DateTime('now', $this->timezone);
        $utc_time = clone $local_time;
        $utc_time->setTimezone(new DateTimeZone('UTC'));
        
        $log_entry = sprintf(
            "[%s] [%s UTC] [%s] %s\n",
            $local_time->format('Y-m-d H:i:s T'),
            $utc_time->format('Y-m-d H:i:s'),
            $level,
            $message
        );
        
        file_put_contents('app.log', $log_entry, FILE_APPEND | LOCK_EX);
    }
}

$logger = new Logger();
$logger->log('애플리케이션 시작');
$logger->logWithUtc('중요한 이벤트 발생');
?>

8. 시간 검증 함수

<?php
function validateServerTime() {
    $issues = [];
    
    // 1. 타임존 설정 확인
    $timezone = date_default_timezone_get();
    if ($timezone === 'UTC' && !in_array('UTC', ['UTC'])) {
        $issues[] = "타임존이 UTC로 설정됨. 지역 시간 설정 필요";
    }
    
    // 2. 시스템 시간과 PHP 시간 비교
    $php_time = time();
    $system_time = trim(shell_exec('date +%s'));
    if (abs($php_time - $system_time) > 5) {
        $issues[] = "PHP 시간과 시스템 시간 불일치";
    }
    
    // 3. 데이터베이스 시간 확인 (MySQL 예시)
    try {
        $pdo = new PDO($dsn, $username, $password);
        $stmt = $pdo->query("SELECT UNIX_TIMESTAMP() as db_time");
        $db_time = $stmt->fetchColumn();
        
        if (abs($php_time - $db_time) > 10) {
            $issues[] = "PHP 시간과 DB 시간 불일치";
        }
    } catch (Exception $e) {
        $issues[] = "DB 시간 확인 실패: " . $e->getMessage();
    }
    
    return $issues;
}

$issues = validateServerTime();
if (empty($issues)) {
    echo "시간 설정 정상\n";
} else {
    echo "시간 설정 문제:\n";
    foreach ($issues as $issue) {
        echo "- $issue\n";
    }
}
?>

핵심 포인트

  • 타임존 설정을 애플리케이션 초기에 명확히 지정
  • 데이터베이스 저장은 UTC로, 표시는 사용자 타임존으로
  • DateTime 클래스 사용으로 타임존 변환 안전하게 처리
  • 로그와 세션에서 일관된 시간 기준 사용
  • 정기적인 시간 동기화 상태 모니터링
profile
일용직 개발자. freetercoder@gmail.com

0개의 댓글