본문 바로가기

컴퓨터/PHP

PHP로 구현한 파일 캐시 클래스

반응형

앞선 글에서 캐시가 무엇인지와 캐싱을 사용하는 이유에 대해서 알아보았다.


이 게시물에서는 PHP를 이용해서 파일 캐시를 직접 구현한 클래스를 소개하고자 한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
<?php
  
class Cache
{
    // 실제 파일이 저장된 폴더
    private $real_file_dir;
    // 캐시 파일이 저장될 폴더
    private $cache_file_dir;
    // 캐시 만료 시간 (초 단위)
    private $timeout;
  
    public function __construct($real_dir, $cache_dir, $timeout)
    {
        $this->real_file_dir = $real_dir;
        $this->cache_file_dir = $cache_dir;
        $this->timeout = $timeout;
  
        // 캐시 폴더가 존재하지 않는 경우 폴더 생성
        if(!file_exists($cache_dir))
        {
            mkdir($cache_dir, 0777, TRUE);
        }
    }
  
    // 파일 출력 가져오기
    private static function _get_file_data($filepath, $render = FALSE)
    {
        if(!file_exists($filepath))
        {
            return NULL;
        }
        if($render === TRUE)
        {
            // PHP 코드를 실행한 결과를 반환
            ob_start();
            include $filepath;
            $content = ob_get_clean();
            return $content;   
        }
        else
        {
            // 그냥 파일을 읽어서 나온 결과를 반환
            return file_get_contents($filepath);
        }
    }
  
    // 캐시 파일 이름 생성 (기존 이름에서 확장자 부분을 제거하고 앞쪽에 cache_를 붙인다)
    private static function _convert_cache_filename($filename)
    {
        return 'cache_' . substr($filename, 0, strrpos($filename, '.'));
    }
  
    // 실제 파일이 위치한 경로
    private function _get_real_file_path($filename)
    {
        return $this->real_file_dir . '/' . $filename;
    }
  
    // 캐시 파일이 위치한 경로
    private function _get_cache_file_path($filename)
    {
        return $this->cache_file_dir . '/' . $filename;
    }
  
    // 실제 파일 출력 가지고 오기
    private function _get_real_file_data($filename)
    {
        return self::_get_file_data($this->_get_real_file_path($filename), TRUE);
    }
  
    // 캐시 파일 내용 가지고 오기
    private function _get_cache_file_data($filename)
    {
        return self::_get_file_data($this->_get_cache_file_path($filename), FALSE);
    }
  
    // 캐시 파일이 생성된 시간 가지고 오기
    private function _get_cache_time($filename)
    {
        $filepath = $this->_get_cache_file_path($filename);
        if(!file_exists($filepath))
        {
            return 0;
        }
        else
        {
            return filemtime($filepath);
        }
    }
  
    // 캐시 파일 생성하기
    private function _create_cache_file($filename)
    {
        $cache_filename = $this->_convert_cache_filename($filename);
        $cache_filepath = $this->_get_cache_file_path($cache_filename);
  
        $content = $this->_get_real_file_data($filename);
  
        $f = fopen($cache_filepath, "w");
        fwrite($f, $content);
        fclose($f);
  
        return $content;
    }
  
    // 캐시 파일들 삭제하기
    public function clear_cache()
    {
        $cache_files = glob($this->cache_file_dir . '/*');
        foreach ($cache_files as $file)
        {
            if(is_file($file))
            {
                unlink($file);
            }
        }
    }
  
    // 파일 내용 읽어오기.
    // 캐싱이 된 경우 캐시 파일을 출력
    // 실패한 경우에는 캐시 파일을 생성하고 해당 내용을 출력
    public function get_content($filename, $timeout = 0)
    {
        if($timeout === 0) $timeout = $this->timeout;
        $cache_filename = self::_convert_cache_filename($filename);
  
        $cache_time = $this->_get_cache_time($cache_filename);
        $current_time = time();
  
        // timeout이 초과한 경우 캐시 파일 재생성
        if($current_time - $cache_time > $timeout)
        {
            return $this->_create_cache_file($filename);
        }
        else
        {
            return $this->_get_cache_file_data($cache_filename);
        }
    }
}
  
// 60초 캐시 클래스 생성
$cache = new Cache(__DIR__ . '/real/file/path', __DIR__ . '/cache/file/path', 60);
// file.php를 캐싱해서 읽어오기 (기본 값 사용)
$result = $cache->get_content('file.php');
echo $result;
  
// file_10s.php를 캐싱해서 읽어오기 (10초)
$result = $cache->get_content('file_10s.php', 10);
echo $result;
  
// 캐시 삭제
$cache->clear_cache();


따로 시간을 정해주지 않으면 처음 클래스를 생성할 때 선언한 만료 시간을 사용하며 캐시 파일이 생성된 시간을 기준으로 만료 시간을 체크하도록 구현한 것이다.


참고로 캐시가 적용되는 폴더에는 다른 파일을 넣어두면 캐시를 삭제하는 과정에서 사라질 수도 있으니 단독으로 사용할 수 있도록 하여야 한다. 그리고 클래스로 구현이 되어 있기 때문에 캐시가 생성되는 폴더의 경로를 따로 설정할 수 있다는 장점이 있다.


물론 실제 운영 환경에서 적용하기에는 예외처리도 되어있지 않는 등의 문제점이 있긴 하나 간단한 용도로 쓰는 것이라면 충분히 괜찮다고 할 수 있다.


현재 직접 운영하고 있는 카카오톡 봇에 적용해본 결과 잘 동작하는 것을 확인할 수 있었다.

반응형

'컴퓨터 > PHP' 카테고리의 다른 글