본문 바로가기

컴퓨터/PHP

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

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


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


<?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' 카테고리의 다른 글

PHP로 구현한 파일 캐시 클래스  (0) 2018.12.12
모바일에서만 보이는 이미지  (0) 2016.08.19
Codeigniter hook로 권한 체크하기  (0) 2016.02.17

태그