코드
2018.12.06 13:41

[PHP] 간단한 캐싱 클래스

조회 수 855 추천 수 1 댓글 3
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
Extra Form
라이선스 MIT

PHP를 이용해서 간단한 캐싱 클래스를 만들어보았습니다.

여기에선 간단하게 시간을 체크해서 캐시를 재설정할 수 있게 해놓았습니다.

redis 등과 같이 좀 더 고급 기술을 사용하진 않고 단순히 파일 캐싱을 구현하였습니다.

고급 기술을 사용하시거나 좀 더 많은 기능이 필요하실 경우 이미 만들어진 라이브러리를 사용하시는 것이 좋습니다.


참고로 제가 만든 카카오톡 봇의 경우 이 캐싱 클래스를 사용하고 있습니다.


<?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();



  • profile
    이니스프리 2018.12.06 14:28

    요새 그러지 않아도 캐시에 관심이 많았는데 좋은 스크립트 올려주셔서 감사합니다 ^-^

    올려주신 스크립트가 일종의 파일캐시(디스크캐시)인 것이죠?

    덕분에 파일캐시의 구조에 대해 조금이나마 이해하게 되었네요~


    그누보드가 세션 등 처리에 있어 상대적으로 캐시 친화적이지 않고

    게다가 XE/라이믹스에는 슈퍼캐시 모듈이 있기 때문에,

    양자 간에 TTFB나 감당할 수 있는 동접자 수에서 차이가 발생하고

    그러한 결과 간접적으로 SEO에서도 불이익이 발생한다고 알고 있네요 ㅠㅠ


    제가 Redis를 사용해보려고 했는데 그누보드/아미나 최신버전에 PHP 7 환경에서

    제대로 작동하는 공개된 플러그인이 아마도 없는 것 같더군요 ㅜㅜ


    만약 글이 자주 올라오지 않는 환경에서 최신글 위젯 등을 효율적으로 캐싱하려면

    캐시 만료시간을 아주 길게 잡는 대신에

    새 글을 작성하면 캐시를 갱신하는 방식으로 사용하면 되겠죠?


    좋은 자료 올려주신 덕분에 열심히 공부해보겠습니다~

    humit 님께 항상 감사드립니다 :)

    날씨가 쌀쌀하지만 즐겁고 뜻깊은 휴가 되세요~!

  • profile
    title: 황금 서버 (30일)humit 2018.12.06 18:47
    네 일종의 파일 캐시라고 생각하시면 됩니다 ㅎㅎ
  • ?
    포인트 폭탄+ 2018.12.06 18:47
    humit님 축하합니다.
    추가로 200포인트만큼 포인트 폭탄+를 받았습니다.

List of Articles
번호 분류 제목 글쓴이 날짜 조회 수
43 코드 [Python] 선택한 파일을 Dropbox API를 이용하여 업로드하고 공유링크를 받아서 이미지 호스팅 용도로 URL을 변환하기 1 file 이니스프리 2019.07.02 1166
42 코드 [JS]클라이언트에서 Ip를 얻어보자 2 Hanam09 2019.01.21 776
41 코드 [JS] http를 https로 리디렉션! 3 Hanam09 2018.12.30 840
40 코드 [PHP] 이미지를 원하는 크기(원본비율 유지)로 리사이즈 하여 출력 (원본 이미지는 수정하지 않습니다) 6 이니스프리 2018.12.20 7994
39 코드 [아미나] 네이트 실시간 검색어 순위 위젯 (아미나 캐시 적용) 3 file 이니스프리 2018.12.18 1123
38 코드 [아미나] 출석 여부를 나타내는 메인화면 위젯 4 file 이니스프리 2018.12.15 769
» 코드 [PHP] 간단한 캐싱 클래스 3 title: 황금 서버 (30일)humit 2018.12.06 855
36 코드 [Python] 텔레그램을 이용한 게시판 새 글 알림봇 7 이니스프리 2018.12.02 3979
35 코드 [아미나] 게시글을 작성하면 ID와 IP로 필터링하여 자동으로 랜덤 댓글을 남기기 (+랜덤 포인트) 7 file 이니스프리 2018.11.18 803
34 코드 [PHP] 그누보드 자동 게시글 작성 - 일본기상협회의 우리나라 날씨를 크롤링한 후 파파고로 번역하여 글 작성 4 file 이니스프리 2018.11.15 821
33 코드 [PHP] 기상청 RSS 시간별 예보 위젯 - cache 적용(?) 9 file 이니스프리 2018.10.28 990
32 코드 [오토핫키] 브라우저를 열어 지난번과 동일한 폴더에 MZK를 다운받고 압축을 네이티브로 해제하는 스크립트 file 이니스프리 2018.10.20 918
31 코드 [PHP] 기상청 중기예보를 캐러셀로 보여주는 위젯 (매우 허접합니다 ㅠㅠ) 10 file 이니스프리 2018.09.28 733
30 코드 [오토핫키] 구글 드라이브의 공유링크를 이미지 호스팅을 위한 다이렉트 링크로 바꿔주는 스크립트 10 file 이니스프리 2018.09.25 1754
29 코드 [오토핫키] 특정 사이트에 대한 ping 테스트 결과를 실행시간과 함께 로그 파일로 저장하는 스크립트 2 이니스프리 2018.09.22 2052
28 코드 [Python] 모 정부기관 사이트 파싱 후 PC 통신처럼 열람하고 싶은 게시글 번호를 입력하면 내용을 보여주는 소스 (허접) 4 이니스프리 2018.09.14 743
27 코드 파이선 셸에서 실행하면...? 3 제르엘 2018.07.22 546
26 코드 C언어 삼중자를 이용한 코드 title: 황금 서버 (30일)humit 2018.07.22 484
25 코드 폰트를 자동 설치하는 코드 1 네모 2018.07.16 977
24 코드 잘못 쓰면 컴퓨터가 날아가는 코드 29 제르엘 2018.07.08 1022
Board Pagination Prev 1 2 3 4 Next
/ 4