환경 설정 파일 PHP.INI
PHP.INI의 [Session] 부분의 마지막에 캐시에 관련된 설정 옵션이 두가지 있습니다. 그것은 session.cache_limiter와 session.cache_expire입니다. 이것은 둘 다 세션함수를 사용한 페이지에서만 사용할 수 있습니다.
[Session]
.
.
.
session.cache_limiter = nocache ; set to {nocache,private,public} to
; determine HTTP caching aspects
session.cache_expire = 180 ; document expires after n minutes
.
.
.
session.cache_limiter
session.cache_limiter란???
session.cache_limiter는 세션페이지에서 사용하는 HTTP 캐시제어방법을 규정하는 것으로 기본값은 nocache로 설정되어 있습니다. 설정할 수 있는 캐시제어방법에는 nocache외에도 private와 public가 있습니다.
캐시 제한자(public, private, nocache)
public, private, nocache라는 캐시 제한자는 바로 HTTP/1.1에서 규정한 Cache-Control 헤더에 있는 캐시 제어 지시자 public, private, no-cache와 같은 의미를 가지고 있습니다. 각각의 의미는 "Cache-Control..." 장을 참조바랍니다.
이와 같이 session.cache_limiter에 설정된 캐시 제한자를 가지고 있는 세션 기능이 동작하고 있는 페이지에서는 브라우저에서 설정한 캐시제어방법 대신에 캐시 제한자에 설정된 값에 따라 캐시가 동작하게 되는 것입니다. 즉, 브라우저가 문서를 요구할 때 함께 보내게 되는 캐시 방법에 관계없이 웹서버에서 PHP를 통해 session.cache_limiter에 설정된 캐시 방법으로 문서를 응답하게 됩니다.
private에 대한 변명
사실 제가 HTTP/1.1 문서를 검토해 보기 전에는 private 지시자에 대한 의미를 정확히 이해할 수가 없었습니다. 그래서 제 홈페이지 Q&A 게시판에서 이전에 올렸던 게시물 "답장: session.cache_limiter를 파헤쳐라....."에서 private에 대한 제 의견이 순 거짓뿌렁이었다는 것을 몰랐었죠. 혹시 이 게시물을 읽더라도 이 점에 유의하여 주시길 바랍니다.
왜 기본값이 하필이면 "nocache"이냐???
캐시가 기본으로 동작되면 더 편할텐데하고 생각할 지도 모르겠으나 아마 PHP4 개발자는 캐시를 사용하지 않는 것이 세션 기능으로 보면 더 타당하다고 판단하지 않았나 생각합니다. 여러분도 아시겠지만 PHP에 관련된 홈페이지에 있는 대부분의 Q/A 게시판을 보면 캐시때문에 새로이 갱신된 데이터가 브라우저에 나타나지 않는다고 하소연하는 분들을 많이 보았을 것입니다. 테이터가 갱신되었어도 캐시에 있는 옛날 데이터가 브라우저에 계속 나타나는 것이지요. 그런데 우리가 세션 기능을 사용하는 페이지에서는 거의가 새로운 데이터를 계속 브라우저에 뿌려주어야 할 경우가 대부분일 것으로 생각되거든요. PHP4 개발자도 이를 염두에 두지 않았나 생각됩니다. 그러니 세션 기능이 동작되는 페이지에서 캐시를 사용할 때는 오히려 이런 부분에 주의를 기울여야 하지 않을까 하네요. 전자상거래 웹사이트를 한번 생각해 보세요......
session.cache_expire 란???
앞서 "HTTP/1.1 캐시" 장에서 Cache-Control 헤더의 max-age 지시자를 이용하여 문서의 만기일을 서버에서 임의 지정할 수 있다고 하였습니다. max-age 지시자에 설정할 값을 PHP 세션에서 정해주는 옵션이 바로 session.cache_expire입니다. 위에서 보는 바와 같이 session.cache_expire의 기본값은 180분입니다. 이 값에 의해 max-age 지시자에 설정되는 값은 초단위로 환산하는데 10,800초입니다. 이에 의해 캐시된 세션 문서는 문서가 발행된 후 10,800초가 지나면 "낡은" 문서가 됩니다.
session_cache_limiter() 함수
PHP.INI 파일의 session.cache_limiter 옵션은 PHP가 실행될 때 단 한번만 실행되므로 이 후 모든 웹문서는 이 설정값에 의해 캐시 여부가 결정되도록 되어 있습니다. 그러나 웹문서를 작성하다 보면 특정 문서의 경우 session.cache_limiter에 설정된 값에 관계없이 캐시 방법을 설정할 필요가 있을 때가 있겠죠. 이럴 때 사용할 수 있는 함수가 session_cache_limiter() 함수입니다.
[code php;gutter:false] <?php

# set the cache limiter to 'private'

session_cache_limiter('private');
$cache_limit = session_cache_limiter();

echo "The cache limiter is now set to $cache_limiter\n";

?> [/code]
이 함수는 PHP4.0.3부터 제공되며, session_start() 함수를 사용하기 전에 사용하여 주십시요.
string session_cache_limiter([string cache_limiter])
session_cache_limiter() 함수는 현 캐시 제한자명(the name of the current cache limiter)을 되돌려 줍니다. 입력 인자로 public/private/nocache 중 하나로 지정하게 되면 현 캐시 제한자명이 지정된 이름으로 변경됩니다.
만료된 페이지
각종 Q&A 게시판에 가보면 "만료된 페이지" 메시지때문에 많은 질문이 올라오는 것을 볼 수 있습니다. 아래와 같이 넷스케이프에선 "데이터 없음", 익스플로러에선 "만료된 페이지"라는 메시지를 나타내지요.
데이터 없음

POST로 작성된 이 문서는 만료되어 캐시에서 없어졌습니다.
다시 읽기 단추를 클릭하면, 서식 데이터를 다시 게시해
문서를 작성할 수 있습니다.
경고: 만료된 페이지입니다. 사용자가 요청한 페이지는 폼으로 보낸 정보를
사용하여 만들어진 페이지입니다. 이 페이지는 더 이상 사용할 수 없습니다.
보안을 위해 Internet Explorer는 사용자의 개인 정보를 자동으로 재전송하지 않습니다.

사용자 개인 정보를 재전송하고 이 페이지를 보려면 새로 고침 단추를 누르십시오.
history, no-cache, http post
이러한 메시지는 보통 이전 페이지로부터 FORM 태그를 이용하여 HTTP POST 방식으로 데이터를 넘겨받는 현재 페이지가 세션함수를 사용할 경우에 "앞으로" 또는 "뒤로" 버튼으로 히스토리 정보를 이용할 경우에 발생합니다. 물론 "뒤로" 버튼 대신에 자바스크립트 함수인 history.back() 함수를 이용하여도 같은 현상이 발생합니다.
앞에서 이런 현상이 세션 페이지에서 나타난다고 해서 세션 함수때문에 발생하는 것은 아닙니다. 위에서도 살펴보았듯이 세션 페이지는 디폴트로 캐싱 방식을 "nocache"로 설정되어 있기 때문이며, 이 설정에 의해 서버에서 웹브라우저로 보내는 응답 헤더에는 아래와 같은 Cache-Control 헤더 지시자가 "no-cache"로 설정됩니다.
expires: Thu, 19 Nov 1981 08:52:00 GMT
cache-control: no-store, no-cache, must-revalidate,
post-check=0, pre-check=0
pragma: no-cache
즉, 세션에 의해 나타난 현상이 아니라 응답 헤더에 담긴 Cache-Control 헤더 지시자가 "no-cache"라는 것에 의해 발생하는 현상이지요. 현재 페이지가 캐싱을 하지 않는 경우에 나타나는 현상입니다.
물론 웹서버로부터 넘어온 현재 페이지가 "no-cache"로 설정되었다고 전부 이러한 현상이 나타나는 것은 아니지요. 문제는 "뒤로" 또는 "앞으로" 버튼에 의해 히스토리 정보를 이용하려고 할 때 발생하는 것이지요. 그러나 한 번 생각해보세요. 현재 페이지가 "no-cache"로 설정하였다는 것은 현재 페이지가 다이나믹한 - 변화무쌍한 - 컨텐츠가 제공되는 페이지라서 캐싱을 이용하지 말고 항상 웹서버로부터 웹문서를 읽어오라는 의미입니다. 그런데 이러한 페이지를 히스토리 정보에 의해 웹서버와 관계없이 브라우저에 저장된 문서를 읽어오게 되면 좀 이상하지 않습니까?
히스토리 메커니즘과 캐시 메커니즘은 기본 개념이 다르기 때문에(이에 대한 정보는 앞장 "HTTP/1.1 캐시 >> 캐시와 history 메커니즘의 차이점"을 참조) 현재 페이지가 "no-cache"로 설정되었다고 "뒤로" 또는 "앞으로" 버튼을 통해 히스토리 캐시에 저장된 현재 페이지를 읽어서는 안된다는 것은 아닙니다. 한가지 경우만 제외하고는 대부분 응답 헤더에 설정된 캐시 설정에 관계없이 히스토리에 저장된 문서를 읽을 수 있습니다. 이 한가지 경우가 바로 앞장에서 FORM 태그를 이용하여 POST 방식으로 데이터가 넘어올 때는 보여주기는 하지만 그 전에 경고 메시지를 보여주는 것이지요. 그것이 "만료된 페이지"라는 메시지입니다. 이 경우에는 "다시 읽기" 또는 "새로 고침" 버튼을 누르게 되면 앞 페이지에서 넘어온 데이터를 이용하여 현재 페이지를 재 작성하여 보여줍니다. "만료된 페이지" 문서의 경우는 문서 내용이 히스토리 캐시에 보관되지 않습니다. 단지 주소만 보관되어 있는 것입니다.
결국 "만료된 페이지"라는 메시지는 다음과 같이 세가지 조건이 충족되어야 나타날 수 있습니다. "만료된 페이지"라는 메시지를 보고 싶으면 이와 같은 세가지 조건을 모두 만족시켜면 되는 것이고, "만료된 페이지"라는 메시지를 보고 싶지 않으면 세가지 조건 중에서 한가지라도 어긋나게 하면 되는 것이지요.
♧ 현재 웹문서의 응답 헤더의 Cache-Control 헤더 지시자가 "no-cache"로 설정됨
(넷스는 "private"로 설정될 때도 포함)
♧ 앞페이지에서 FORM 태그를 이용하여 HTTP POST 방식으로 데이터가 넘어옴
♧ 현재 페이지를 "뒤로", "앞으로" 또는 history.back() 함수와 같은
히스토리 관련 함수로 접근함
위에서 익스와 넷스가 다르게 동작되는 부분이 일부 있습니다. 익스는 "no-cache"일 때만 해당되는데 반하여 넷스는 "no-cache" 뿐만 아니라 "private"일 때도 해당됩니다. 그러니 익스와 넷스가 동일하게 동작하도록 작성된 페이지에서는 "private"의 사용을 피하는 것이 좋을 듯 합니다. 아울러 제가 모든 경우를 대상으로 실험할 수 없었기 때문에 위 조건 내용 중 일부가 추가 또는 삭제 될 수 있습니다. 관련된 정보는 연락바랍니다.
응답 헤더 "no-cache"
웹 문서를 작성하면서 개발자가 응답 헤더의 Cache-Control 헤더 지시자가 "no-cache"로 설정하게 되는 경우를 살펴 보면 아래와 같이 크게 두가지 입니다.
♧ PHP4 세션함수를 사용하는 페이지
♧ header()함수를 이용하여 현재 문서의 캐싱을 금지하는 페이지
한가지 실험을 해 보겠습니다. 총 9개의 페이지로 구성되어 있고 각 페이지마다 다른 캐시 설정으로 구성되어 있으며 8.php 페이지를 제외하고는 모두 POST 방식의 FORM 태그로 데이터를 다음 페이지로 넘기게 됩니다.
[code html;gutter:false] //1.php
//=====

<HTML>
<BODY>
<H2><?php echo $ck ?></H2>
<FORM action="2.php" method="post">
<INPUT type="text" name="ck">
<INPUT type="submit" value="2.php">
</FORM>
</BODY>
</HTML>

//2.php
//=====

<?php
session_start();
?>

<HTML>
<BODY>
<H2><?php echo $ck ?></H2>
<FORM action="3.php" method="post">
<INPUT type="text" name="ck">
<INPUT type="submit" value="3.php">
</FORM>
</BODY>
</HTML>

//3.php
//=====

<?php
session_cache_limiter("public");
session_start();
?>

<HTML>
<BODY>
<H2><?php echo $ck ?></H2>
<FORM action="4.php" method="post">
<INPUT type="text" name="ck">
<INPUT type="submit" value="4.php">
</FORM>
</BODY>
</HTML>

//4.php
//=====

<?php
session_cache_limiter("private");
session_start();
?>

<HTML>
<BODY>
<H2><?php echo $ck ?></H2>
<FORM action="5.php" method="post">
<INPUT type="text" name="ck">
<INPUT type="submit" value="5.php">
</FORM>
</BODY>
</HTML>

//5.php
//=====

<?php
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");
?>

<HTML>
<BODY>
<H2><?php echo $ck ?></H2>
<FORM action="6.php" method="post">
<INPUT type="text" name="ck">
<INPUT type="submit" value="6.php">
</FORM>
</BODY>
</HTML>

//6.php
//=====

<?php
header("expires: ".gmdate("D, j M Y H:i:s", time() + 3600*3)." GMT");
header("cache-control: public, max-age=$maxage");
header("last-modified: ".gmdate("D, j M Y H:i:s", time() - 896)." GMT");
?>

<HTML>
<BODY>
<H2><?php echo $ck ?></H2>
<FORM action="7.php" method="post">
<INPUT type="text" name="ck">
<INPUT type="submit" value="7.php">
</FORM>
</BODY>
</HTML>

//7.php
//=====

<?php
header("expires: Thu, 19 Nov 1981 08:52:00 GMT");
header("cache-control: private, max-age=$maxage, pre-check=$maxage");
header("last-modified: ".gmdate("D, j M Y H:i:s", time() - 896)." GMT");
?>

<HTML>
<BODY>
<H2><?php echo $ck ?></H2>
<FORM action="8.php" method="post">
<INPUT type="text" name="ck">
<INPUT type="submit" value="8.php">
</FORM>
</BODY>
</HTML>

//8.php
//=====

<HTML>
<HEAD>
</HEAD>
<BODY>
<H2><?php echo $ck ?></H2>
<A href="9.php">9.php</A>
</BODY>
</HTML>

//9.php
//=====

<?php
session_start();
?>

<HTML>
<BODY>
<H2><?php echo $ck ?></H2>
<FORM action="1.php" method="post">
<INPUT type="text" name="ck">
<INPUT type="submit" value="1.php">
</FORM>
</BODY>
</HTML> [/code]
위 페이지 중에서 히스토리 정보를 이용할 때 익스는 "2.php"와 "5.php"에서만, 넷스는 "2.php", "4.php", "5.php"와 "7.php"에서만 "만료된 페이지"라는 메시지를 볼 수 있을 것입니다. "2.php"와 "5.php" 페이지는 "no-cache"로 설정된 페이지이고, "4.php"와 "7.php"는 "private"로 설정된 페이지입니다. 이 예제를 제대로 이해하셨다면 문제를 해결하는 방법도 어렵지 않게 찾으리라 생각합니다.
"nocache" 페이지에서 입력된 FORM 값
여기에 관련된 많은 질문 중에 하나가 현재 페이지에서 FORM 태그를 통해 데이터를 입력하고, 서브밋하여 다음 페이지로 넘어간 후에 "뒤로" 버튼으로 현재 페이지로 되돌아 왔을 때 입력하였던 내용이 모두 없어진다는 것입니다.
현재 페이지가 "nocache"로 설정되어 있다고 생각해 보세요. 앞에서도 언급했었지만 개발자가 현재 페이지를 "nocache"로 설정하였을 때는 현재 페이지가 다이내믹한 문서이므로 항상 웹문서를 캐시가 아닌 서버에서 받도록 지시한 것입니다. 이러한 다이내믹한 문서를 히스토리 영역에 저장하였을 때 "뒤로" 또는 "앞으로" 버튼을 이용하여 현재 페이지를 다시 접근하였다고 해서 앞서 입력하였던 내용이 그대로 살아있다면 오히려 이상하지 않을까요. 이러한 다이내믹한 문서의 경우에는 히스토리 데이터를 보여주더라도 입력한 내용 만은 다시 입력하도록 웹브라우저가 배려한 것이 오히려 타당할 것 같습니다. 이러한 문제가 발생되는 경우는 아래와 같은 조건이 모두 맞아 떨어져야 합니다.
♧ 현재 웹문서의 응답 헤더의 Cache-Control 헤더 지시자가 "no-cache"로 설정됨
(넷스는 "private"로 설정될 때도 포함)
♧ 앞페이지에서 FORM 태그를 이용하여 데이터가 넘어옴
(HTTP POST 또는 GET 방식에 관계없이)
♧ 현재 페이지를 "뒤로", "앞으로" 또는 history.back() 함수와 같은
히스토리 관련 함수로 접근함
따라서 앞서 입력한 내용을 히스토리 데이터에서도 계속 보존하고 싶으면 현재 페이지를 "nocache"로 설정하지 마세요. 아니면 위의 조건중 다른 조건을 어긋나게 하면 되겠지요.아래는 문제가 생기는("뒤로" 버튼을 눌렀을 때 입력하였던 내용이 모두 없어지는) 경우의 소스코드 예제입니다.
[code html;gutter:false] //10.php
//======

<?php
session_start();
?>

<HTML>
<BODY>
<H2><?php echo $ck ?></H2>
<FORM action="20.php" method="get">
<INPUT type="text" name="ck">
<INPUT type="submit" value="20.php">
</FORM>
</BODY>
</HTML>


//20.php
//======

<?php
session_start();
?>

<HTML>
<BODY>
<H2><?php echo $ck ?></H2>
<FORM action="10.php" method="get">
<INPUT type="text" name="ck">
<INPUT type="submit" value="10.php">
</FORM>
</BODY>
</HTML> [/code]
이 문제를 해결하는 방법은 위에서 언급한 바와 같이 세션의 캐시방식을 "nocache"로 설정하지 않는 것입니다. 세션에서 캐시방식을 변경하는 방법은 여러가지가 있으나 현재 페이지의 캐시방식만 변경할 경우는 session_cache_limiter() 함수를 이용하면 간단합니다. 아래는 캐시방식을 "public"로 변경하였습니다.
[code html;gutter:false] //10.php
//======

<?php
session_cache_limiter("public");
session_start();
?>

<HTML>
<BODY>
<H2><?php echo $ck ?></H2>
<FORM action="20.php" method="get">
<INPUT type="text" name="ck">
<INPUT type="submit" value="20.php">
</FORM>
</BODY>
</HTML>


//20.php
//======

<?php
session_cache_limiter("public");
session_start();
?>

<HTML>
<BODY>
<H2><?php echo $ck ?></H2>
<FORM action="10.php" method="get">
<INPUT type="text" name="ck">
<INPUT type="submit" value="10.php">
</FORM>
</BODY>
</HTML> [/code]
만약 현재 페이지를 반드시 "nocache"로 설정하여야 하는 경우라면 위의 수정코드는 곤란하겠지요. 다른 방법을 생각해 보죠. 원래 코드는 "10.php -> 20.php -> 10.php"로 페이지가 이동하고 있고 10.php과 20.php 페이지 모두 FORM 태그와 세션을 이용하고 있습니다. FORM 태그를 사용하는 페이지와 세션페이지를 분리시키면 어떨까요? "10.php -> 11.php -> 20.php -> 21.php -> 10.php"와 같이...... 페이지를 작성하는데 좀 불편하기는 하지만......
[code html;gutter:false] //10.php(데이터를 입력받는 페이지)
//======

<HTML>
<BODY>
<H2><?php echo $ck ?></H2>
<FORM action="11.php" method="get">
<INPUT type="text" name="ck">
<INPUT type="submit" value="20.php">
</FORM>
</BODY>
</HTML>


//11.php(세션을 처리하는 페이지)
//======

<?php
session_start();
?>

<META http-equiv='Refresh' content='0; URL=20.php?ck=<?php echo $ck ?>'>


//20.php(데이터를 입력받는 페이지)
//======

<HTML>
<BODY>
<H2><?php echo $ck ?></H2>
<FORM action="21.php" method="get">
<INPUT type="text" name="ck">
<INPUT type="submit" value="10.php">
</FORM>
</BODY>
</HTML>


//21.php(세션을 처리하는 페이지)
//======

<?php
session_start();
?>

<META http-equiv='Refresh' content='0; URL=10.php?ck=<?php echo $ck ?>'> [/code]
만약 HTTP GET 방식으로 데이터를 넘기기가 싫다면 - URL 창에 데이터가 보이니까 - POST 방식과 쿠키를 이용하여 개조해 보죠.
[code html;gutter:false] //10.php(데이터를 입력받는 페이지)
//======

<HTML>
<BODY>
<H2><?php echo $ck ?></H2>
<FORM action="11.php" method="post">
<INPUT type="text" name="ck">
<INPUT type="submit" value="20.php">
</FORM>
</BODY>
</HTML>


//11.php(세션을 처리하는 페이지)
//======

<?php
setcookie("ck", $HTTP_POST_VARS["ck"]);
session_start();
?>

<META http-equiv='Refresh' content='0; URL=20.php'>


//20.php(데이터를 입력받는 페이지)
//======

<HTML>
<BODY>
<H2><?php echo $ck ?></H2>
<FORM action="21.php" method="post">
<INPUT type="text" name="ck">
<INPUT type="submit" value="10.php">
</FORM>
</BODY>
</HTML>


//21.php(세션을 처리하는 페이지)
//======

<?php
setcookie("ck", $HTTP_POST_VARS["ck"]);
session_start();
?>

<META http-equiv='Refresh' content='0; URL=10.php'> [/code]
기본 개념만 확실히 잡고 계시면 이제 문제가 되는 것은 여러분의 아이디어입니다. 여러분의 참신한 아이디어만 있으면 얼마든지 문제를 해결할 수 있지요.
"nocache" & "no-cache"
위에서 어떤 경우는 "nocache"라고 기술하고 어떤 경우는 "no-cache"라고 기술하여 어떤 것이 맞는지 아니면 둘다 맞는지 혼동될 수 있을 것입니다. 둘 다 맞는 것은 아니고 사용하는 곳에 따라 정하여져 있습니다. 이것이 맞지 않으면 제대로 동작되지 않습니다.
세션함수 header() 함수
nocache no-cache

Posted by 방글24
header() 함수
int header(string string)
header() 함수는 HTML파일의 최상단에서 HTTP 헤더 문자열을 protocol level에서 데이터를 브라우저로 직접 전송할 수 있도록 해 줍니다. HTTP 헤더에 대한 자세한 내용은 HTTP/1.1 규약(Specification)을 참조하세요.
header() 함수를 사용할 때 발생하는 에러
header() 함수를 사용하는 데 주의 할 점이 있습니다. header() 함수는 일반적인 HTML 태그 또는 PHP로부터 보내지는 실제의 출력 이전에 호출되어야 합니다. header() 함수를 호출하기 전에 include() 또는 auto_prepend를 통하여 코드를 읽어들일 수 있는데 이러한 코드에 브라우저로 출력되는 스페이스 또는 빈줄이 있으면 에러가 발생합니다. 아래에 에러가 발생하는 3가지 경우를 나타내었습니다. 이러한 에러는 아주 흔히 발생하는 에러입니다.
[code php;gutter:false] echo("연습삼아\n"); // header() 함수 전에 출력함수를 사용하면 안됨
header(......); [/code]
[code php;gutter:false] <?
<--- 이곳에 공백(white space)이 있으면 안됨
header(......); [/code]
[code php;gutter:false] <--- 이곳에 공백(white space)이 있으면 안됨
<?
header(......); [/code]
동적으로 생성되는 웹컨텐트
PHP 스크립트는 자주 동적으로 HTML을 생성하여야 하는데, 이러한 경우에는 서버와 클라이언트 브라우저 사이에 있는 브라우저 캐시 또는 프록시 캐시에 의해 캐싱되어서는 안됩니다. 많은 프록시와 클라이언트들은 아래와 같은 코드를 가지고 강제적으로 캐시를 중지시킬 수 있습니다.
[code php;gutter:false] header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // 과거의 날짜
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . "GMT"); // 항상 수정되고 있는
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Pragma: no-cache"); // HTTP/1.0 [/code]
headers_sent() 함수
boolean headers_sent(void)
(PHP 3>= 3.0.8, PHP 4 >= 4.0b2) HTTP 헤더가 이미 송신되고 있는 경우에는 true를, 그렇지 않은 경우에는 false를 돌려주기 위한 함수입니다.
setcookie() 함수
int setcookie (string name [, string value [, int expire [, string path [, string domain [, int secure]]]]])
쿠키를 설정하도록 하는 요청을 브라우저로 전달하기 위해 setcookie() 함수를 사용합니다. 이 요청은 클라이언트 상에 있는 쿠키를 갱신하거나 작성합니다. 이 코드는 반드시 페이지의 맨 앞에 들어 있어야 합니다. PHP 스크립트를 시작하는 태그("<?php") 앞의 컨텐트(공백 문자를 포함하여)는 오류를 발생시킵니다.
만약 HTTP 응답이 이미 전송된 이후에 setcookie() 함수가 호출된다면 PHP는 자동적으로 경고 메시지를 발생시킵니다.
setcookie() 함수에 대한 자세한 사용법이나 설명은 관련서적이나 홈페이지를 참조바랍니다.
GetAllHeaders() 함수
array GetAllHeaders(void)
모든 HTTP 요구 헤더를 분석하여 읽어옵니다. 이 함수는 현재의 요구에 해당하는 모든 HTTP 헤더를 가지는 연상 배열을 돌려줍니다.
GetAllHeaders() 함수는 PHP가 Apache 모듈로 설치되어 있을 경우에만 동작합니다. 환경 변수로부터 HTTP 요구 헤더값을 얻을 수도 있는데 이 방법은 PHP를 Apache모듈로 설치되지 않을 때도 동작합니다. 정의된 모든 환경 변수에 대한 리스트를 얻으려면 phpinfo() 함수를 사용하세요.
[code php;gutter:false] $headers = GetAllHeaders();
while (list($header,$value)=each($headers)) {
echo "$header: $value\n";
} [/code]
이 예는, 현재의 요구에 관계되어 있는 모든 요구 헤더를 표시 합니다

Posted by 방글24
Cache-Control, Expires, Last-Modified, Pragma에 대하여 하나씩 살펴보겠습니다.
Cache-Control 메커니즘
HTTP/1.1의 기본적인 캐시 메커니즘(서버설정 만기시간 및 검증자)은 캐시에 내장된 지시자입니다. 때에 따라서는 서버나 클라이언트에게 HTTP 캐시를 위해 명시된 지시자 제공할 필요가 있습니다. Cache-Control 헤더를 이 목적으로 사용합니다.
Cache-Control 헤더는 클라이언트나 서버가 요구나 응답의 다양한 지시자를 전달할 수 있도록 합니다. 이 지시자는 대개의 경우 기본 캐시 알고리즘을 무시합니다. 보편적인 원칙으로 만약 헤더값 사이에 분명한 충돌이 있으면 가장 엄격한 - 가장 의미투명한 동작을 할 수 있는 - 해석을 하여야 합니다.
원서버가 응답할 수 있는 캐시 지시자
Cache-Control 일반 헤더 필드는 요구/응답 체인에 따라 모든 캐시 메커니즘이 반드시 따라야 하는 지시자를 표시하는데 사용합니다. 여기서는 응답에서 사용되는 캐시지시자(cache-directive)에 대하여 알아봅니다. 요구에서 사용되는 캐시 지시자에 대하여는 관련 문서를 참조바랍니다.
Cache-Control: public
                    | private
                    | no-cache
                    | no-store
                    | no-transform
                    | must-revalidate
                    | proxy-revalidate
                    | max-age
                    | cache-extension
캐시 제한자(public, private, no-cache)
Cache-Control 응답 지시자 중에서 public, private, no-cache는 원서버가 응답의 캐시 가능성을 무시할 수 있도록 합니다.
public
보통은 비공유 캐시 내에서만 캐시할 수 있거나(private) 캐시할 수 없지만(no-cache) public은 모든 공유/비공유 캐시에서 응답을 캐시할 수 있도록 지정합니다.
private
응답 메시지의 전체 또는 일부분을 단일 사용자만이 사용하며 절대로 공유 캐시(shared cache)에 의해 캐시해서는 안됨을 표시합니다. 원서버가 응답의 특정 부분이 단일 사용자만을 위한 것이며 다른 사용자의 요구에 대한 유효한 응답은 아니라는 것을 명시할 수 있도록 합니다.
no-cache
응답의 전체 또는 부분을 캐시해서는 안된다는 것을 나타냅니다. 원서버가 클라이언트 요구에 낡은 응답(stale response)을 리턴하도록 설정된 캐시에 의해서도 캐시를 하지 못하도록 합니다. 대부분의 HTTP/1.0 캐시는 이 지침을 인지하지 못하거나 따르지 않을 것입니다.
캐시 저장 금지(no-store)
no-store 지시자의 목적은 부주의하게 민감한 정보를 백업테이프와 같은 곳에 보유하거나 배포하는 것을 방지하는 것입니다. no-store 지시자는 요구/응답 모두에 발송할 수 있습니다. 요구에 포함하여 발송하게 되면 캐시는 요구의 어떤 부분 또는 이 요구에 대한 어떠한 응답도 캐시해서는 안됩니다. 응답에 발송하게 되면 캐시는 이 응답의 어떤 부분 또는 응답을 이끌어 낸 요구를 저장해서는 안됩니다. 이 지시자는 비공유 및 공유 캐시에 모두 적용됩니다.
만기일 메커니즘의 변경(max-age)
원서버는 expires 헤더를 이용하여 엔터티의 만기시간을 명시합니다. 대안으로 응답에 max-age 지시자를 사용하여 표시할 수도 있습니다.
응답에 expires 헤더 및 max-age 지시자가 모두 포함되어 있으면 max-age 지시자는 expires 헤더가 더 제한적이라 할지라도 이를 무시합니다. 이 원칙은 원서버가 HTTP/1.0 캐시에 HTTP/1.1 캐시(또는 이후 버전)보다 긴 만기시간을 응답에 부여할 수 있도록 합니다. HTTP/1.0 캐시가 동기화되지 않은(desynchronized) 시계때문에 부적절하게 경과시간이나 만기시간을 계산했을 때 유용합니다.
캐시된 사본을 원서버가 직접적으로 검증하도록 강요하여 응답을 명확히 하려면 아래와 같이 max-age 값을 0으로 지정합니다.
Cache-Control: max-age=0
캐시의 재검증(must-revalidate)
규약은 원서버가 계속되는 캐시 사용에 대한 캐시 엔트리 검증을 요구할 수 있는 메커니즘을 포함하고 있습니다. must-revalidate 지시자가 캐시가 수신한 응답에 포함되어 있고 캐시가 계속되는 요구에 응답하기에는 낡아진 이후에 캐시는 먼저 원서버에 이를 재검증하기 전에는 엔트리를 사용해서는 안됩니다.
must-revalidate 지시자는 특정 규약 기능의 안정된 운영을 위해서 필요합니다. 어떠한 경우이든 HTTP/1.1 캐시는 must-revalidate 지시자를 반드시 따라야 합니다.
비변경 지시어(no-transform)
구현된 중간 캐시(프록시)에서 특정 엔터티 본문의 media type을 변환하는 것이 유용할 수 있습니다. 예를 들어 프록시는 캐시 공간을 절약하거나 느린 링크 상의 트래픽 양을 줄이기 위해 이미지의 포맷을 변환할 수 있습니다. 그러나 특정 종류의 애플리케이션에 사용할 엔터티 본문에 이러한 변환을 적용했을 때 심각한 운영 문제가 발생하게 됩니다. 예를 들어 의료 이미지 처리, 과학적 자료 분석 및 end-to-end 인증에 사용되는 애플리케이션은 모두 원서버의 엔터티 본문와 비트 단위까지 동일한 엔터티 본문을 수신하는 방식에 의존하고 있습니다.
따라서 응답이 no-transform 지시자를 포함하고 있으면 중간 캐시나 프록시는 Content-Encoding, Content-Length, Content-Range, Content-Type와 같은 헤더 필드 값을 절대로 변경해서는 안됩니다.
캐시 제어 확장(cache-extension)
Cache-Control 헤더 필드는 하나 또는 그 이상의 cache-extension 토큰을 이용하여 각각 선택적으로 부여된 값을 가지고 확장할 수 있습니다. 정보 확장(informational extensions - 캐시 동작에 변화를 요구하지 않는)은 다른 지시자의 의미를 변화시키지 않고도 추가할 수 있습니다 동작 확장(behavioral extensions)은 캐시 지시자의 기본 베이스에 대한 변경자의 역할을 수행하도록 디자인 되었습니다. 새로운 지시자 및 표준 지시자 모두가 제공되었을 때 새로운 지시자를 이해하지 못하는 애플리케이션은 표준 지시자가 명시한 동작에 기본적으로 따르며 새로운 지시자를 이해하는 애플리케이션은 이를 표준 지시자와 관련된 필요 조건의 변경으로 인식합니다. 이러한 방식으로 지시자를 기본 규약에 대한 변경을 요구하지 않고도 확장할 수 있습니다.
인지할 수 없는 캐시지시자는 무시해야 합니다. HTTP/1.1 캐시가 인지하지 못하는 모든 캐시지시자는 캐시가 확장을 이해하지 못하더라도 최소한도로 이러한 캐시 동작이 정학한 것으로 유지되도록 표준 지시자(또는 응답의 캐시 제한자)와 결합되어 있다고 가정합니다.
IE5에서의 캐시 제어 확장
post-check, pre-check 지시자는 익스플로러 5.0부터 제공되기 시작한 캐시 제어 메커니즘입니다. 이 헤더는 이전 버전의 익스플로러나 다른 브라우저에서는 무시됩니다. 이 2개의 헤더에 의해 문서는 캐시로부터 가져오기 때문에 문서를 빠르게 표시할 수 있습니다. 캐시는 웹서버의 최신의 문서를 기초로 갱신되므로, 다음에 사용자가 이 페이지를 방문헸을 때에는, 새로이 갱신된 문서가 표시됩니다.
post-check 및 pre-check에 대한 상세한 정보는 http://msdn.microsoft.com/workshop/author/perf/perftips.asp를 참조하세요. (삭제:2010.1.8)
post-check
post-check에 설정된 시간(초)이 지나고 나서부터는 사용자에게 캐시문서를 보낸 후 엔터티가 신선한 지 확인합니다. 문서를 보낸 후(post)에 엔터티가 신선한 지 확인하는 고로 post-check라고 합니다. 이와 같은 이유로 인하여 금번에 받은 문서는 낡은 문서일 수 있습니다. 그러나 다음 방문 때는 새로이 갱신된 캐시문서를 분명히 보게 됩니다.
pre-check
pre-check에 설정된 시간(초)이 지나고 나서부터는 엔터티가 신선한 지 먼저 확인한 후 사용자에게 문서를 보냅니다. 문서를 사용자에게 보내기 전(pre)에 엔터티가 신선한 지 확인하는 고로 pre-check라고 합니다.
post-check 및 pre-check에 의한 캐시 동작
< IE5 캐시 제어 메커니즘 >
브라우저가 캐시에 있는 문서를 가져오도록 요구할 때, HTTP 응답 헤더로 서버에서 클라이언트로 보내지는 캐시 엔트리에 캐시 제어 확장(cache-control extensions)가 포함되어 있으면, 브라우저는 서버로부터 가장 최신의 자료를 가져올 시기를 결정하기 위해 캐시 제어 확장과 다음 로직을 이용하게 됩니다.
- post-check 구간을 아직 지나지 않았다면, 간단하게 캐시로 부터 해당 페이지를 검색합니다.
- 마지막 요구가 있은 후 경과 시간이 post-check와 pre-check 구간 사이에 있다면 캐시로부터 해당 페이지를 보여주고, 갱신된 페이지를 가져와서 캐시에 저장합니다.
- 사용자가 해당 페이지를 재요구한 시간이 pre-check 구간을 지났다면, 우선 HTTP 서버에게 브라우저가 해당 페이지를 마지막으로 요구한 이래로 수정되었는지 확인합니다. 해당 페이지가 수정되었다면 가져와서 갱신된 페이지를 보여줍니다.
Refresh 버튼(F5 키를 포함하여)은 서버에게 항상 if-modified-since 요구를 보내기 때문에 위의 로직에 따라 동작하지는 않을 것입니다. 하이퍼링크(hyperlink)는 위의 로직에 따라 동작합니다.
IE5의 캐시 동작
post-check 및 pre-check 지시자를 지정하게 되면 검색 대상이 되고 있는 문서는 다음과 같은 순서로 캐시가 처리됩니다.
첫째, 사용자가 페이지를 처음으로 방문하면, 문서는 웹서버로부터 취득되어 캐시에 저장됩니다.
둘째, 사용자가 페이지를 2번째에 방문하면, 문서는 캐시로부터 표시되며, 캐시 내의 데이터는 웹서버를 기초로 갱신됩니다.
이후에 문서는 캐시로부터 취득되므로, 페이지는 단시간에 로드되어 그 후로 캐시가 서버의 문서를 기초로 갱신됩니다.
post-check, pre-check에 의한 캐시 제어 구조는 항상 변화를 계속하고 있는 주식 정보 등의 데이터에는 적합하지 않습니다만, 가끔 변경되는 따라서 매회 갱신할 필요가 없는 문서의 경우에는 잘 동작합니다. 예를 들어, MSN.com 사이트의 네비게이션 유저 인터페이스는 자주 바뀌지 않기 때문에, post-check 및 pre-check 설정으로 마크되어 있습니다.
다음은 각각의 캐시 제어 메커니즘에 적합한 조건을 나타내었습니다.
구분 자주 갱신되는 컨텐트 가끔 갱신되는 컨텐트 비교적 정적인 컨텐트
사용예 주식정보 사이트 네비게이션 회사로고
캐시 제어 설정의 예 컨텐츠를 즉시 기한 마감으로 한다.
(예: Expires: 0)
post-check와 pre-check를 사용한다.
(예: Cache-Control: post-check=50, pre-check=100)
유효기간을 먼 미래에 설정한다.
(예: Expires: Thu, 01 Dec 2002 16:00:00 GMT)
Expires 헤더 필드
Expires 엔터티 헤더 필드에 지정된 시간이 지나면 응답이 낡았다고 간주해야 하는 날짜를 제공합니다. 캐시(프록시 캐시 또는 사용자 에이전트 캐시)는 대개 먼저 원서버(또는 엔터티의 신선한 복사본을 가지고 있는 중간 캐시)가 검증하지 않는 한 낡은 캐시 엔트리를 리턴하지 않습니다.
Expires 필드가 존재한다는 것이 그 시간 이전 또는 이후에 원래의 자원이 변경되거나 사라진다는 것을 의미하지는 않습니다.
Expires 필드는 RFC1123-date 포맷으로 작성된 절대 날짜와 시간입니다.
Expires: Thu, 01 Dec 1994 16:00:00 GMT
앞에서도 언급하였듯이 응답이 max-age 지시자를 포함한 Cache-Control 필드를 포함하고 있으면 expires 필드는 무시됩니다.
HTTP/1.1 클라이언트와 캐시는 반드시 다른 유효하지 않는 날짜 포맷을, 특히 "0" 값을 포함하고 있는 날짜 포맷을 지나간 날짜로 취급해야 합니다.(예를 들면 "벌써 만료된(already expired)"으로)
응답을 "벌써 만료된(already expired)" 것으로 표시하기 위해서 원서버는 expires 날짜를 Date 헤더 필드와 동일한 것으로 사용해야 합니다.
응답을 "결코 만료되지 않는(never expires)" 것으로 표시하기 위해서 원서버는 expires 날짜를 대략 응답이 발송된 후 시점부터 1년 후를 지정합니다. HTTP/1.1 서버는 향후 1년 이상된 expires 날짜를 발송하지 말아야 합니다.
기본적으로 캐시할 수 없는 응답에 미래의 특정 시간의 시간값과 함께 expires 헤더 필드가 존재하면 Cache-Control 헤더 필드가 다른 식으로 표시하지 않는 한 응답을 캐시할 수 있다는 것을 표시합니다.
Last-Modified 헤더 필드
Last-Modified 엔터티 헤더 필드는 원서버가 변형자(variant)가 마지막으로 변경되었다고 믿는 날짜와 시간을 표시합니다.
Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT
원서버는 절대 서버의 메시지 발생 시간보다 늦은 Last-Modified 날짜를 발송해서는 안됩니다. 이처럼 자원의 최근 변경이 미래의 특정 시간을 표시하는 경우 서버는 그 날짜를 메시지 발생 날짜로 대체해야 합니다.
기본 서버는 엔터티의 Last-Modified 값을 응답의 Date 값을 생성한 시간과 가능한 한 가까운 것을 얻어야 합니다. 이것은 수신측이 특히 엔터티가 응답이 생성된 시간에 가깝게 변경되었을 때 정확하게 엔터티의 변경 시간을 평가할 수 있도록 합니다.
HTTP/1.1 서버는 가능할 때 마다 반드시 Last-Modified를 발송해야 합니다.
Pragma 헤더 필드
Pragma 일반 헤더 필드는 요구/응답 체인을 따라 어떤 수신측에도 적용할 수 있는 구현 방식에 한정된 지시자(implementation-specfic)를 포함하는데 사용합니다.
Pragma: no-cache
no-cache 지시자는 요구 메시지에 존재하면 애플리케이션은 요구되고 있는 것으 캐시 사본을 가지고 있다 하더라도 요구를 원서버에 전달해야 합니다. 이 Pragma 지시자는 no-cache 캐시지시자와 동일한 의미를 가지며 여기서는 HTTP/1.0과의 호환성 유지를 위해 규정하였습니다. 클라이언트는 no-cache 요구가 HTTP/1.1을 따르지 않는 것으로 알려진 서버로 전달되었을 때 두 헤더 필드를 모두 포함해야 합니다.
HTTP/1.0에서 캐시 등을 제어하기 위해 사용되었으나 HTTP/1.1에서는 사용되지 않습니다. 따라서 HTTP/1.1 클라이언트는 Pragma 요구 헤더를 발송해서는 안됩니다. HTTP/1.1 캐시는 "Pragma: no-cache"를 클라이언트가 "Cache-Control: no-cache"를 발송한 것처럼 취급해야 합니다.
Internet Explorer에서 캐싱 방지
아래 링크는 Microsoft에서 제공하는 캐싱에 관련된 기술자료입니다. 참조바랍니다.
(웹주소수정:2010.1.8) "HOWTO: Internet Explorer에서 캐싱 방지" 문서의 웹주소가 변경되어 수정합니다.

Posted by 방글24
캐시(cache)는 임시 저장소로 웹 브라우저가 홈페이지를 받아오기 전에 먼저 검색하여 똑같은 홈페이지의 내용이 캐시에 있으면 캐시로부터 읽어들입니다. 이와 같이 웹상에서 동작되는 캐시(web cache)에는 각 클라이언트에서 개별적으로 동작되는 브라우저 캐시(browser cache)와 모든 인터넷 또는 인트라넷 상의 사용자가 공유할 수 있는 공유캐시(shared cache)로 동작되는 프록시 캐시(proxy cache)가 있습니다. 본 란에서는 이 중에 브라우저 캐시에 대해서만 살펴보고 최종적으로는 PHP 스크립트로 캐시 동작을 제어하는 캐시리미터(cache limiter) 함수를 작성해 보려고 합니다.
양해 사항
이 문서를 정리한 본인도 캐시리미터 함수를 만들면서 HTTP/1.1 문서를 정식으로 접해봅니다. HTTP/1.1 문서를 읽어본 소감을 말한다면 "이게 무슨 말을 하는 건지......"라고 할까요? 그러니 여러분이 본 내용을 읽다가 의문이 나더라도 제 홈페이지 Q&A 게시판에는 "HTTP/1.1"에 관련해서는 가능하면 질문하지 마시기 바랍니다. 의문나는 사항은 여러분이 직접 HTTP/1.1 문서를 읽어보기 바랍니다.
HTTP/1.1에 관련된 문서들
(수정:2010.1.8) HTTP/1.1 한글문서가 링크된 웹주소가 삭제되어 접속되지 않습니다. 복사본을 참조하세요.
본 란에서는 HTTP/1.1 내용 중에 캐시에 관련된 부분만 일부 정리한 것으로 위에 있는 http://pec.etri.re.kr/~qkim/HTTP/http11v2.html의 "HTTP/1.1 번역서"의 내용에서 주로 발췌한 것입니다. "HTTP/1.1 번역서"의 전체 내용에 관심있는 분은 해당 웹사이트에 가셔서 문서를 다운로드 받아 참조하기 바랍니다.
동적으로 생성되는 웹 컨텐트
동적으로 생성되는 웹 컨텐트의 경우에는 캐시가 동작되어서는 안되는데 HTTP/1.0에는 이를 지원하는 메카니즘이 없기 때문에 사용자(end-users)가 보게되는 정보가 잘못 전달될 수 있습니다. 그러나 HTTP/1.1에는 이러한 오류를 방지할 수 있는 명시적인 캐시 관리 메카니즘을 지원합니다.
HTTP/1.1을 지원하는 서버 및 브라우저
현재 거의 모든 웹브라우저(넷스케이프 4.0, 익스플로러 4.0, 핫자바 1.1)가 HTTP/1.1을 지원하고 있습니다. 새버전의 웹서버들도 거의 모두 HTTP/1.1을 일부 또는 전체를 지원하고 있습니다.
요구(request) & 응답(response)
HTTP 규약은 요구/응답 규약입니다. 클라이언트는 요구 메소드, URI, 규약 버전의 형태로 서버에 요구 메시지를 전송합니다. 요구 변경자, 클라이언트 정보, 서버와의 접속에 사용되는 본문 내용을 포함하는 MIME 유형의 메시지가 뒤따릅니다. 서버는 메시지의 규약 버전 및 성공/실패 코드를 포함하는 상태 정보로서 응답합니다. 서버 정보, 엔터티 메타 정보, 엔터티 본문 내용을 포함하는 MIME 유형의 메시지도 뒤따릅니다.
< 요구 및 응답 체인 >
요구는 HTTP 요구 메시지를 의미하며, 클라이언트로부터 서버로의 요구 메시지는 해당 메시지의 첫 라인 내에 자원, 자원의 식별자 및 사용 중인 규약 버전에 적용할 메소드를 포함합니다.
Request = Request-Line
             * ( general-header
             | request-header
             | Entity-Header )
             CRLF
             [ message-body ]
다른 부분은 위에서 언급한 "HTTP/1.1 번역서"를 참조하기 바라며, 여기서는 일반 헤더(general-header) 필드의 구조만 아래에 적습니다.
general-header = Cache-Control
                       | Connection
                       | Date
                       | Pragma
                       | Transfer-Encoding
                       | Upgrade
                       | Via
위에서 Cache-Control 헤더가 우리가 관심을 가져야 되는 캐시 제어를 구현하는 부분입니다.
응답은 HTTP 응답 메시지를 의미하며, 요구 메시지를 수신하고 해석한 후 서버는 HTTP 응답 메시지로 응답합니다.
Response = Status-Line
                * ( general-header
                | response-header
                | Entity-Header )
                CRLF
                [ message-body ]
요구 메시지 부분과 마찬가지로 여기에도 일반 헤더(general-header) 필드가 있습니다. 일반 헤더는 요구와 응답 메시지에 모두 적용되는 부분으로, 메시지 본문의 내용에 영향을 주지 않는 메시지 전송 관련 헤더입니다.
원서버(origin server)
해당 자원이 보관되어 있거나 자원을 생성할 수 있는 서버
경과시간(age)
응답 메시지의 경과 시간은 원서버로부터 전송된 후,
또는 성공적으로 검증된 후의 시간
신선한 기간(freshness lifetime)
응답의 생성 시점과 만기시간(expiration time) 사이의 시간 길이
신선한(fresh)
응답의 경과시간이 신선한 기간을 넘어서지 않았을 때
낡은(stale)
응답의 경과시간이 신선한 기간을 넘어섰을 때
의미투명한(semantically transparent)
성능을 향상시키고자 하는 목적을 제외하고 캐시 사용이
요구되는 클라이언트나 원서버에 영향을 미치지 않을 때
특정한 요구에 대하여 캐시가 "의미투명한" 동작을 한다고 할 수 있습니다.
캐시가 의미투명한 동작을 할 때 클라이언트는 원서버가 직접 처리했을
때와 완전히 동일한 응답을 받게 됩니다.
사용자 에이전트(user agent)
요구 메시지를 시작하는 클라이언트.
이것은 종종 브라우저, 편집기, 스파이더(웹을 탐색하는 로봇)
또는 다른 사용자 툴이 될 수 있습니다.
서버설정 만기시간(explicit expiration time)
원서버가 캐시된 데이터의 유효성을 보장할 수 있는 시간.
자동설정 만기시간(heuristic expiration time)
서버설정 만기시간을 지정하지 않았을 때 캐시가 스스로 할당하는 만기시간
검증자(validator)
캐시 엔트리가 엔터티의 복사본과 동일한 지 알아내는데 사용하는 규약 요소
(예를 들면 엔터티 태그 또는 Last-Modified 시간)
HTTP/1.1 캐시의 목적
많은 경우에 요구(request)를 발송할 필요를 제거하고 또 다른 많은 경우에 완전한 응답을 발송할 필요를 제거하는 것입니다.
첫째, 요구 발송 감소
많은 운영에서 네트워크의 왕복 여행 숫자를 줄여 줍니다. 이 목적을 위해서 "만기일(expiration)" 메커니즘을 사용합니다.
둘째, 응답 발송 감소
네트워크 대역폭 요구를 감소시켜 줍니다. 이 목적을 위해서 "검증(validation)" 메커니즘을 사용합니다.
만기일 모델(expiration model)
사용자 에이전트(예를 들어 브라우저)가 웹문서를 요구할 때, 캐시에 저장되어 있는 캐시된 문서의 만기일을 확인하며, 이 때 만기일이 지나지 않은 문서라면 캐시된 문서를 브라우저로 응답하게 됩니다. 이러한 경우의 요구/응답 체인은 아래 그림과 같습니다.
< 요구 및 응답 체인(만기일 계산) >
캐시된 문서를 브라우저로 응답하게 되면 위 그림과 같은 예에서는 캐시에서 원서버로 가는 부분이 요구 및 응답 체인에서 빠지게 되며 따라서 네트워크의 동작이 신속히 이루어지게 됩니다. 이와 같이 HTTP 캐시는 원서버로 요구를 발송하는 것을 완전히 피할 수 있을 때 최상으로 동작합니다.
요구를 피하는 주요 메커니즘은 원서버가 분명하게 해당 응답이 계속되는 요구를 만족시킬 수 있다는 것을 표시하는 미래의 만기시간을 제공하는 것입니다. 다른 말로 표현하면 캐시가 먼저 서버와 접촉하지 않고도 새로운 응답을 리턴할 수 있다는 것입니다.
이와 같이 HTTP 요구 발송을 감소시키기 위한 방법으로 사용하게 되는 만기일은 원서버가 문서를 발행할 때 함께 지정할 수도 있으며 원서버에서 지정하지 않았을 때는 캐시에서 스스로 알아서 만기일을 계산하여 지정하게 됩니다.
"HTTP/1.1 번역서"에는 expiration을 "유효일"이라고도 번역되어 있고
"만기일"이라고도 번역되어 있습니다.
반면 Microsoft 웹사이트에서는 이를 "만료날짜"라는 용어를 사용합니다.
여기서는 모두를 대표하여 "만기일"이라는 용어를 사용하겠습니다.
만기일 메커니즘은 캐시에서 얻은 응답에만 적용되며 요구한 클라이언트에게 직접적으로 전달되는 첫 응답에는 적용되지 않습니다.
서버설정 만기일(server-specified expiration)
우리가 기대하는 것은 서버가 만기일이 도착 전에 엔터티가 의미상으로 중대하게 변화하지 않을 것이라는 믿음으로 미래의 분명한 만기시간을 부여하는 것입니다. 이렇게 하면 서버의 만기시간이 신중하게 선택되는 한 대개의 경우에 의미투명성을 보존합니다.
서버는 expires 헤더 또는 Cache-Control 헤더의 max-age 지시자를 사용하여 만기시간을 지정합니다.
원서버가 모든 요구를 검증하기 위해 의미투명한 캐시를 요구한다면 과거 시점의 만기시간을 부여할 수도 있습니다. 이는 응답이 항상 낡은 것이기 때문에 계속되는 요구에 이것을 사용하기 위해서는 반드시 먼저 검증을 해야 한다는 것을 의미합니다.
원서버가 HTTP/1.1 캐시가 모든 요구를 강제로 검증하도록 하려면 어떤 방식으로 환경이 설정되었든 "must-revalidate" Cache-Control 지시자를 사용해야 합니다.
자동설정 만기일(heuristic expiration)
원서버가 언제나 서버설정 만기시간(explicit expiration time)을 제공하는 것이 아니므로, expires 및 cache-control: max-age 모두가 응답에 없으면 HTTP 캐시는 전형적으로 그럴듯한 만기시간을 짐작하기 위해 다른 헤더값(last-modified 시간과 같은)을 사용하는 알고리즘을 활용하는 자동설정 만기시간(heuristic expiration time)을 할당합니다. 자동설정 만기시간은 의미투명한 동작을 하지 않을 수도 있기 때문에 조심해서 사용해야 하며 가능한 한 원서버가 서버설정 만기시간을 제공하도록 권고합니다.
만기일 계산
응답이 신선한 것인지 낡은 것인지 결정하기 위해 경과시간(age)과 신선한 기간(freshness lifetime)을 비교할 필요가 있습니다.
max-age 지시자는 expires 보다 우선권을 갖습니다. 따라서 응답에 max-age 지시자가 있으면 이 지시자가 가지고 있는 값이 신선한 기간이 됩니다. 그렇지 않고 expires가 응답에 있으면 expires 헤더값에서 원서버의 Date 값을 빼 준 값이 신선한 기간이 됩니다.
신선한 기간 = max-age 값 또는
신선한 기간 = expires 값 - 원서버의 Date값
경과시간이 신선한 기간을 넘어서지 않았을 때 응답이 신선하다고 할 수 있으며, 이 때는 원서버에 계속 요구하지 않고 캐시된 문서를 브라우저에 보내게 됩니다.
신선한 응답 = 신선한 기간 > 경과시간
검증 모델(validation model)
캐시가 클라이언트 요구에 대한 응답으로 사용하고자 하는 낡은 엔트리를 가지고 있을 때 캐시된 엔트리를 아직도 사용할 수 있는지 알아보기 위해서 클라이언트는 먼저 원서버(또는 새로운 응답을 가진 중간 캐시)를 점검해야 합니다. 이것을 캐시 엔트리를 "검증한다"고 합니다.
< 요구 및 응답 체인(캐시 엔트리 검증) >
최종 갱신 날짜(last-modified dates)
Last-Modified 엔터티 헤더 필드 값은 종종 캐시 검증자로 사용됩니다. 간단히 말하면 캐시 엔트리는 엔터티가 Last-Modified 값 이후에 변경되지 않았으면 유효한 것으로 간주된다는 것입니다.
엔터티 태그 캐시 검증자(validators)
ETag 엔터티 헤더 필드 값, 엔터티 태그는 "불투명한" 캐시 검증자를 제공합니다. 이 검증자는 변경된 날짜를 저장하는 것이 불편한 상황에서, HTTP 날짜 값을 1초 동안 분석하는 것이 충분하지 않은 상황에서 또는 원서버가 변경된 날짜를 사용하여 발생하는 특정 역설을 피하고자 하는 상황에서 좀 더 신뢰성있는 검증을 가능하게 합니다.
응답 캐시 정도(response cachability)
다음 장에서 설명하는 Cache-Control 지시자가 특별히 통제하지 않는 한 캐시 시스템은 언제나 성공적인 응답을 캐시 엔트리로서 저장할 수 있고, 신선한 것이라면 검증없이 리턴할 수 있으며 성공적인 검증 후에 리턴할 수도 있습니다.
캐시 검증자도 없고 응답과 관련된 명확한 만기시간도 없는 문서는 이 문서가 캐시될 것이라고 생각되지 않습니다. 그러나 네트워크가 약하게 연결되었거나 연결되지 않았을 때와 같은 경우에는 캐시된 문서가 제공될 수 있으며, 클라이언트는 보통 이러한 응답이 캐시에서 나왔다는 것을 Date 헤더와 현재 시간을 비교하여 탐지할 수 있습니다.
그러나 어떤 경우에는 캐시가 엔터티를 보유하고 있는 것이, 또는 캐시를 계속되는 요구에 대한 응답으로 리턴하는 것이 적절하지 않을 수 있습니다. 이는 서비스 저작자가 완전한 의미투명한 문서를 제공하려고 하거나 또는 보안이나 사생활 보호에 관한 고려 사항 때문입니다. 다른 고려 사항에 관계없이 특정 엔터티 또는 엔터니의 일부를 캐시할 수 없다는 것을 표시하기 위해 특정 Cache-Control 지시자가 제공되었습니다.
캐시의 정확성
정확한 캐시는 반드시 아래의 조건 중 하나를 만족하며 요구에 적합한 보유하고 있는 캐시 중 가장 최근의 응답으로 요구에 답해야 합니다.
1. 원서버가 원서버를 사용하여 응답을 재검증한 후 되돌려 주었을 것과 같은 것인지 점검하였다.
2. 충분히 신선하다. 기본적인 경우 이것은 클라이언트, 서버 및 캐시의 최소한도의 신선도 필요 조건을 만족한다는 것을 의미한다. 원서버가 그렇게 명시하였으면 그것은 원서버의 신선도 필요 조건일 뿐이다.
3. 클라이언트 또는 서버의 신선도 요구가 위반되었을 경우 경고를 포함하고 있다.
4. 적절한 304(Not Modified), 305(Use Proxy), 또는 error(4xx 또는 5xx) 응답 메시지이다.
캐시가 원서버와 통신할 수 없다면 정확한 캐시는 위처럼 응답해야 합니다(캐시가 정확한 응답을 할 수 있다면). 그렇지 못하면 캐시는 통신 실패가 있었음을 알리는 에러 또는 경고를 리턴해야 합니다.
캐시와 history 메커니즘의 차이점
사용자 에이전트는 종종 "이전" 버튼과 history 목록과 같은 history 메커니즘을 사용합니다. 이것은 세션에서 이전에 조회한 엔터티를 다시 화면에 표시하기 위해 사용합니다.
history 메커니즘과 캐시는 다릅니다. 특히 history 메커니즘은 자원의 현재 상태를 의미상 투명한 모양으로 보여 주려 시도해서는 안됩니다. history 메커니즘은 자원을 조회했을 때 사용자가 본 것과 동일한 것을 보여 주기 위한 것입니다.
기본적으로 만기시간은 history 메커니즘에 적용되지 않습니다. 엔터티가 여전히 저장소에 있으면 history 메커니즘은 엔터티가 만료되었다 할 지라도 사용자가 만료된 history 문서를 갱신하도록 상세하게 에이전트의 환경을 설정하지 않는 한 이것을 보여 주어야 합니다.
이것은 history 메커니즘이 사용자에게 현재의 화면이 낡은 것일 수도 있음을 알리는 것을 금지하는 것으로 해석해서는 안됩니다.
history 목록 메커니즘이 불필요하게 사용자가 낡은 자원을 볼 수 없도록 한다면 이는 서비스 저작자들에게 그렇지 않았더라면 사용하고 싶어하는 HTTP 만기일 제어 및 캐시 제어의 사용을 피하도록 강요할 수 있습니다. 서비스 저작자들은 그들이 운행제어("이전" 버튼과 같은 navigaton control)를 사용하여 이전에 가져온 자원을 보고자 할 때 사용자에게 에러 메시지나 경고 메시지를 표시하지 않는 것이 중요하다고 생각할 수 있습니다. 때때로 이러한 자원을 캐시하지 말거나 빨리 만료해야 할 수도 있지만 서비스 저작자들은 사용자 인터페이스를 고려하여 사용자가 history 메커니즘이 부적합하게 작동하여 고통을 받지 않도록 캐시를 방지할 수 있는(예를 들어 "once-only" URL) 다른 방법에 호소하도록 만듭니다.

Posted by 방글24
캐시 설정 화면
넷스케이프 4.0
"편집"을 클릭하고, 다음엔 "환경설정", 그 다음엔 "고급"과 "+" 아이콘을 클릭하십시오. 확장된 트리에서 "캐시"를 선택하십시오.
< 넷스 4.0에서의 캐시 설정 화면 >
익스플로러 4.0
"보기"를 클릭하고, "인터넷 옵션..."을 클릭, 다음에는 일반 탭에서 "임시 인터넷 파일"안에 있는 "설정..."을 선택하십시오.
익스플로러 5.0
"도구"를 클릭하고, "인터넷 옵션..."을 클릭, 다음에는 일반 탭에서 "임시 인터넷 파일"안에 있는 "설정..."을 선택하십시오.
< 익스 5.0에서의 캐시 설정 화면 >
캐시 동작 설정
넷스 4.0 익스 5.0 캐시문서와 네트워크에 위치한 문서비교
세션 당 한번 IE를 시작할 때마다 브라우저를 처음 실행시킬 때
단 한번만 문서가 변경되었는지 확인
항상 페이지를 열 때마다 문서를 열때마다 문서가 갱신되었는지 확인
안함 확인하지 않음 캐시된 문서가 있으면 문서 변경에 관계없이
캐시된 문서를 읽어 옴
- 자동으로 ???
캐시된 문서와 네트워크에 위치한 문서 비교는 캐시된 페이지와 사이트의 페이지를 언제 비교할 것인가 지정하는 것으로 "세션 당 한번", "항상", "안함" 중에 선택하게 되는 데 각 설정에 대한 동작은 아래와 같습니다.
세션 당 한번(Once per session)
세션당 한번만 비교합니다. 넷스를 실행한 다음 종료할 때까지 한번만 페이지의 갱신 정보를 점검합니다.
항상(Every Time)
선택하면 페이지를 오픈하는 속도는 저하되지만 페이지를 열 때마다 매번 그 페이지의 갱신 정보를 점검합니다.
안함(Never)
선택하면 페이지의 갱신 정보를 점검하지 않으므로 캐시에 저장된 페이지를 항상 오픈합니다. 이 경우에는 캐시된 문서가 없을 때만 네트워크에 위치한 문서를 읽어오게 됩니다.
웹 검색 중 어느 때라도 갱신된 페이지를 원할 때는 "다시읽기"(넷스) 또는 "새로고침"(익스) 버튼을 누르면 됩니다. 그러면 즉시 갱신 정보를 점검합니다. 이때 만약 페이지가 갱신되어있지 않다면 캐시에 저장된 페이지를 다시 오픈합니다. 그러나 페이지가 갱신되었다면 네트워크 상의 서버로부터 갱신된 페이지를 새롭게 오픈합니다. 시프트 키를 누른 상태에서 다시읽기 버튼을 누르면 무조건 캐시의 내용이 아닌 네트워크상의 서버로부터 페이지를 읽어옵니다
자동으로(익스에서만 설정 가능함)
??????
캐시 저장 디렉토리 및 파일
넷스케이프 4.0
C:\Program Files\Netscape\Users\xxxxxxxx\cache에 캐시 문서를 저장합니다. 디렉토리명의 중간에 있는 xxxxxxxx는 네트워크환경 설정에 기록된 컴퓨터이름이 들어갑니다. 컴퓨터이름을 지정하지 않았다면 default라는 이름이 들어갑니다.
익스플로러 4.0, 5.0
C\windows\Temporary internet files에 캐시 문서를 저장됩니다.
캐시 공간 확보
캐시 공간을 적당히(?) 확보해 놓으면 보다 빠르게 웹검색을 할 수 있습니다. 익스플로러는 디스크 캐시 공간을 사용자가 설정할 수 있는 반면 넷스케이프는 디스크 캐시뿐만 아니라 메모리 캐시 공간도 사용자가 임의 설정할 수 있습니다.
넷스와 익스 모두 캐시 설정 화면에서 캐시 공간 크기를 설정할 수 있습니다. 넷스는 메모리 캐시와 디스크 캐시 크기를 KBytes 단위로 설정할 수 있으며, 익스는 디스크 캐시에 대해서만 MB 단위로 설정할 수 있습니다.
캐시 문서 삭제
동적인 콘텐트를 제공하는 웹사이트를 접속할 때에 브라우저 캐시 동작에 의해 과거의 문서가 브라우저 화면에 나타나서 문제가 발생할 수 있습니다. 이럴 때는 브라우저 캐시를 지워주어야 합니다.
넷스케이프 4.0의 경우에는 위쪽에 있는 캐시 설정 화면에서 "메모리 캐시 삭제" 및 "디스크 캐시 삭제" 버튼을 누르시면 됩니다.
익스플로러 5.0에서는 "도구메뉴 >> 인터넷옵션 >> 일반탭 >> 임시 인터넷 파일"에서 "파일삭제" 버튼을 누르시면 됩니다. 다른 방법으로 내컴퓨터=>C:\windows\Temporary Internet files 디렉토리에서 전체파일을 삭제할 수도 있습니다.
< 익스 5.0에서의 캐시 삭제 >
캐시 동작 중에 수정된 내용을 보려면
때에 따라서는 캐시된 문서가 아닌 새로운 문서를 보아야 할 필요가 있습니다. 이와 같이 캐시가 동작하고 있는 중에 새로운 문서를 보려고 할 때는 다음과 같이 해 보세요.
1. 브라우저의 새로고침(익스) 또는 다시읽기(넷스) 버튼을 누릅니다.
   안되면...
2. shift 버튼을 누른채로 새로고침(익스) 또는 다시읽기(넷스) 버튼을 누릅니다.
   안되면...
3. 캐시 문서를 모두 지운 후 새로고침(익스) 또는 다시읽기(넷스) 버튼을 누릅니다.
   안되면...
4. 웹브라우저를 종료했다가 다시 실행합니다.
   안되면....
5. 컴퓨터를 재부팅한 후 처음부터 다시 해봅니다.
만약에 그래도 안되면... 문서가 변경되지 않은 경우이겠지만 혹시 문서가 변경되었는데도 안된다면 최후 수단으로 컴퓨터 부품을 교환합니다??? (어떤 부품을 갈아야 하는 지는 저도 모름).
캐시 정보 확인
넷스케이프에서는 about이라는 명령을 이용하여 디스크 캐시, 메모리 캐시 및 이미지 캐시 정보를 확인할 수 있습니다.
1. about:cache
2. about:memory-cache
3. about:image-cache
'about:cache'는 디스크에 축적돼 있는 디스크 캐시 상태를 보여줍니다. 'about:memory-cache'는 메모리 캐시 내용을 보여줍니다. 'about:image-cache'는 GIF 또는 JPEG 등의 이미지 정보를 보여줍니다.
< 넷스 4.0에서의 디스크 캐시 정보 >
< 넷스 4.0에서의 메모리 캐시 정보 >
< 넷스 4.0에서의 이미지 캐시 정보 >

Posted by 방글24
브라우저 캐시의 필요성
브라우저 캐시는 클라이언트 시스템에 있는 디스크 또는 메모리를 이용하기 때문에 클라이언트 캐시(client cache)라고도 합니다. 한 번 접속했던 웹 사이트들의 내용을 사용자의 메모리 또는 디스크의 캐시 디렉토리에 일시적으로 저장해 놓았다가 또 다시 같은 사이트에 접속하게 되면 캐시된 문서와 사이트에 위치한 문서를 서로 비교하여 웹 페이지의 내용이 바뀌었을 경우에만 사이트로 직접 가서 내용을 읽어 오고, 바뀌지 않았을 경우에는 캐시된 문서를 읽어서 보여 주게 되므로, 웹 문서를 빠르게 보여줄 수 있습니다.
브라우저 캐시의 종류
캐시 기능에는 메모리 캐시(memory cache)와 디스크 캐시(disc cache)가 있습니다.
메모리 캐시(memory cache)
메모리 캐시는 컴퓨터 내부의 주기억장치인 램의 일정 영역을 브라우저의 캐시 기능으로 할당하는 것으로서, 사용자가 자신의 주메모리의 크기를 고려하여 임의로 설정할 수 있습니다. 단, 이 메모리 캐시 영역에 일시적으로 저장되는 내용은 브라우저를 종료함과 동시에 자동적으로 지워지게 됩니다.
디스크 캐시(disc cache)
디스크 캐시는 브라우저를 종료한 후에도 캐시의 내용을 계속 저장하고 있는데, 그것은 주기억장치가 아닌 보조기억장치인 사용자의 하드디스크 드라이브의 일정 영역에 저장해 놓기 때문입니다. 따라서 브라우저를 다시 시작하더라도 이전에 캐시된 내용을 이용할 수 있기 때문에 빠른 웹검색이 가능합니다.

Posted by 방글24
애플리케이셔너 0.0.2(2001.5.30)
  • register(), unregister() 메소드를 삭제하였으며 따라서 lock(), unlock() 메소드 만으로 방문자공용변수를 제어합니다.
  • 애플리케이셔너 배열 변수 $APPL_VARS[]를 삭제하였습니다.
  • 실행속도 향상을 위해 객체 생성시 모든 방문자공용변수를 복원하던 것을 수정하여 해당 페이지에서 사용하는 변수값만 복원합니다.
애플리케이셔너 0.0.1(2000.11.21-최초 공개 버전)
  • 애플리케이셔너는 모든 방문자가 공용으로 사용할 수 있는 변수(방문자공용변수)를 사용할 수 있도록 제작된 라이브러리로, ASP의 애플리케이션 객체와 같은 역할을 합니다.

Posted by 방글24
생성자
방문자공용변수가 저장되는 장소(디렉토리 또는 디비 테이블명)를 변경할 필요가 없으면 아래와 같이 입력인자 없이 객체를 생성합니다.
[code php;gutter:false] $appl = new Applicationer;
.
.
. [/code]
파일시스템용에서 저장되는 디렉토리를 변경하려면 아래와 같이 생성자의 입력인자인 배열의 요소 "resource"에 디렉토리명을 지정하십시요.
[code php;gutter:false] require("./class.applfile.php");

$argv["resource"] = "새로운 디렉토리명";
$appl = new Applicationer($argv);
.
.
. [/code]
데이터베이스용에서 저장되는 테이블을 변경하려면 아래와 같이 생성자의 입력인자인 배열의 요소 "resource"에 테이블명을 지정하십시요.
[code php;gutter:false] require("./class.applbase.php");

$argv["resource"] = "새로운 테이블명";
$appl = new Applicationer($argv);
.
.
. [/code]
사용자 메소드
bool lock(string varlist | array varlist);
lock() 메소드에 전달되는 방문자공용변수 중에 아직 등록되지 않은 변수가 있으면 lock() 메소드 내부에서 자동적으로 등록시켜 줍니다. 반대로 방문자공용변수에 할당된 값이 null이면 등록을 취소(해당 변수에 대한 모든 정보를 삭제함)합니다. 이 함수의 역할은 다른 방문자가 지정된 변수를 조작할 수 없도록 막아줍니다. lock() 메소드로 지정된 방문자공용변수는 오직 lock() 시킨 문서에서만 그 값을 수정할 수 있습니다. 다른 방문자(다른 웹문서)에서 해당 변수를 사용할 수 있도록 하기 위해서는 unlock() 메소드로 풀어주어야 합니다.
[code php;gutter:false] $appl->lock("counter");

if (!$appl->counter)
$appl->counter = 100; // 100부터 카운팅 시작

$appl->counter++;

$appl->unlock("counter"); [/code]
복수의 방문자공용변수를 lock, unlock 하려면 배열을 이용하여 전달합니다.
[code php;gutter:false] $appl->lock(array("counter", "stock"));
.
.
.
$appl->unlock(array("counter", "stock")); [/code]
bool unlock(string varlist | array varlist);
다른 방문자가 lock() 으로 지정된 변수를 조작할 수 있도록 하기 위해 lock를 풀어주는 메소드입니다. 만약 unlock에서 지정된 변수의 값이 빈문자열이면 더 이상 필요없는 변수라고 판단하여 파일 또는 디비에 등록되어 있는 변수를 완전히 삭제시켜 줍니다.
사용 예제
첨부된 사용예제(파일명 test.php3)는 세션함수를 이용하기 때문에 만약 PHP3에서 실험하기위해서는 제가 공개한 세셔너를 추가로 다운로드 받아 같은 디렉토리에 복사하여야 합니다. 그리고 디비용 애플리케이셔너를 실험하기 위해서는 미니디비 0.2.2p1 버전이 필요하니 이것도 필요하면 다운로드하여 같은 디렉토리에 복사하여야 합니다.

Posted by 방글24
애플리케이셔너 개요
MS의 ASP에서 사용되는 Application 객체에서와 같이 웹애플리케이션에서 모든 방문자가 데이터를 공유할 수 있는 변수를 등록하여 사용할 수 있도록 해 줍니다. 방문자공용변수와 동일한 기능을 수행하는 것이지만, 사용자 인터페이스가 매우 간결해졌기 때문에 방문자공용변수보다 사용하기가 훨씬 편합니다.
애플리케이셔너란?
애플리케이셔너(Applicationer)는 PHP3 & PHP4에서 동작되는 클래스로 작성된 방문자공용변수를 사용할 수 있도록 제작된 툴로 ASP의 애플리케이션 객체와 같은 역할을 합니다.
저장 매체
애플리케이셔너에서 지원하는 저장 매체는 파일시스템과 데이터베이스이고, 파일시스템과 데이터베이스 모두를 동일한 인터페이스로 사용할 수 있도록 작성되어 있습니다. 따라서 향후 동일한 코드로 저장 매체만 변경할 경우 애플리케이셔너 파일을 인클루드하는 부분만 변경하면 됩니다.
< 애플리케이셔너의 구성 >
애플리케이셔너의 파일 구성
애플리케이셔너는 저장매체에 따라 별도로 작성되어 있습니다. 파일시스템을 위해 개발된 class.applfile.php와 데이터베이스를 위해 개발된 class.applbase.php가 있습니다. class.applbase.php의 경우는 별도로 DB Layer인 MiniDB가 필요합니다.
저장 매체 파일명
파일시스템 class.applfile.php
데이터베이스 class.applbase.php
파일시스템용 애플리케이셔너
파일시스템을 이용한 애플리케이셔너는 디폴트로 /tmp 디렉토리에 파일로 저장할 수 있습니다. "/tmp"는 웹서버 상에 공유하는 임시 디렉토리이므로, 하나의 서버로 여러 명이 사용하는 경우, 예를 들면 직접 웹서버를 운영하는 것이 아니고 웹호스팅 서비스를 받는 경우에는 아래와 같이 생성자를 통하여 이 디렉토리를 자신의 웹사이트에서만 접근할 수 있는 디렉토리로 변경할 필요가 있습니다.
[code php;gutter:false] <?php

require("./class.applfile.php");

$argv["resource"] = "/home/httpd/phpclass/applicationer";
$appl = new Applicationer($argv);
.
.
. [/code]
위에서 지정된 디렉토리 내에 방문자공용변수에 대한 정보가 기록되어 있는 파일들이 저장됩니다. 각 변수마다 별도의 파일에 그 정보가 기록 유지됩니다. 결국 애플리케이셔너 디렉토리에는 현재 웹사이트에서 사용되고 있는 방문자공용변수의 수량만큼의 파일이 존재합니다. 이 파일명은 "appl_$varname"입니다. 여기서 $varname은 방문자공용변수명을 나타냅니다.
복수의 방문자가 동일한 방문자공용변수를 사용할 때 발생할 지도 모르는 변수값의 불확실성을 해결하기 위해 "appl_$varname" 파일에 대한 locking 및 unlocking이 필요하며, 이러한 locking 및 unlocking 역할을 할 파일이 또 하나 필요합니다. 이 파일명은 "appllock_$varname"입니다. 애플리케이셔너 디렉토리에 해당변수에 대한 lock 파일이 없으면 unlocking 상태이고, lock 파일이 있으면 locking 상태입니다.
데이터베이스용 애플리케이셔너
데이터베이스용의 경우(파일명:class.applbase.php)에는 내부적으로 미니디비를 이용하기 때문에 애플리케이셔너 객체를 생성하기에 앞서 미니디비 객체를 생성하여야 합니다.
[code php;gutter:false] <?php

require("./class.mysql.php"); // 미니디비(MySQL용) 0.2.2
require("./class.applbase.php"); // 애플리케이셔너(디비용) 0.0.2

$base = new MiniDB(
"디비 호스트명",
"사용자 id",
"디비 패스워드",
"디비명",
"접속방식"
);
$appl = new Applicationer;
.
.
. [/code]
데이터베이스를 이용하는 애플리케이셔너는 여러가지 데이터베이스를 다루기 위해 내부적으로 공개된 DB 레이어인 미니디비를 사용하기 때문에 미니디비에서 지원되는 데이터베이스를 애플리케이셔너에서도 그대로 사용할 수 있습니다. 미니디비에 대해서는 미니디비 메뉴를 참조하세요. 현재(2001.6)까지 MiniDB에서 지원되는 데이터베이스로는 MySQL, 오라클, 포스트그레스, 사이베이스, MSQL, MSSQL, Informix가 있습니다.
데이터베이스용 애플리케이셔너에서 사용하는 디비 테이블명은 "Applicationer"입니다. 만약 이 테이블명을 변경하려면 아래와 같이 생성자의 입력인자로 테이블명을 지정하여 줍니다.
[code php;gutter:false] <?php

require("./class.mysql.php"); // 미니디비(MySQL용) 0.2.2
require("./class.applbase.php");

$argv["resource"] = "새로운 테이블명";
$appl = new Applicationer($argv);
.
.
. [/code]
데이터베이스용 애플리케이셔너에서의 locking 및 unlocking
아래에 있는 애플리케이셔너의 테이블 구조(MySQL용)를 보면 알 수 있지만, 현재 방문자공용변수를 사용 중인지 아닌지를 나타낼 수 있는 필드 islock가 준비되어 있습니다. 이 필드에 "0"이 기록되어 있으면 현재 필드를 어떠한 방문자도 사용하고 있지 않는 상태이므로 현재 필드에 해당하는 방문자공용변수를 자유롭게 읽고 쓸 수 있습니다. 그러나 이 필드에 "1"이 기록되어 있으면 누군가 현재 필드를 사용하고 있는 상태를 나타내므로 이 때는 이 필드에 기록되어 있는 방문자공용변수를 다룰 수 없습니다.
[code sql;gutter:false] CREATE TABLE Applicationer (
id varchar(255) not null PRIMARY KEY,
value text not null,
islock SET("0","1") not null DEFAULT "0",
lastused int(8)
); [/code]
대기 시간(Waiting Time)
만약 다른 방문자가 임의의 방문자공용변수를 다루기 위해 lock 파일을 생성하거나 또는 islock 필드에 "1"이 기록한다면 또 다른 방문자의 스크립트는 대기 상태에 들어가게 됩니다. 최대 대기 시간은 5초로 설정되어 있으며, 이 대기 시간 내에 현재 방문자공용변수를 사용하고 있는 스크립트가 사용을 끝내고 lock 파일을 삭제하거나 또는 islock 필드에 "0"으로 설정한 후 종료하게 됩니다. 그러면 대기 상태에 있던 또 다른 스크립트가 해당하는 방문자공용변수를 사용할 수 있게 됩니다. 5초로 설정된 최대 대기 시간은 비상시를 대비하여 설정된 시간이며, 접속하는 방문자가 많다고 하더라도 대부분의 경우에는 수(십) 밀리세컨드 이내에 제어권을 되돌려 받게 될 것입니다. 최대 대기 시간이 지나도록 lock 파일이 존재하거나 또는 islock 필드의 값이 계속 "1"인 경우에는 강제로 lock 파일을 삭제하거나 islock 필드의 값을 "0"으로 재설정한 후 해당하는 방문자공용변수를 다룰 수 있게 해 줍니다. 애플리세이셔너가 이러한 알고리즘을 이용하기 때문에, 전부 또는 전무를 요구하는 트랙잭션 처리로 얻어지는 100% 신뢰성있는 데이터를 제공하지는 않습니다. 100% 신뢰성있는 데이터를 얻기를 원한다면 소스코드를 수정하여 데이터베이스에서 제공하는 트랙잭션 기능을 이용하여야 할 것 입니다.

Posted by 방글24
세셔너와 애플리케이셔너의 공통점
세셔너와 애플리케이셔너 모두 웹애플리케이션 전체에 사용되는 변수를 등록하여 다룰 수 있게 해줍니다.
변수의 사용범위(scope)
방문자를 기준으로 하여 변수의 사용범위를 구분하게 되면, 세셔너는 특정 방문자에게만 적용되는 변수를 다룰 수 있도록 해 주지만, 애플리케이셔너는 모든 방문자가 공유하여 읽고 쓸 수 있는 변수(방문자공용변수)를 등록하여 다룰 수 있도록 해 줍니다. 방문자공용변수로 사용될 수 있는 대표적인 예로는 카운터를 들 수가 있습니다. 방문자가 웹사이트에 접속할 때마다 카운터도 하나씩 증가하게 됩니다.

Posted by 방글24