파일시스템용, MySQL용 1.0.0 (2003.4.25)
  • 파일명 변경(class.hCache.php -> class.hCacheFile.php)
  • 클래스명 변경(hCache -> hCacheFile)
  • garbage collection 핸들러 gc()를 private 함수 _gc()로 변경 - 이전 버전에서는 보통 객체 생성한 후에 garbage collection 핸들러를 명시적으로 실행하여야 하였으나 이를 open 함수 내에서 동작하도록 수정하였습니다.
  • garbage collection period를 0으로 설정하면 garbage collection을 수행하지 않습니다.
  • 2명 이상의 방문자가 동시에 방문하였을 때 garbage collection 동작은 단 한명에게만 허용
  • 한 문서에서는 객체 생성을 몇 번을 하던지 관계없이 garbage collection을 디렉토리별로 한번만 수행
  • 하나의 객체에서 여러 개의 캐시 파일을 다룰 수 있도록 save_id() 함수를 추가
  • 캐시파일의 내용을 URL을 통해 불법적으로 접근하는 경우에 그 내용이 웹브라우저에 나타나지 않도록 개선
파일시스템용 0.0.2(2002.7.19)
  • PHP_OS 상수를 이용하여 서버가 윈도우 시스템인지 아닌지 자동 판별
[code php;gutter:false] $this->WIN32 = ("WIN32" == PHP_OS) ? true : false; [/code]
  • 캐시파일명으로 사용되는 $this->ID는 생성자에서 반드시 지정하여 주어야 합니다.
[code php;gutter:false] $cache = new hCache (array("id" => cache id)); [/code]
  • 파일시스템용 후키 캐시만 지원
  • 파일시스템용 후키 캐시 파일명 변경(class.hCacheHandler.php -> class.hCache.php), 클래스명은 hCache로 이전 버전과 동일함
파일시스템용 0.0.1p3(2002.4.25)
  • $HTTP_ENV_VARS["windir"] 문제 발생
윈도우 시스템 또는 PHP 버전에 따라 $GLOBALS["HTTP_ENV_VARS"]["windir"] 가 제대로 동작하지 않고 $GLOBALS["HTTP_ENV_VARS"]["WINDIR"] 로 지정해야 동작하는 경우도 있네요... 그래서 일단 iswin() 함수를 아래와 같이 재수정합니다.
[code php;gutter:false] function iswin() {
return ($GLOBALS["HTTP_SERVER_VARS"]["WINDIR"] ? true : false);
} [/code]
파일시스템용 0.0.1p2
  • 서버가 윈도우 시스템인지 아닌지 자동 판별하는 함수 추가
[code php;gutter:false] function iswin() {
if ($GLOBALS["HTTP_ENV_VARS"]["windir"]) {
return true;
} else {
return false;
}
} [/code]
위 함수에 의해 아래와 같이 생성자 내에서 멤버변수 WIN32를 자동 설정합니다.
[code php;gutter:false] function hCache($arg=NULL) {
.
.
.
$this->WIN32 = $this->iswin();
.
.
.
} [/code]
  • register_globals 값이 off일 때의 문제점 수정
[code php;gutter:false] function hCache($arg=NULL) {
$this->ID = get_class($this) . strtr($GLOBALS["HTTP_SERVER_VARS"]["PHP_SELF"],
$this->get_path_separator(), "_");
.
.
.
} [/code]
$GLOBALS["PHP_SELF"] 을 $GLOBALS["HTTP_SERVER_VARS"]["PHP_SELF"] 으로 수정합니다. $GLOBALS["PHP_SELF"]의 경우를 보면 PHP 버전에 따라 php.ini 파일 중 register_globals 값이 off일 때 제대로 동작하지 않습니다. 버전에 관계없이 정상적으로 동작시키기 위하여 $HTTP_SERVER_VARS를 통해 PHP_SELF 값을 얻습니다.
파일시스템용 0.0.1p1(2002.4.22)
  • 윈도우 시스템에서보면 라인끝을 CR/LF로 나타내느냐? LF로 나타내느냐에 따라 serialize()/unserialize() 함수가 제대로 동작하지 않습니다. 이를 해결하기 위해 메소드 read에서 파일 내용을 읽을 때 file 함수 대신에 fread 함수를 이용하였습니다.
[code php;gutter:false] function read() {
$cache_file = $this->PATH . $this->ID;
if (!file_exists($cache_file)) {
return false;
}
return @implode("", @file($cache_file));
} [/code]
[code php;gutter:false] function read() { // patch#1
$cache_file = $this->PATH . $this->ID;

if ($fp=@fopen($cache_file, "r")) {
$str = fread($fp, filesize($cache_file));
fclose($fp);
} else {
return false;
}

return $str;
} [/code]
 으로 수정합니다.
MySQL용 0.0.1-beta1(2002.1.29)
  • MySQL용으로 제공
파일시스템용 0.0.1-beta1(2002.1.29-최초 공개 버전)
  • open, gc, destroy, read, write, close 핸들러 제공
  • 생성자의 캐시 설정값으로는 update, id, period, maxlifetime, path를 지정할 수 있음

Posted by 방글24
제공되는 함수
<표1> 제공되는 함수
생성자 및 함수 사용가능 버전 기능
open all 캐시 열기
close all 캐시 닫기
save_id 1.0.0 캐시 ID 지정
read all 캐시 데이터 읽기
write all 캐시 데이터 쓰기
destroy all 캐시 데이터 지우기
save_id() 함수는 생성된 하나의 객체를 통해 다중 캐시 데이터를 다루기 위해 1.0.0 버전부터 제공되는 함수입니다.
1.0.0 이전 버전에서 제공되던 gc() 함수는 불필요한 쓰레기를 청소하는 garbage collection을 위해 작성된 함수입니다. 1.0.0 버전부터는 gc() 함수가 open() 함수 내에 포함되어 자동으로 수행됩니다. 따라서 1.0.0 버전부터는 gc() 함수를 사용할 수 없습니다.
bool open();
이 함수는 캐시를 열 때 사용합니다. 현재는 불필요한 캐시 데이터를 청소하는 garbage collection을 주로 수행하고 있습니다.
이 함수가 수행된 이후에 각 캐시 데이터에 대하여 save_id(), read(), write(), destroy() 함수를 이용하여 각각의 캐시 데이터를 다룰 수 있습니다.
이 함수는 성공하면 true를, 에러가 발생하면 false를 반환합니다.
bool close();
이 함수는 캐시를 닫을 때 사용합니다. 한 개 이상의 캐시 데이터를 저장한 후에 수행해야할 마무리 작업을 수행하기 위해 준비된 함수입니다. 따라서 현재 문서에서 각각의 캐시 데이터를 더 이상 다룰 필요가 없는 시점에서 close() 함수를 반드시 실행하여 주시기 바랍니다.
close() 함수가 수행된 후에는 save_id(), read(), write(), destroy() 함수를 실행할 수 없습니다.
이 함수는 성공하면 true를, 에러가 발생하면 false를 반환합니다.
string save_id(string id);
1.0.0 버전부터는 open() 함수를 수행한 이후에도 여러 개의 캐시 ID를 다룰 수 있도록 save_id() 함수를 제공합니다. 이 함수의 인수로 지정되는 id는 파일시스템용 캐시핸들러의 경우에서는 캐시 데이터를 저장되는 파일의 이름으로 사용됩니다.
이 함수는 open() 함수를 실행한 후, close() 함수를 실행하기 전에 사용하여야 합니다.
이 함수를 실행하면 이전에 지정된 캐시 ID가 반환됩니다. 만약 이전에 지정된 캐시 ID가 없었다면 기본값이 "_HW_CACHE_ID"가 반환됩니다.
string read();
캐시 데이터를 읽어들일 때 사용하는 함수입니다. 이 함수를 수행하기 전에 읽어들일 캐시 ID(파일시스템의 경우 파일명)는 생성자 또는 save_id() 함수를 통해 미리 지정하여야 합니다.
만약 지정하지 않게 되면 항상 기본값이 "_HW_CACHE_ID"라는 캐시 ID로 캐시 데이터가 저장됩니다. 따라서 저장되는 캐시 데이터를 다른 것과 구별하기 위해 캐시 ID를 반드시 지정하여 주시기 바랍니다.
이 함수는 open() 함수를 실행한 후, close() 함수를 실행하기 전에 사용하여야 합니다.
이 함수는 성공하면 지정된 캐시 ID에 대한 문자열 형식의 캐시 데이터를 반환하며, 에러가 발생하면 false를 반환합니다.
bool write([string value]);
데이터를 캐시 저장디렉토리에 기록할 때 이 함수를 수행합니다. 이 함수에 전달할 데이터의 형식은 반드시 문자열이어야 합니다. 만약 배열과 같은 값을 캐시하려면 먼저 serialize() 함수 등을 이용하여 문자열로 변환한 후 write() 함수에게 넘겨주어야 합니다.
이 함수는 open() 함수를 실행한 후, close() 함수를 실행하기 전에 사용하여야 합니다.
캐시 데이터의 내용을 변경하지 않고 다만 캐시 파일의 작성 날짜(file modification time)만을 현재시간으로 변경하려면 인수없이 write() 함수를 수행하기 바랍니다.
이 함수는 성공하면 true를, 에러가 발생하면 false를 반환합니다.
bool destroy();
더 이상 필요없는 쓰레기인 캐시 데이터를 강제로 지워주기위해 수행되는 함수입니다.
이 함수는 open() 함수를 실행한 후, close() 함수를 실행하기 전에 사용하여야 합니다.
이 함수는 성공하면 true를, 에러가 발생하면 false를 반환합니다.

Posted by 방글24
생성자(constructor)
생성자에서는 캐시를 초기화하기 위한 작업을 수행하며 캐시핸들러를 동작시키는데 필요한 각종 설정값을 사용자로부터 전달받아 처리합니다.
생성자를 통해 사용자가 전달할 수 있는 설정값으로는 캐시 ID(id), 저장디렉토리(path), 캐시 데이터 생존 시간(maxlifetime) 및 청소 주기(period)가 있습니다.
<표1> 캐시핸들러의 초기 설정값
매개변수명 인덱스 기본값 동작 저장매체
캐시 ID id "_HW_CACHE_ID" 캐시 데이터가 저장될 파일명 또는 데이터베이스 필드명을 의미 all
생존 시간 maxlifetime 2,592,000초(30일) 캐시 데이터의 생존 시간을 의미 all
청소 주기 period 259,200초(3일) garbage collection을 수행할 주기 all
저장 디렉토리 path "/tmp" 캐시 데이터가 저장될 서버상의 디렉토리 파일 시스템용
디비 호스트명 host "localhost" 디비 호스트명 MySQL용
디비 사용자명 user none 디비 사용자명 MySQL용
디비 패스워드 pass none 디비 패스워드 MySQL용
디비명 base none 디비명 MySQL용
디비 테이블명 table "hcache" 디비 테이블명 MySQL용
접속방식 connect "pconnect" 접속방식 MySQL용
캐시 ID(cache id)
사용자와 캐시 데이터를 연결하기 위해서는 캐시 ID가 필요합니다. 파일시스템에서는 캐시 ID가 파일명으로 사용되며, 데이터베이스 시스템에서는 필드명으로 사용됩니다.
예를 들어 캐시 저장 디렉토리에 "my.cache"라는 이름으로 캐시 데이터를 저장하려면 생성자의 인수 중에 캐시 ID를 아래와 같이 "my.cache"로 지정합니다.
[code php;gutter:false] $cache = new hCache(array(
"id" => "my.cache"
)); [/code]
생존 시간(maxlifetime)
캐시 데이터의 생존 시간은 캐시 데이터가 생성된 시간을 기준으로 이 데이터가 유효한 기간을 초로 나타낸 것입니다. 예를 들어 캐시 데이터가 생성된 후 1시간(3600초) 동안만 유효하도록 하려면 생성자의 인수 중에 생존 시간을 아래와 같이 지정합니다.
[code php;gutter:false] $cache = new hCache(array(
"maxlifetime" => 3600
)); [/code]
그러면 캐시 데이터를 읽어들일 때 캐시 데이터가 생성된 후 1시간이 지나지 않은 것만 읽어들이며 1시간이 지났다면 해당 캐시 데이터가 없는 것과 같이 false를 반환합니다.
또한 불필요한 캐시 데이터를 청소 주기에 따라 청소할 때 생존 기간이 지난 캐시 데이터를 강제로 전부 지우게 됩니다.
청소 주기(garbage collection period)
destory() 함수를 통해 캐시 데이터를 강제로 지울 수도 있으나 수시로 생성되는 캐시 데이터를 사용자가 일일히 지우기에는 여러가지 제한이 많이 있습니다.
이러한 이유로 캐시 데이터는 보통 생존 시간(maxlifetime) 설정을 통해 캐시 데이터가 생성된 후 얼마나 지난 후에 캐시 데이터가 삭제되어야 할 지 지정하게 됩니다.
그러나 모든 사용자가 웹문서에 접근할 때마다 캐시 데이터를 청소(garbage collection)한다면 서버에 상당한 부하(overhead)를 주게 됩니다. 이러한 문제를 해결하기 위해 캐시핸들러에서는 청소 주기(garbage collection period) 설정을 통해 일정한 주기마다 한번씩만 청소하도록 하였습니다.
기본값으로는 3일(259,200초)로 설정되어 있습니다. 캐시 데이터가 짧은 시간에 너무 많이 생성된다면 서버가 캐시 파일에 접근하는데 문제가 발생할 수도 있습니다. 따라서 서버 상황에 따라, 또는 캐시 데이터가 얼마나 많이 생성되느냐에 따라 이 주기를 적절히 조정하는 것이 좋을 것입니다. 캐시 데이터가 많이 생성될수록 청소 주기를 짧게 하여야 겠지요.
청소 주기를 0으로 설정하면 garbage collection을 수행하지 않습니다. 이 경우에 특정 캐시 데이터를 지우려면 destroy() 함수를 이용하든지 아니면 쉘 스크립트를 통해 서버를 뒤져서 직접 지워주셔야 합니다.
저장 디렉토리(path to cache)
기본적으로 파일시스템용 캐시핸들러에서 캐시 데이터는 "/tmp"에 저장됩니다.
서버 디렉토리 "/tmp"는 서버에 계정을 가지고 있는 모든 회원이 공용으로 사용할 수 있는 임시 디렉토리로 전혀 보안이 되지 않습니다. 즉, 회원이면 누구든지 /tmp 디렉토리에 있는 파일의 내용을 아무런 제한없이 살펴볼 수 있습니다. 따라서 서버를 다수가 공유하여 사용하는 경우에는 캐시 데이터를 저장할 디렉토리를 자신만이 접근할 수 있는 곳으로 변경하는 것이 좋습니다.
예를 들어 "./cache"라는 자신만의 디렉토리에 캐시 데이터를 저장하려면 생성자의 인수 중에 저장 디렉토리를 아래와 같이 지정합니다.
[code php;gutter:false] $cache = new hCache(array(
"path" => "./cache"
)); [/code]
캐시 저장 디렉토리는 읽기/쓰기를 할 수 있어야 하기 때문에 리눅스의 경우 퍼미션을 아래와 같이 설정하여 주시기 바랍니다.
chmod a+rwx 캐시 저장 디렉토리
디렉토리의 소유자 또는 퍼미션을 재설정하기 위한 chown 또는 chmod 사용법은 리눅스 쉘 Manual을 참조하세요.
윈도우 서버라면 디렉토리 속성을 읽기전용이 되지 않도록 설정하세요.
데이터베이스 호스트명
 
데이터베이스 사용자명
 
데이터베이스 패스워드
 
데이터베이스명
 
데이터베이스 테이블명
 
데이터베이스 접속 방식(connection type)
접속방식에는 "connect"와 "pconnect"를 지정할 수 있습니다. "connect"는 쿼리하는 동안에만 일시적으로 데이터베이스와 연결하는 방식이며, "pconnect"는 일단 데이터베이스와 연결된 후에는 일정시간동안 연결상태가 계속 유지되는 방식입니다.
저장 매체별 정의된 클래스명
생성자에서는 캐시를 초기화하기 위한 작업을 수행하며 캐시핸들러를 동작시키는데 필요한 각종 설정값을 사용자로부터 전달받아 처리합니다.
생성자를 통해 사용자가 전달할 수 있는 설정값으로는 캐시 ID(id), 저장디렉토리(path), 캐시 데이터 생존 시간(maxlifetime) 및 청소 주기(period)가 있습니다.
<표2> 저장 매체별 클래스명
저장매체 정의된 클래스명 클래스 파일
파일 시스템용 hCacheFile class.hCacheFile.php
MySQL용 hCacheMysql class.hCacheMysql.php
저장 매체에 관계없이 "hCache"라는 클래스명을 사용할 수 있습니다. "hCache" 클래스는 "hCacheFile" 또는 "hCacheMysql" 클래스를 상속받아 정의된 자식 클래스입니다.
"hCache" 클래스로는 하나의 저장 매체만 접근할 수 있습니다. 먼저 문서에 포함된 클래스에게 우선권이 있습니다.

Posted by 방글24
캐시핸들러 개요
캐시(cache)는 임시 저장소로 캐시핸들러는 캐시에 저장된 데이터를 관리하는 기능을 제공합니다. 캐시핸들러의 캐시 관리 기능은 PHP4에서 제공하는 세션 관리 기능을 모델링하였기 때문에 사용방법이 세션 관리 기능과 유사함을 알 수 있습니다.
캐시핸들러가 어떻게 캐시 데이터를 열고, 읽고, 쓰고, 닫는 지와 더 이상 필요하지 않은 쓰레기를 어떻게 지우는 지에 대하여 하나씩 살펴보도록 하겠습니다.
캐시핸들러 동작 수순
캐시핸들러는 아래 그림과 같이 가장 먼저 생성자 내에서 캐시핸들러가 동작하는데 필요한 초기화작업을 수행한 후 캐시를 열기 위해 open() 함수를 수행합니다.
<그림1> 캐시 동작 수순
캐시가 열린 후에는 각각의 캐시 데이터에 대한 작업이 close() 함수를 하기 전에 반복적으로 수행됩니다. 이 때 수행되는 함수는 save_id(), read(), write(), destroy() 함수가 있습니다.
각각의 캐시 데이터에 대한 작업이 완료되면 close() 함수를 수행하여 캐시를 닫습니다. close() 함수가 수행된 이후에는 각각의 캐시 데이터에 대한 작업을 할 수 없습니다.
캐시핸들러를 이용하여 응용프로그램을 작성할 때 close() 함수는 많은 경우에 응용프로그램의 소멸자(또는 사용자 정의 소멸자)에서 수행하게 될 것입니다.
아래는 실제로 캐시핸들러를 이용하여 작성된 예제입니다.
[code php;gutter:false] <?php
/**
* 처리하려는 캐시 데이터 id를 배열에 담는다.
*/
$cache_files = array(
"test1.cache",
"test2.cache",
"test3.cache"
);

/**
* 캐시핸들러의 객체를 생성한다.
*
* 초기에 처리할 캐시파일명을 test.cache으로 설정
* 청소 주기를 1년(31,536,000초)으로 설정
* 생존 시간을 5년(157,680,000초)으로 설정
* "./cache/my" 디렉토리에 캐시 저장
*/
$cache = new hCache(array(
"id" => "test.cache",
"period" => 31536000,
"maxlifetime" => 157680000,
"path" => "./cache/my"
));

/**
* 캐시를 연다.
*/
$cache->open();

/**
* 생성자에서 설정한 캐시파일 "./cache/my/test.cache"를 지운다.
* 이 파일이 처음부터 없었다면 false가 반환되었을 것이다.
*/
$cache->destroy();

/**
* "./cache/my" 디렉토리에 있는
* 캐시파일 "test1.cache", "test2.cache", "test3.cache"를
* 순서대로 읽어들여 그 내용에 "*"를 덧붙인다.
* 해당 캐시파일이 없으면 해당 캐시파일을 "./cache/my"에 생성한다.
*/
foreach($cache_files as $file) {
$cache->save_id($file);
$value = $cache->read();

if ($value) {
$value .= "*";
} else {
$value = "";
}

/**
* $value의 내용을 지정된 캐시파일에 저장한다.
*/
$cache->write($value);
}

/**
* 캐시를 닫는다.
*/
$cache->close();
?> [/code]
쓰레기 청소(garbage collection)
더 이상 사용되지 않는 불필요한 캐시 데이터에 대하여는 open() 함수 내에서 자동적으로 지워주며, 때에 따라서는 destroy() 함수를 이용해 특정 캐시 데이터를 강제로 지울 수 있습니다.
캐시 데이터
저장하기 위해 캐시핸들러로 전달된 데이터는 문자열이어야 합니다. 따라서 배열과 같은 데이터를 캐시에 저장하기 위해서는 먼저 serialize() 함수를 통해 문자열로 만든 후 캐시핸들러 write() 함수로 전달하여야 합니다.
아래 그림은 배열값이 어떻게 캐시되는지를 보여줍니다.
<그림2> 배열값의 캐싱
저장 매체
캐시 데이터는 서버에 저장하게 되므로 필요에 따라 파일시스템은 물론 데이터베이스 및 공유메모리 등을 이용할 수 있습니다.
저장 매체의 분류
캐시핸들러에는 파일시스템용, MySQL용이 포함되어 있습니다.
<표1> 캐시핸들러의 저장매체
구분 파일 MySQL용
저장매체 파일 시스템 MySQL 데이터베이스
오라클 데이터베이스 또는 공유메모리와 같은 다른 저장매체를 이용하려면 파일 시스템용 또는 MySQL용 캐시핸들러를 참고하여 수정하면 별 어려움없이 작성할 수 있으리라 봅니다.
각 저장 매체의 장점
후키템풀릿에서와 같이 임시로 생성된 웹문서를 관리하는데는 대부분의 경우에 파일 시스템이 유리할 것으로 생각됩니다.
그러나 캐시 데이터의 수량과 용량이 거대하다면 데이터베이스 시스템이 더 유리할 수도 있습니다.
반면에 아주 간단한 캐시 데이터의 경우는 공유메모리를 이용하는 것이 나을 수도 있겠지요.
캐시핸들러의 응용
현재 캐시핸들러를 이용하여 작성된 응용프로그램으로는 후키템플릿이 있습니다. 후키템플릿에서 캐시핸들러가 어떻게 응용되었는가에 관심이 있으시다면 후키템플릿 정보에서 "캐시를 이용하는 방법"을 참조바랍니다.

Posted by 방글24

RFC2109 - HTTP State Management Mechanism

Network Working Group                                         D. Kristol
Request for Comments: 2109 Bell Laboratories, Lucent Technologies
Category: Standards Track L. Montulli
Netscape Communications
February 1997

HTTP State Management Mechanism

Status of this Memo

This document specifies an Internet standards track protocol for the
Internet community, and requests discussion and suggestions for
improvements. Please refer to the current edition of the "Internet
Official Protocol Standards" (STD 1) for the standardization state
and status of this protocol. Distribution of this memo is unlimited.

1. ABSTRACT

This document specifies a way to create a stateful session with HTTP
requests and responses. It describes two new headers, Cookie and
Set-Cookie, which carry state information between participating
origin servers and user agents. The method described here differs
from Netscape's Cookie proposal, but it can interoperate with
HTTP/1.0 user agents that use Netscape's method. (See the HISTORICAL
section.)

2. TERMINOLOGY

The terms user agent, client, server, proxy, and origin server have
the same meaning as in the HTTP/1.0 specification.

Fully-qualified host name (FQHN) means either the fully-qualified
domain name (FQDN) of a host (i.e., a completely specified domain
name ending in a top-level domain such as .com or .uk), or the
numeric Internet Protocol (IP) address of a host. The fully
qualified domain name is preferred; use of numeric IP addresses is
strongly discouraged.

The terms request-host and request-URI refer to the values the client
would send to the server as, respectively, the host (but not port)
and abs_path portions of the absoluteURI (http_URL) of the HTTP
request line. Note that request-host must be a FQHN.

Hosts names can be specified either as an IP address or a FQHN
string. Sometimes we compare one host name with another. Host A's
name domain-matches host B's if

* both host names are IP addresses and their host name strings match
exactly; or

* both host names are FQDN strings and their host name strings match
exactly; or

* A is a FQDN string and has the form NB, where N is a non-empty name
string, B has the form .B', and B' is a FQDN string. (So, x.y.com
domain-matches .y.com but not y.com.)

Note that domain-match is not a commutative operation: a.b.c.com
domain-matches .c.com, but not the reverse.

Because it was used in Netscape's original implementation of state
management, we will use the term cookie to refer to the state
information that passes between an origin server and user agent, and
that gets stored by the user agent.

3. STATE AND SESSIONS

This document describes a way to create stateful sessions with HTTP
requests and responses. Currently, HTTP servers respond to each
client request without relating that request to previous or
subsequent requests; the technique allows clients and servers that
wish to exchange state information to place HTTP requests and
responses within a larger context, which we term a "session". This
context might be used to create, for example, a "shopping cart", in
which user selections can be aggregated before purchase, or a
magazine browsing system, in which a user's previous reading affects
which offerings are presented.

There are, of course, many different potential contexts and thus many
different potential types of session. The designers' paradigm for
sessions created by the exchange of cookies has these key attributes:

1. Each session has a beginning and an end.

2. Each session is relatively short-lived.

3. Either the user agent or the origin server may terminate a
session.

4. The session is implicit in the exchange of state information.

4. OUTLINE

We outline here a way for an origin server to send state information
to the user agent, and for the user agent to return the state
information to the origin server. The goal is to have a minimal
impact on HTTP and user agents. Only origin servers that need to
maintain sessions would suffer any significant impact, and that
impact can largely be confined to Common Gateway Interface (CGI)
programs, unless the server provides more sophisticated state
management support. (See Implementation Considerations, below.)

4.1 Syntax: General

The two state management headers, Set-Cookie and Cookie, have common
syntactic properties involving attribute-value pairs. The following
grammar uses the notation, and tokens DIGIT (decimal digits) and
token (informally, a sequence of non-special, non-white space
characters) from the HTTP/1.1 specification [RFC 2068] to describe
their syntax.

av-pairs = av-pair *(";" av-pair)
av-pair = attr ["=" value] ; optional value
attr = token
value = word
word = token | quoted-string

Attributes (names) (attr) are case-insensitive. White space is
permitted between tokens. Note that while the above syntax
description shows value as optional, most attrs require them.

NOTE: The syntax above allows whitespace between the attribute and
the = sign.

4.2 Origin Server Role

4.2.1 General

The origin server initiates a session, if it so desires. (Note that
"session" here does not refer to a persistent network connection but
to a logical session created from HTTP requests and responses. The
presence or absence of a persistent connection should have no effect
on the use of cookie-derived sessions). To initiate a session, the
origin server returns an extra response header to the client, Set-
Cookie. (The details follow later.)

A user agent returns a Cookie request header (see below) to the
origin server if it chooses to continue a session. The origin server
may ignore it or use it to determine the current state of the

session. It may send back to the client a Set-Cookie response header
with the same or different information, or it may send no Set-Cookie
header at all. The origin server effectively ends a session by
sending the client a Set-Cookie header with Max-Age=0.

Servers may return a Set-Cookie response headers with any response.
User agents should send Cookie request headers, subject to other
rules detailed below, with every request.

An origin server may include multiple Set-Cookie headers in a
response. Note that an intervening gateway could fold multiple such
headers into a single header.

4.2.2 Set-Cookie Syntax

The syntax for the Set-Cookie response header is

set-cookie = "Set-Cookie:" cookies
cookies = 1#cookie
cookie = NAME "=" VALUE *(";" cookie-av)
NAME = attr
VALUE = value
cookie-av = "Comment" "=" value
| "Domain" "=" value
| "Max-Age" "=" value
| "Path" "=" value
| "Secure"
| "Version" "=" 1*DIGIT

Informally, the Set-Cookie response header comprises the token Set-
Cookie:, followed by a comma-separated list of one or more cookies.
Each cookie begins with a NAME=VALUE pair, followed by zero or more
semi-colon-separated attribute-value pairs. The syntax for
attribute-value pairs was shown earlier. The specific attributes and
the semantics of their values follows. The NAME=VALUE attribute-
value pair must come first in each cookie. The others, if present,
can occur in any order. If an attribute appears more than once in a
cookie, the behavior is undefined.

NAME=VALUE
Required. The name of the state information ("cookie") is NAME,
and its value is VALUE. NAMEs that begin with $ are reserved for
other uses and must not be used by applications.

The VALUE is opaque to the user agent and may be anything the
origin server chooses to send, possibly in a server-selected
printable ASCII encoding. "Opaque" implies that the content is of
interest and relevance only to the origin server. The content
may, in fact, be readable by anyone that examines the Set-Cookie
header.

Comment=comment
Optional. Because cookies can contain private information about a
user, the Cookie attribute allows an origin server to document its
intended use of a cookie. The user can inspect the information to
decide whether to initiate or continue a session with this cookie.

Domain=domain
Optional. The Domain attribute specifies the domain for which the
cookie is valid. An explicitly specified domain must always start
with a dot.

Max-Age=delta-seconds
Optional. The Max-Age attribute defines the lifetime of the
cookie, in seconds. The delta-seconds value is a decimal non-
negative integer. After delta-seconds seconds elapse, the client
should discard the cookie. A value of zero means the cookie
should be discarded immediately.

Path=path
Optional. The Path attribute specifies the subset of URLs to
which this cookie applies.

Secure
Optional. The Secure attribute (with no value) directs the user
agent to use only (unspecified) secure means to contact the origin
server whenever it sends back this cookie.

The user agent (possibly under the user's control) may determine
what level of security it considers appropriate for "secure"
cookies. The Secure attribute should be considered security
advice from the server to the user agent, indicating that it is in
the session's interest to protect the cookie contents.

Version=version
Required. The Version attribute, a decimal integer, identifies to
which version of the state management specification the cookie
conforms. For this specification, Version=1 applies.

4.2.3 Controlling Caching

An origin server must be cognizant of the effect of possible caching
of both the returned resource and the Set-Cookie header. Caching
"public" documents is desirable. For example, if the origin server
wants to use a public document such as a "front door" page as a
sentinel to indicate the beginning of a session for which a Set-
Cookie response header must be generated, the page should be stored
in caches "pre-expired" so that the origin server will see further
requests. "Private documents", for example those that contain
information strictly private to a session, should not be cached in
shared caches.

If the cookie is intended for use by a single user, the Set-cookie
header should not be cached. A Set-cookie header that is intended to
be shared by multiple users may be cached.

The origin server should send the following additional HTTP/1.1
response headers, depending on circumstances:

* To suppress caching of the Set-Cookie header: Cache-control: no-
cache="set-cookie".

and one of the following:

* To suppress caching of a private document in shared caches: Cache-
control: private.

* To allow caching of a document and require that it be validated
before returning it to the client: Cache-control: must-revalidate.

* To allow caching of a document, but to require that proxy caches
(not user agent caches) validate it before returning it to the
client: Cache-control: proxy-revalidate.

* To allow caching of a document and request that it be validated
before returning it to the client (by "pre-expiring" it):
Cache-control: max-age=0. Not all caches will revalidate the
document in every case.

HTTP/1.1 servers must send Expires: old-date (where old-date is a
date long in the past) on responses containing Set-Cookie response
headers unless they know for certain (by out of band means) that
there are no downsteam HTTP/1.0 proxies. HTTP/1.1 servers may send
other Cache-Control directives that permit caching by HTTP/1.1
proxies in addition to the Expires: old-date directive; the Cache-
Control directive will override the Expires: old-date for HTTP/1.1
proxies.

4.3 User Agent Role

4.3.1 Interpreting Set-Cookie

The user agent keeps separate track of state information that arrives
via Set-Cookie response headers from each origin server (as
distinguished by name or IP address and port). The user agent
applies these defaults for optional attributes that are missing:

VersionDefaults to "old cookie" behavior as originally specified by
Netscape. See the HISTORICAL section.

Domain Defaults to the request-host. (Note that there is no dot at
the beginning of request-host.)

Max-AgeThe default behavior is to discard the cookie when the user
agent exits.

Path Defaults to the path of the request URL that generated the
Set-Cookie response, up to, but not including, the
right-most /.

Secure If absent, the user agent may send the cookie over an
insecure channel.

4.3.2 Rejecting Cookies

To prevent possible security or privacy violations, a user agent
rejects a cookie (shall not store its information) if any of the
following is true:

* The value for the Path attribute is not a prefix of the request-
URI.

* The value for the Domain attribute contains no embedded dots or
does not start with a dot.

* The value for the request-host does not domain-match the Domain
attribute.

* The request-host is a FQDN (not IP address) and has the form HD,
where D is the value of the Domain attribute, and H is a string
that contains one or more dots.

Examples:

* A Set-Cookie from request-host y.x.foo.com for Domain=.foo.com
would be rejected, because H is y.x and contains a dot.

* A Set-Cookie from request-host x.foo.com for Domain=.foo.com would
be accepted.

* A Set-Cookie with Domain=.com or Domain=.com., will always be
rejected, because there is no embedded dot.

* A Set-Cookie with Domain=ajax.com will be rejected because the
value for Domain does not begin with a dot.

4.3.3 Cookie Management

If a user agent receives a Set-Cookie response header whose NAME is
the same as a pre-existing cookie, and whose Domain and Path
attribute values exactly (string) match those of a pre-existing
cookie, the new cookie supersedes the old. However, if the Set-
Cookie has a value for Max-Age of zero, the (old and new) cookie is
discarded. Otherwise cookies accumulate until they expire (resources
permitting), at which time they are discarded.

Because user agents have finite space in which to store cookies, they
may also discard older cookies to make space for newer ones, using,
for example, a least-recently-used algorithm, along with constraints
on the maximum number of cookies that each origin server may set.

If a Set-Cookie response header includes a Comment attribute, the
user agent should store that information in a human-readable form
with the cookie and should display the comment text as part of a
cookie inspection user interface.

User agents should allow the user to control cookie destruction. An
infrequently-used cookie may function as a "preferences file" for
network applications, and a user may wish to keep it even if it is
the least-recently-used cookie. One possible implementation would be
an interface that allows the permanent storage of a cookie through a
checkbox (or, conversely, its immediate destruction).

Privacy considerations dictate that the user have considerable
control over cookie management. The PRIVACY section contains more
information.

4.3.4 Sending Cookies to the Origin Server

When it sends a request to an origin server, the user agent sends a
Cookie request header to the origin server if it has cookies that are
applicable to the request, based on

* the request-host;

* the request-URI;

* the cookie's age.

The syntax for the header is:

cookie = "Cookie:" cookie-version
1*((";" | ",") cookie-value)
cookie-value = NAME "=" VALUE [";" path] [";" domain]
cookie-version = "$Version" "=" value
NAME = attr
VALUE = value
path = "$Path" "=" value
domain = "$Domain" "=" value

The value of the cookie-version attribute must be the value from the
Version attribute, if any, of the corresponding Set-Cookie response
header. Otherwise the value for cookie-version is 0. The value for
the path attribute must be the value from the Path attribute, if any,
of the corresponding Set-Cookie response header. Otherwise the
attribute should be omitted from the Cookie request header. The
value for the domain attribute must be the value from the Domain
attribute, if any, of the corresponding Set-Cookie response header.
Otherwise the attribute should be omitted from the Cookie request
header.

Note that there is no Comment attribute in the Cookie request header
corresponding to the one in the Set-Cookie response header. The user
agent does not return the comment information to the origin server.

The following rules apply to choosing applicable cookie-values from
among all the cookies the user agent has.

Domain Selection
The origin server's fully-qualified host name must domain-match
the Domain attribute of the cookie.

Path Selection
The Path attribute of the cookie must match a prefix of the
request-URI.

Max-Age Selection
Cookies that have expired should have been discarded and thus
are not forwarded to an origin server.

If multiple cookies satisfy the criteria above, they are ordered in
the Cookie header such that those with more specific Path attributes
precede those with less specific. Ordering with respect to other
attributes (e.g., Domain) is unspecified.

Note: For backward compatibility, the separator in the Cookie header
is semi-colon (;) everywhere. A server should also accept comma (,)
as the separator between cookie-values for future compatibility.

4.3.5 Sending Cookies in Unverifiable Transactions

Users must have control over sessions in order to ensure privacy.
(See PRIVACY section below.) To simplify implementation and to
prevent an additional layer of complexity where adequate safeguards
exist, however, this document distinguishes between transactions that
are verifiable and those that are unverifiable. A transaction is
verifiable if the user has the option to review the request-URI prior
to its use in the transaction. A transaction is unverifiable if the
user does not have that option. Unverifiable transactions typically
arise when a user agent automatically requests inlined or embedded
entities or when it resolves redirection (3xx) responses from an
origin server. Typically the origin transaction, the transaction
that the user initiates, is verifiable, and that transaction may
directly or indirectly induce the user agent to make unverifiable
transactions.

When it makes an unverifiable transaction, a user agent must enable a
session only if a cookie with a domain attribute D was sent or
received in its origin transaction, such that the host name in the
Request-URI of the unverifiable transaction domain-matches D.

This restriction prevents a malicious service author from using
unverifiable transactions to induce a user agent to start or continue
a session with a server in a different domain. The starting or
continuation of such sessions could be contrary to the privacy
expectations of the user, and could also be a security problem.

User agents may offer configurable options that allow the user agent,
or any autonomous programs that the user agent executes, to ignore
the above rule, so long as these override options default to "off".

Many current user agents already provide a review option that would
render many links verifiable. For instance, some user agents display
the URL that would be referenced for a particular link when the mouse
pointer is placed over that link. The user can therefore determine
whether to visit that site before causing the browser to do so.
(Though not implemented on current user agents, a similar technique
could be used for a button used to submit a form -- the user agent

could display the action to be taken if the user were to select that
button.) However, even this would not make all links verifiable; for
example, links to automatically loaded images would not normally be
subject to "mouse pointer" verification.

Many user agents also provide the option for a user to view the HTML
source of a document, or to save the source to an external file where
it can be viewed by another application. While such an option does
provide a crude review mechanism, some users might not consider it
acceptable for this purpose.

4.4 How an Origin Server Interprets the Cookie Header

A user agent returns much of the information in the Set-Cookie header
to the origin server when the Path attribute matches that of a new
request. When it receives a Cookie header, the origin server should
treat cookies with NAMEs whose prefix is $ specially, as an attribute
for the adjacent cookie. The value for such a NAME is to be
interpreted as applying to the lexically (left-to-right) most recent
cookie whose name does not have the $ prefix. If there is no
previous cookie, the value applies to the cookie mechanism as a
whole. For example, consider the cookie

Cookie: $Version="1"; Customer="WILE_E_COYOTE";
$Path="/acme"

$Version applies to the cookie mechanism as a whole (and gives the
version number for the cookie mechanism). $Path is an attribute
whose value (/acme) defines the Path attribute that was used when the
Customer cookie was defined in a Set-Cookie response header.

4.5 Caching Proxy Role

One reason for separating state information from both a URL and
document content is to facilitate the scaling that caching permits.
To support cookies, a caching proxy must obey these rules already in
the HTTP specification:

* Honor requests from the cache, if possible, based on cache validity
rules.

* Pass along a Cookie request header in any request that the proxy
must make of another server.

* Return the response to the client. Include any Set-Cookie response
header.

* Cache the received response subject to the control of the usual
headers, such as Expires, Cache-control: no-cache, and Cache-
control: private,

* Cache the Set-Cookie subject to the control of the usual header,
Cache-control: no-cache="set-cookie". (The Set-Cookie header
should usually not be cached.)

Proxies must not introduce Set-Cookie (Cookie) headers of their own
in proxy responses (requests).

5. EXAMPLES

5.1 Example 1

Most detail of request and response headers has been omitted. Assume
the user agent has no stored cookies.

1. User Agent -> Server

POST /acme/login HTTP/1.1
[form data]

User identifies self via a form.

2. Server -> User Agent

HTTP/1.1 200 OK
Set-Cookie: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"

Cookie reflects user's identity.

3. User Agent -> Server

POST /acme/pickitem HTTP/1.1
Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"
[form data]

User selects an item for "shopping basket."

4. Server -> User Agent

HTTP/1.1 200 OK
Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1";
Path="/acme"

Shopping basket contains an item.

5. User Agent -> Server

POST /acme/shipping HTTP/1.1
Cookie: $Version="1";
Customer="WILE_E_COYOTE"; $Path="/acme";
Part_Number="Rocket_Launcher_0001"; $Path="/acme"
[form data]

User selects shipping method from form.

6. Server -> User Agent

HTTP/1.1 200 OK
Set-Cookie: Shipping="FedEx"; Version="1"; Path="/acme"

New cookie reflects shipping method.

7. User Agent -> Server

POST /acme/process HTTP/1.1
Cookie: $Version="1";
Customer="WILE_E_COYOTE"; $Path="/acme";
Part_Number="Rocket_Launcher_0001"; $Path="/acme";
Shipping="FedEx"; $Path="/acme"
[form data]

User chooses to process order.

8. Server -> User Agent

HTTP/1.1 200 OK

Transaction is complete.

The user agent makes a series of requests on the origin server, after
each of which it receives a new cookie. All the cookies have the
same Path attribute and (default) domain. Because the request URLs
all have /acme as a prefix, and that matches the Path attribute, each
request contains all the cookies received so far.

5.2 Example 2

This example illustrates the effect of the Path attribute. All
detail of request and response headers has been omitted. Assume the
user agent has no stored cookies.

Imagine the user agent has received, in response to earlier requests,
the response headers

Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1";
Path="/acme"

and

Set-Cookie: Part_Number="Riding_Rocket_0023"; Version="1";
Path="/acme/ammo"

A subsequent request by the user agent to the (same) server for URLs
of the form /acme/ammo/... would include the following request
header:

Cookie: $Version="1";
Part_Number="Riding_Rocket_0023"; $Path="/acme/ammo";
Part_Number="Rocket_Launcher_0001"; $Path="/acme"

Note that the NAME=VALUE pair for the cookie with the more specific
Path attribute, /acme/ammo, comes before the one with the less
specific Path attribute, /acme. Further note that the same cookie
name appears more than once.

A subsequent request by the user agent to the (same) server for a URL
of the form /acme/parts/ would include the following request header:

Cookie: $Version="1"; Part_Number="Rocket_Launcher_0001"; $Path="/acme"

Here, the second cookie's Path attribute /acme/ammo is not a prefix
of the request URL, /acme/parts/, so the cookie does not get
forwarded to the server.

6. IMPLEMENTATION CONSIDERATIONS

Here we speculate on likely or desirable details for an origin server
that implements state management.

6.1 Set-Cookie Content

An origin server's content should probably be divided into disjoint
application areas, some of which require the use of state
information. The application areas can be distinguished by their
request URLs. The Set-Cookie header can incorporate information
about the application areas by setting the Path attribute for each
one.

The session information can obviously be clear or encoded text that
describes state. However, if it grows too large, it can become
unwieldy. Therefore, an implementor might choose for the session
information to be a key to a server-side resource. Of course, using

a database creates some problems that this state management
specification was meant to avoid, namely:

1. keeping real state on the server side;

2. how and when to garbage-collect the database entry, in case the
user agent terminates the session by, for example, exiting.

6.2 Stateless Pages

Caching benefits the scalability of WWW. Therefore it is important
to reduce the number of documents that have state embedded in them
inherently. For example, if a shopping-basket-style application
always displays a user's current basket contents on each page, those
pages cannot be cached, because each user's basket's contents would
be different. On the other hand, if each page contains just a link
that allows the user to "Look at My Shopping Basket", the page can be
cached.

6.3 Implementation Limits

Practical user agent implementations have limits on the number and
size of cookies that they can store. In general, user agents' cookie
support should have no fixed limits. They should strive to store as
many frequently-used cookies as possible. Furthermore, general-use
user agents should provide each of the following minimum capabilities
individually, although not necessarily simultaneously:

* at least 300 cookies

* at least 4096 bytes per cookie (as measured by the size of the
characters that comprise the cookie non-terminal in the syntax
description of the Set-Cookie header)

* at least 20 cookies per unique host or domain name

User agents created for specific purposes or for limited-capacity
devices should provide at least 20 cookies of 4096 bytes, to ensure
that the user can interact with a session-based origin server.

The information in a Set-Cookie response header must be retained in
its entirety. If for some reason there is inadequate space to store
the cookie, it must be discarded, not truncated.

Applications should use as few and as small cookies as possible, and
they should cope gracefully with the loss of a cookie.

6.3.1 Denial of Service Attacks

User agents may choose to set an upper bound on the number of cookies
to be stored from a given host or domain name or on the size of the
cookie information. Otherwise a malicious server could attempt to
flood a user agent with many cookies, or large cookies, on successive
responses, which would force out cookies the user agent had received
from other servers. However, the minima specified above should still
be supported.

7. PRIVACY

7.1 User Agent Control

An origin server could create a Set-Cookie header to track the path
of a user through the server. Users may object to this behavior as
an intrusive accumulation of information, even if their identity is
not evident. (Identity might become evident if a user subsequently
fills out a form that contains identifying information.) This state
management specification therefore requires that a user agent give
the user control over such a possible intrusion, although the
interface through which the user is given this control is left
unspecified. However, the control mechanisms provided shall at least
allow the user

* to completely disable the sending and saving of cookies.

* to determine whether a stateful session is in progress.

* to control the saving of a cookie on the basis of the cookie's
Domain attribute.

Such control could be provided by, for example, mechanisms

* to notify the user when the user agent is about to send a cookie
to the origin server, offering the option not to begin a session.

* to display a visual indication that a stateful session is in
progress.

* to let the user decide which cookies, if any, should be saved
when the user concludes a window or user agent session.

* to let the user examine the contents of a cookie at any time.

A user agent usually begins execution with no remembered state
information. It should be possible to configure a user agent never
to send Cookie headers, in which case it can never sustain state with

an origin server. (The user agent would then behave like one that is
unaware of how to handle Set-Cookie response headers.)

When the user agent terminates execution, it should let the user
discard all state information. Alternatively, the user agent may ask
the user whether state information should be retained; the default
should be "no". If the user chooses to retain state information, it
would be restored the next time the user agent runs.

NOTE: User agents should probably be cautious about using files to
store cookies long-term. If a user runs more than one instance of
the user agent, the cookies could be commingled or otherwise messed
up.

7.2 Protocol Design

The restrictions on the value of the Domain attribute, and the rules
concerning unverifiable transactions, are meant to reduce the ways
that cookies can "leak" to the "wrong" site. The intent is to
restrict cookies to one, or a closely related set of hosts.
Therefore a request-host is limited as to what values it can set for
Domain. We consider it acceptable for hosts host1.foo.com and
host2.foo.com to share cookies, but not a.com and b.com.

Similarly, a server can only set a Path for cookies that are related
to the request-URI.

8. SECURITY CONSIDERATIONS

8.1 Clear Text

The information in the Set-Cookie and Cookie headers is unprotected.
Two consequences are:

1. Any sensitive information that is conveyed in them is exposed
to intruders.

2. A malicious intermediary could alter the headers as they travel
in either direction, with unpredictable results.

These facts imply that information of a personal and/or financial
nature should only be sent over a secure channel. For less sensitive
information, or when the content of the header is a database key, an
origin server should be vigilant to prevent a bad Cookie value from
causing failures.

8.2 Cookie Spoofing

Proper application design can avoid spoofing attacks from related
domains. Consider:

1. User agent makes request to victim.cracker.edu, gets back
cookie session_id="1234" and sets the default domain
victim.cracker.edu.

2. User agent makes request to spoof.cracker.edu, gets back
cookie session-id="1111", with Domain=".cracker.edu".

3. User agent makes request to victim.cracker.edu again, and
passes

Cookie: $Version="1";
session_id="1234";
session_id="1111"; $Domain=".cracker.edu"

The server at victim.cracker.edu should detect that the second
cookie was not one it originated by noticing that the Domain
attribute is not for itself and ignore it.

8.3 Unexpected Cookie Sharing

A user agent should make every attempt to prevent the sharing of
session information between hosts that are in different domains.
Embedded or inlined objects may cause particularly severe privacy
problems if they can be used to share cookies between disparate
hosts. For example, a malicious server could embed cookie
information for host a.com in a URI for a CGI on host b.com. User
agent implementors are strongly encouraged to prevent this sort of
exchange whenever possible.

9. OTHER, SIMILAR, PROPOSALS

Three other proposals have been made to accomplish similar goals.
This specification is an amalgam of Kristol's State-Info proposal and
Netscape's Cookie proposal.

Brian Behlendorf proposed a Session-ID header that would be user-
agent-initiated and could be used by an origin server to track
"clicktrails". It would not carry any origin-server-defined state,
however. Phillip Hallam-Baker has proposed another client-defined
session ID mechanism for similar purposes.

While both session IDs and cookies can provide a way to sustain
stateful sessions, their intended purpose is different, and,
consequently, the privacy requirements for them are different. A
user initiates session IDs to allow servers to track progress through
them, or to distinguish multiple users on a shared machine. Cookies
are server-initiated, so the cookie mechanism described here gives
users control over something that would otherwise take place without
the users' awareness. Furthermore, cookies convey rich, server-
selected information, whereas session IDs comprise user-selected,
simple information.

10. HISTORICAL

10.1 Compatibility With Netscape's Implementation

HTTP/1.0 clients and servers may use Set-Cookie and Cookie headers
that reflect Netscape's original cookie proposal. These notes cover
inter-operation between "old" and "new" cookies.

10.1.1 Extended Cookie Header

This proposal adds attribute-value pairs to the Cookie request header
in a compatible way. An "old" client that receives a "new" cookie
will ignore attributes it does not understand; it returns what it
does understand to the origin server. A "new" client always sends
cookies in the new form.

An "old" server that receives a "new" cookie will see what it thinks
are many cookies with names that begin with a $, and it will ignore
them. (The "old" server expects these cookies to be separated by
semi-colon, not comma.) A "new" server can detect cookies that have
passed through an "old" client, because they lack a $Version
attribute.

10.1.2 Expires and Max-Age

Netscape's original proposal defined an Expires header that took a
date value in a fixed-length variant format in place of Max-Age:

Wdy, DD-Mon-YY HH:MM:SS GMT

Note that the Expires date format contains embedded spaces, and that
"old" cookies did not have quotes around values. Clients that
implement to this specification should be aware of "old" cookies and
Expires.

10.1.3 Punctuation

In Netscape's original proposal, the values in attribute-value pairs
did not accept "-quoted strings. Origin servers should be cautious
about sending values that require quotes unless they know the
receiving user agent understands them (i.e., "new" cookies). A
("new") user agent should only use quotes around values in Cookie
headers when the cookie's version(s) is (are) all compliant with this
specification or later.

In Netscape's original proposal, no whitespace was permitted around
the = that separates attribute-value pairs. Therefore such
whitespace should be used with caution in new implementations.

10.2 Caching and HTTP/1.0

Some caches, such as those conforming to HTTP/1.0, will inevitably
cache the Set-Cookie header, because there was no mechanism to
suppress caching of headers prior to HTTP/1.1. This caching can lead
to security problems. Documents transmitted by an origin server
along with Set-Cookie headers will usually either be uncachable, or
will be "pre-expired". As long as caches obey instructions not to
cache documents (following Expires: <a date in the past> or Pragma:
no-cache (HTTP/1.0), or Cache-control: no-cache (HTTP/1.1))
uncachable documents present no problem. However, pre-expired
documents may be stored in caches. They require validation (a
conditional GET) on each new request, but some cache operators loosen
the rules for their caches, and sometimes serve expired documents
without first validating them. This combination of factors can lead
to cookies meant for one user later being sent to another user. The
Set-Cookie header is stored in the cache, and, although the document
is stale (expired), the cache returns the document in response to
later requests, including cached headers.

11. ACKNOWLEDGEMENTS

This document really represents the collective efforts of the
following people, in addition to the authors: Roy Fielding, Marc
Hedlund, Ted Hardie, Koen Holtman, Shel Kaphan, Rohit Khare.

12. AUTHORS' ADDRESSES

David M. Kristol
Bell Laboratories, Lucent Technologies
600 Mountain Ave. Room 2A-227
Murray Hill, NJ 07974

Phone: (908) 582-2250
Fax: (908) 582-5809
EMail: dmk@bell-labs.com

Lou Montulli
Netscape Communications Corp.
501 E. Middlefield Rd.
Mountain View, CA 94043

Phone: (415) 528-2600
EMail: montulli@netscape.com

Posted by 방글24

    Client Side State - HTTP Cookies



Original of this text is here(www.netscape.com/newsref/std/cookie_spec.html)

PERSISTENT CLIENT STATE
HTTP COOKIES

Preliminary Specification - Use with caution


    Introduction

Cookies are a general mechanism which server side connections (such as CGI scripts) can use to both store and retrieve information on the client side of the connection. The addition of a simple, persistent, client-side state significantly extends the capabilities of Web-based client/server applications.

    Overview

A server, when returning an HTTP object to a client, may also send a piece of state information which the client will store. Included in that state object is a description of the range of URLs for which that state is valid. Any future HTTP requests made by the client which fall in that range will include a transmittal of the current value of the state object from the client back to the server. The state object is called a cookie, for no compelling reason.

This simple mechanism provides a powerful new tool which enables a host of new types of applications to be written for web-based environments. Shopping applications can now store information about the currently selected items, for fee services can send back registration information and free the client from retyping a user-id on next connection, sites can store per-user preferences on the client, and have the client supply those preferences every time that site is connected to.

    Specification

A cookie is introduced to the client by including a Set-Cookie header as part of an HTTP response, typically this will be generated by a CGI script.

    Syntax of the Set-Cookie HTTP Response Header

This is the format a CGI script would use to add to the HTTP headers a new piece of data which is to be stored by the client for later retrieval.
Set-Cookie: NAME=VALUE; expires=DATE;
path=PATH; domain=DOMAIN_NAME; secure
NAME=VALUE
This string is a sequence of characters excluding semi-colon, comma and white space. If there is a need to place such data in the name or value, some encoding method such as URL style %XX encoding is recommended, though no encoding is defined or required.

This is the only required attribute on the Set-Cookie header.

expires=DATE
The expires attribute specifies a date string that defines the valid life time of that cookie. Once the expiration date has been reached, the cookie will no longer be stored or given out.

The date string is formatted as:

Wdy, DD-Mon-YYYY HH:MM:SS GMT
This is based on RFC 822, RFC 850, RFC 1036, and RFC 1123, with the variations that the only legal time zone is GMT and the separators between the elements of the date must be dashes.

expires is an optional attribute. If not specified, the cookie will expire when the user's session ends.

Note: There is a bug in Netscape Navigator version 1.1 and earlier. Only cookies whose path attribute is set explicitly to "/" will be properly saved between sessions if they have an expires attribute.

domain=DOMAIN_NAME
When searching the cookie list for valid cookies, a comparison of the domain attributes of the cookie is made with the Internet domain name of the host from which the URL will be fetched. If there is a tail match, then the cookie will go through path matching to see if it should be sent. "Tail matching" means that domain attribute is matched against the tail of the fully qualified domain name of the host. A domain attribute of "acme.com" would match host names "anvil.acme.com" as well as "shipping.crate.acme.com".

Only hosts within the specified domain can set a cookie for a domain and domains must have at least two (2) or three (3) periods in them to prevent domains of the form: ".com", ".edu", and "va.us". Any domain that fails within one of the seven special top level domains listed below only require two periods. Any other domain requires at least three. The seven special top level domains are: "COM", "EDU", "NET", "ORG", "GOV", "MIL", and "INT".

The default value of domain is the host name of the server which generated the cookie response.

path=PATH
The path attribute is used to specify the subset of URLs in a domain for which the cookie is valid. If a cookie has already passed domain matching, then the pathname component of the URL is compared with the path attribute, and if there is a match, the cookie is considered valid and is sent along with the URL request. The path "/foo" would match "/foobar" and "/foo/bar.html". The path "/" is the most general path.

If the path is not specified, it as assumed to be the same path as the document being described by the header which contains the cookie.

secure
If a cookie is marked secure, it will only be transmitted if the communications channel with the host is a secure one. Currently this means that secure cookies will only be sent to HTTPS (HTTP over SSL) servers.

If secure is not specified, a cookie is considered safe to be sent in the clear over unsecured channels.

    Syntax of the Cookie HTTP Request Header

When requesting a URL from an HTTP server, the browser will match the URL against all cookies and if any of them match, a line containing the name/value pairs of all matching cookies will be included in the HTTP request. Here is the format of that line:
Cookie: NAME1=OPAQUE_STRING1; NAME2=OPAQUE_STRING2 ...

    Additional Notes

  • Multiple Set-Cookie headers can be issued in a single server response.
  • Instances of the same path and name will overwrite each other, with the latest instance taking precedence. Instances of the same path but different names will add additional mappings.
  • Setting the path to a higher-level value does not override other more specific path mappings. If there are multiple matches for a given cookie name, but with separate paths, all the matching cookies will be sent. (See examples below.)
  • The expires header lets the client know when it is safe to purge the mapping but the client is not required to do so. A client may also delete a cookie before it's expiration date arrives if the number of cookies exceeds its internal limits.
  • When sending cookies to a server, all cookies with a more specific path mapping should be sent before cookies with less specific path mappings. For example, a cookie "name1=foo" with a path mapping of "/" should be sent after a cookie "name1=foo2" with a path mapping of "/bar" if they are both to be sent.
  • There are limitations on the number of cookies that a client can store at any one time. This is a specification of the minimum number of cookies that a client should be prepared to receive and store.
    • 300 total cookies
    • 4 kilobytes per cookie, where the name and the OPAQUE_STRING combine to form the 4 kilobyte limit.
    • 20 cookies per server or domain. (note that completely specified hosts and domains are treated as separate entities and have a 20 cookie limitation for each, not combined)
    Servers should not expect clients to be able to exceed these limits. When the 300 cookie limit or the 20 cookie per server limit is exceeded, clients should delete the least recently used cookie. When a cookie larger than 4 kilobytes is encountered the cookie should be trimmed to fit, but the name should remain intact as long as it is less than 4 kilobytes.
  • If a CGI script wishes to delete a cookie, it can do so by returning a cookie with the same name, and an expires time which is in the past. The path and name must match exactly in order for the expiring cookie to replace the valid cookie. This requirement makes it difficult for anyone but the originator of a cookie to delete a cookie.
  • When caching HTTP, as a proxy server might do, the Set-cookie response header should never be cached.
  • If a proxy server receives a response which contains a Set-cookie header, it should propagate the Set-cookie header to the client, regardless of whether the response was 304 (Not Modified) or 200 (OK).

    Similarly, if a client request contains a Cookie: header, it should be forwarded through a proxy, even if the conditional If-modified-since request is being made.

    Examples

Here are some sample exchanges which are designed to illustrate the use of cookies.

First Example transaction sequence:

Client requests a document, and receives in the response:
Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT
When client requests a URL in path "/" on this server, it sends:
Cookie: CUSTOMER=WILE_E_COYOTE
Client requests a document, and receives in the response:
Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
When client requests a URL in path "/" on this server, it sends:
Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
Client receives:
Set-Cookie: SHIPPING=FEDEX; path=/foo
When client requests a URL in path "/" on this server, it sends:
Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
When client requests a URL in path "/foo" on this server, it sends:
Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001; SHIPPING=FEDEX

Second Example transaction sequence:

Assume all mappings from above have been cleared.
Client receives:
Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
When client requests a URL in path "/" on this server, it sends:
Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001
Client receives:
Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo
When client requests a URL in path "/ammo" on this server, it sends:
Cookie: PART_NUMBER=RIDING_ROCKET_0023; PART_NUMBER=ROCKET_LAUNCHER_0001
NOTE: There are two name/value pairs named "PART_NUMBER" due to the inheritance of the "/" mapping in addition to the "/ammo" mapping.

Corporate Sales: 415/937-2555; Personal Sales: 415/937-3777; Government Sales: 415/937-3678
If you have any questions, please visit Customer Service.

Copyright ⓒ 1997 Netscape Communications Corporation


Posted by 방글24
쿠키는 서버와 클라이언트 사이에 정보를 주고 받을 수 있는 통로인 동시에, 서버가 사용할 수 있는 유일한 로컬시스템(클라이언트) 자원입니다. 이러한 쿠키를 이용하면 방문자에게 좀 더 친밀한(?) 서비스를 제공할 수 있는 웹사이트를 구성할 수 있습니다.
하지만 쿠키가 로컬시스템에 저장된다는 것 때문에 혹시 나의 정보가 나도 모르게 외부로 유출되지 않는가 하는 걱정을 하게 만드는 것도 쿠키입니다.
여기서는 쿠키가 매우 유용한 도구라는 긍정적인 면에서 쿠키정보를 다루기 위한 클래스를 작성해 보려 합니다. 이 클래스는 세셔너에 포함된 세셔너핸들러 쿠키용과 비교해 볼 때 유사한 부분이 많이 있습니다. 그러나 쿠키만을 위해 제작되었기 때문에 소스 분석하기에는(이해하기에는) 훨씬 수월할 것입니다. 이 클래스는 쿠키를 요리하는 도구의 역할을 하기 때문에 이름을 쿠커(cooker)라고 정했습니다.
쿠키(cooker - class.cooker.php)를 이용하는 것이 보안상 여러가지 문제를 가지고 있음에도 불구하고 제가 쿠커를 작성하는 것은 쿠키가 세션과 같은 다른 방법보다는 이해하기가 쉽고 웹문서를 작성하기가 편하고 단순하다는 것입니다. 또한 서버자원이 아닌 방문자의 로컬시스템 하드디스크에 쿠키정보를 저장하게 되어 많은 방문자가 동시에 접속하는 웹사이트에서는 많은 장점을 가지게 됩니다. 그리고 보안에 조금만 주의를 기울인다면 아주 민감한 정보가 아닌 이상은 적용하는데 별 무리가 없다는 이유도 있습니다. 제 자신과 여러분에게도 한번쯤은 쿠키 사용법을 습득할 수 있는 기회가 될 수도 있겠지요.
쿠커란?
쿠키를 직접 관리해주는 클래스입니다. 클라이언트에서 날라온 쿠키값을 디코딩(암호 해독 과정 포함)하여 얻은 정보를 이용해 쿠키변수를 설정합니다. 이 과정에서 쿠키가 담고 있는 현재 상태를 얻을 수 있습니다. 새로운 쿠키를 생성할 때는 쿠키변수 정보를 인코딩(암호화 과정 포함)하여 이 정보를 클라이언트로 보내어 쿠키파일에 저장할 수 있도록 합니다. 인코딩 과정에서 쿠키변수 정보와 함께 클라이언트 IP 및 현재 시간을 함께 담아 보내게 되며 이러한 정보는 다음 페이지에서 쿠키를 디코딩하는 과정에서 추출되어 적절히 이용하게 됩니다. 클라이언트 IP는 보안을 고려할 때 필요한 정보이고 현재 시간은 쿠키의 유효기간을 결정하기 위한 정보로 사용됩니다.
< 쿠커의 역할 >
쿠키의 유효기간
쿠키의 유효기간은 우선 params() 메소드로 설정할 수 있습니다. params()에 의해 쿠키 생성할 때 설정된 유효기간은 웹브라우저에 의해 관리됩니다. params() 메소드에서 lifetime의 기본값은 0입니다. 따라서 브라우저가 살아있는 동안만 쿠키가 존재합니다. 브라우저를 종료하는 즉시 쿠키 정보도 같이 사라집니다.
서버에서 관리되는 쿠키의 유효기간이 별도로 존재합니다. 브라우저에서 관리되는 lifetime과 독립적으로 서버에서는 쿠키 생성 후 31536001초(1년)가 지나면 쿠커가 생성한 쿠키를 삭제하도록 되어있습니다. 이 값은 gc_maxlifetime() 메소드로 변경될 수 있습니다.
gc_maxlifetime() 함수로 유효기간을 설정하는 것은 쿠키를 처음 생성할 때 한번만 수행하면 됩니다. 따라서 여러페이지에 걸쳐 쿠커를 사용할 때는 처음 진입하는 페이지에서만 이 함수로 유효기간을 설정하면 됩니다. 다른 페이지에서는 이 함수를 사용하지 않더라도 이미 유효기간에 대한 정보가 쿠키 내에 포함되어 있으므로 자동으로 수행할 수 있습니다.
제공되는 메소드
메소드 버전 기능
start 0.0.1 쿠키파일로부터 쿠키정보를 전달받아 쿠키변수 설정
params 0.0.1 쿠키 설정 매개변수 획득/설정
gc_maxlifetime 0.0.2 서버상에서 확인하는 쿠키의 생존시간 획득/설정
name 0.0.1 쿠키파일에 저장될 쿠키명 획득/설정
get 0.0.1 쿠키변수값 획득
set 0.0.1 쿠키변수 등록 및 값 설정
isset2 0.0.2 쿠키변수 존재여부 확인
unset2 0.0.1 쿠키변수 삭제
write 0.0.1 쿠키변수에 기록된 쿠키정보를 쿠키파일에 저장
delete 0.0.1 쿠키변수 삭제, 쿠키파일의 쿠키삭제
메소드 사용법
int start(void)
클라이언트에서 전달된 쿠키를 받아 그 정보를 디코딩한 후 방문자 IP, 쿠키에 마지막으로 접근한 시간, 쿠키변수를 설정합니다. 그리고 쿠키와 PHP에 의해 자동으로 만들어지는 $HTTP_COOKIE_VARS["쿠키명"] 및 해당 전역변수를 삭제합니다. 따라서 이들 전역변수에 의해 쿠키값에 접근할 수 없습니다. 쿠키명은 디폴트로 "PHP_AUTH_DATA"로 지정되어 있습니다.
방문자 IP, 쿠키에 마지막으로 접근한 시간, 쿠키변수 정보를 통해 쿠키의 현재 상태를 파악해 그 값을 되돌려 줍니다. 마지막으로 현재 시간을 기준으로 쿠키파일의 쿠키를 업데이트합니다.
< start() 함수의 동작 >
반환되는 상태값을 보면 다음과 같습니다.
상태값 설명
0 등록된 쿠키변수가 존재함(정상적인 상태)
1 초기 상태(이전에 쿠키가 생성된 적이 없거나 브라우저가 쿠키를 받아들이지 않음)
2 쿠키가 만료되었음, 따라서 등록된 모든 쿠키변수가 삭제되었음
3 등록된 쿠키변수가 없음
4 앞서 쿠키를 생성한 방문자 IP와 현재 방문자 IP가 다름(이상한 사람임)
[code php;gutter:false] <?php

require "./cooker/class.cooker.php"; // 쿠키정보 클래스

$cooker = new Cooker;

$cooker->params(3600);
$status = $cooker->start();

switch ($status) {
case 0:
echo "이전 페이지에서 쿠키변수를 등록하셨군요.\n"";
echo "\n";
echo "USERID=".$cooker->get("USERID")."\n"";
echo "DATA=".$cooker->get("DATA")."\n"";
$cooker->delete();
echo "쿠키변수 및 쿠키파일의 쿠커정보를 지웠습니다.\n"";
echo "USERID=".$cooker->get("USERID")."\n"";
echo "DATA=".$cooker->get("DATA")."\n"";
break;
case 1:
$data = "처음으로 구원진 쿠키";
$cooker->set("USERID", "hwooky");
$cooker->set("DATA", $data);
$cooker->write();
echo "이전에 쿠키가 생성된 적이 없거나"
." 브라우저가 쿠키를 받아들이지 않습니다.\n"";
echo "\n";
echo "USERID=hwooky\n"";
echo "DATA=$data\n"";
echo "새로운 쿠키를 구웠습니다.\n"";
break;
case 2:
$data = "쿠키가 만료되었습니다.";
break;
case 3:
echo "등록된 쿠키변수가 없습니다.\n"";
break;
case 4:
echo "어떻게 들어오셨어요???\n"";
break;
}

echo "<A href=$PHP_SELF?id=$id>다시실행</A>";

?> [/code]
쿠커 내부에서 기본으로 설정된 유효기간은 24분(1440초)입니다. 이것은 세션함수에서의 유효기간 기본값과 같습니다.
void params(int lifetime [, string path [, string domain]])
PHP4 세션함수에서 session_set_cookie_params() 함수와 같이 쿠키를 생성할 때 필요한 유효기간, 유효경로, 유효도메인을 설정하는데 사용되는 함수입니다. 이 함수는 반드시 start() 함수보다 앞서 수행하여야 합니다. 각 매개변수에 대한 자세한 설명을 앞장("쿠키 규격") 및 PHP4 메뉴얼 세션함수를 참조바랍니다.
[code php;gutter:false] $cooker->params(3600, "/phpclass/exam/cooker/", ".phpclass.com"); [/code]
첫번째 매개변수 lifetime는 쿠키가 생존하는 시간을 초로 나타냅니다. 3600초라고 지정하면 쿠키를 생성한 후 1시간이 지나면 쿠키는 더 이상 유효하지 않습니다. 이 값의 디폴트 값은 0이며 이 경우의 쿠키는 사용자가 브라우저를 종료할 때까지만 존재합니다.
두번째 매개변수 path는 유효경로를 지정합니다. 특정 디렉토리에서만 이용할 필요가 있는 쿠키를 생성할 때 유효경로를 지정합니다. 위와 같이 "/phpclass/exam/cooker/"라고 지정하면 "http://www.phpclass.com/phpclass/exam/cooker/"의 디렉토리 및 그 하위디렉토리에 있는 웹문서만 사용할 수 있는 쿠키를 생성합니다. 다른 곳에 있는 웹문서는 이 쿠키를 받을 수 없습니다. 디폴트 값은 "/"이며 이 경우의 쿠키는 서버의 모든 디렉토리에서 유효합니다.
세번째 매개변수 domain은 쿠키의 유효도메인을 지정합니다. 위와 같이 ".phpclass.com"이라고 지정하면 www.phpclass.com, ftp.phpclass.com 등 도메인의 뒷부분이 일치하는 웹서버로만 쿠키가 전달됩니다. 디폴트 값은 ""이며 이 경우의 쿠키는 쿠키를 생성한 서버의 도메인으로 자동 지정됩니다.
array params()
PHP4 세션함수에서 session_get_cookie_params() 함수와 같은 역할을 수행합니다. 즉 쿠키를 생성할 때 필요한 유효기간, 유효경로, 유효도메인의 현재 설정값을 되돌려 줍니다.
[code php;gutter:false] $params = $cooker->params();
echo "유효기간=".$params["lifetime"]."\n""
echo "유효경로=".$params["path"]."\n""
echo "유효도메인=".$params["domain"]."\n"" [/code]
void gc_maxlifetime(int lifetime), int gc_maxlifetime(void)
위에 있는 params() 함수가 클라이언트에 생성하게 되는 쿠키의 유효기간을 설정하는 것이라면 gc_maxlifetime() 함수는 서버에서 쿠키의 유효기간을 확인할 수 있도록 그 시간을 설정하거나 획득하기 위한 함수입니다.
[code php;gutter:false] $cooker = new Cooker;
$cooker->params(0); //클라이언트에서의 쿠키지속시간
$cooker->gc_maxlifetime(1440); //서버에서의 쿠키지속시간(초단위/24분)
$cooker->start(); [/code]
위와 같은 경우 params()에서 lifetime을 0으로 설정하였기 때문에 클라이언트에서의 쿠키지속시간은 브라우저가 살아있는 한 계속 쿠키는 존재합니다. 그러나 쿠키가 생성된 후 24분이 지나면 서버에서 gc_maxlifetime(1440)에 의해 쿠키정보를 임의로 삭제하게 됩니다. 이러한 기능은 시간에 의한 자동로그아웃을 구현할 때 유용하게 사용될 수 있을 것입니다.
params()와 gc_maxlifetime() 함수에서 설정할 때는 모두 start() 함수 전에 수행하여야 합니다.
string name([string newname])
쿠커에서 사용되는 쿠키명(cookie name)을 얻거나 새로운 쿠키명으로 설정할 때 사용할 수 있습니다. 새로운 쿠키명을 설정할 때는 반드시 start() 함수보다 앞서 수행하여야 합니다. 쿠커는 기본적으로 쿠키명을 "PHP_AUTH_DATA"로 설정되어 있습니다. 보안을 위해 주기적으로 변경해주는 것이 바람직합니다.
[code php;gutter:false] $cooker = new Cooker;
$cooker->name("NEW_COOKIE_NAME");
$cooker->start();
.
.
. [/code]
array get(void)
등록된 모든 쿠키변수에 대한 정보를 되돌려줍니다. 정확한 정보를 얻기 위해서는 start() 함수를 먼저 수행하여야 합니다.
[code php;gutter:false] $list = $cooker->get();
if (is_array($list))
while(list($name,$value)=each($list))
echo "\$list[$name]=$value\n""; [/code]
string get(string name)
쿠키변수명을 입력 매개변수로 지정하면 해당 쿠키변수명에 대한 값을 되돌려 줍니다.
[code php;gutter:false] $userid = $cooker->get("USERID"); [/code]
void set(string name [, string value])
쿠키변수를 등록시켜주며 동시에 그 값을 설정합니다. 값을 지정하지 않으면 널문자열로 초기화합니다.
[code php;gutter:false] $cooker->set("USERID", "hwooky"); [/code]
bool isset2(string name)
등록된 쿠키변수가 존재하는지 확인합니다. 존재하면 true, 아니면 false를 반환합니다. 쿠키변수의 값이 null이더라도 존재한다면 true를 반환합니다.
[code php;gutter:false] if ($cooker->isset2("USERID"))
echo "쿠키변수 USERID가 존재하네요.\n""; [/code]
void unset2([string name])
등록된 쿠키변수를 삭제합니다. 입력 매개변수를 지정하지 않으면 모든 쿠키변수를 삭제합니다.
[code php;gutter:false] $cooker->unset2("USERID"); [/code]
쿠키변수를 삭제해 주는 함수의 함수명은 unset2입니다. 메소드명을 unset으로하여 함수를 정의하면 에러(Parse error)가 발생하여 할 수 없이 unset2로 명명하였습니다. 클래스 내에서 정의된 메소드명이라 내장함수 unset와 전혀 관련이 없는데도 에러가 나는 것을 보면 PHP의 버그가 아니면 unset() 함수가 다른 함수와 달리 PHP 내에서 특수하게 처리되는 것 같습니다. 이와같이 메소드명으로 사용할 수 없는 함수명으로는 unset 외에도 empty, isset 입니다. 모두 변수 처리 관련 함수들입니다.
void write(void)
등록된 쿠키변수와 기타 쿠키파일에 저장할 정보를 인코딩(암호화 포함)하여 쿠키파일에 저장합니다. start() 함수를 먼저 수행하여야 하며, 또한 내부적으로 PHP header() 함수를 사용하기 때문에 브라우저로 출력하는 문자가 발생하기 전에 수행하여야 합니다.
[code php;gutter:false] $cooker->write(); [/code]
void delete()
쿠키변수를 모두 삭제한 후 쿠키파일에서 쿠커가 사용하는 쿠키를 삭제합니다. write() 함수와는 달리 응답헤더 정보와 관계없이 수행합니다. 왜냐하면 쿠키를 삭제하기 위해 PHP header() 함수를 사용하지 않으며 자바스크립트의 document.cookie 객체를 이용합니다. 로그아웃과 같은 기능을 수행할 때 요긴하게 사용될 수 있을 것입니다. 없어도 로그아웃할 수는 있겠지만 보다 편하게 하기 위해 작성되었습니다.
[code php;gutter:false] $cookie->delete(); [/code]
데이터 암호화 클래스(class.crypto.php)
보안에 취약한 쿠키의 단점을 다소나마 보완하기 위해 쿠키값을 암호화하는데 활용할 수 있는 클래스입니다. 이 클래스는 제가 작성한 것이 아니며 hansanderson 라는 분이 작성하여 공개한 것을 포함시켰을 뿐입니다. 쿠키를 아무리 암호화한다고 해도 그 알고리즘이 노출된다면 본래의 목적이 반감될 수 밖에 없다는 것을 인식하시고 이 부분은 직접 작성할 것을 고려해 보시는 것이 좋을 듯합니다. 따라서 이 클래스는 참고용으로 첨부되어 있을 뿐입니다. 이 클래스에서 정의된 메소드는 쿠커(class.cooker.php)에서 사용하게 됩니다. 그러나 실제로 쿠커 내용을 보면 아시겠지만 데이터 암호화 클래스에 있는 메소드를 전혀 이용하지 않고 있습니다. 동일한 메소드를 쿠커 내에서 더미함수로 정의하여 사용하고 있습니다. 따라서 현재의 쿠커를 이용하더라도 쿠키의 암호화는 수행되지 않습니다. 이것은 여러분의 몪으로 남겨 놓겠습니다. 아래는 데이터 암호화 클래스(class.crypto.php)를 공개한 분에 대한 개인신상입니다.
AUTHOR hansanderson
HOME www.hansanderson.com/php/crypto/
EMAIL corporation@hansanderson.com
쿠커를 이용한 실험 예제
메뉴 "회원인증정보 >> 장바구니 클래스"에 있는 예제를 실험 대상으로 하였습니다. 자세한 것은 "장바구니 클래스"를 참조바랍니다.

Posted by 방글24
document.cookie 객체의 구조
자바스크립트에서는 document.cookie 객체를 통해 쿠키에 접근할 수 있습니다. 이 객체는 대입연산자를 통해 새로운 값을 내부 쿠키 리스트에 추가할 수 있습니다.
[code javascript;gutter:false] document.cookie = "ID=123456789";
document.cookie = "PW=abcdefghi"; [/code]
위와 같은 자바스크립트를 수행하면 일반적인 대입문처럼 쿠키명 ID가 없어지는 것이 아니라 내부 쿠키 리스트에 ID라는 쿠키와 PW라는 쿠키가 추가될 것입니다. 만약 쿠키명이 일치하는 것이 내부 쿠키 리스트에 있었다면 새로운 값으로 대치될 것입니다.
이미 생성되어 있는 쿠키를 참조하려면 document.cookie 객체를 문자열처럼 다루면 됩니다. 이 문자열은 쿠키명과 쿠키값으로 구성되어 있습니다. 각 쿠키명과 쿠키값은 등호(=)로 구분되어 있고, 각각의 쿠키는 세미콜론(;)으로 구분되어 있습니다. 위와 같이 쿠키가 생성되었을 때 document.cookie 객체를 참조하면 "ID=123456789;PW=abcdefghi"라는 문자열을 얻을 수 있습니다. 이 문자열을 가지고 문자열 메소드인 indexOf() 또는 substring() 함수를 이용하면 각 쿠키에 대한 정보를 분리할 수 있을 것입니다. 이러한 예는 아래에 있는 사용자 정의 함수 getCookie()를 참조하기 바랍니다.
PHP에서와 마찬가지로 유효한 도메인과 유효한 경로에서 만들어 낸 쿠키 정보만이 document.cookie을 통해서 볼 수 있습니다.
document.cookie 객체를 직접 사용할 수도 있지만, 대부분 아래와 같이 미리 정의된 함수 setCookie(), getCookie(), delCookie()를 통해 쿠키를 다루게 됩니다.
쿠키 설정하기
PHP의 setcookie() 함수와는 달리 expires(유효기간) 매개변수의 단위는 천분의 일초단위로 설정합니다. secure가 다소 다르기는 하지만 다른 매개변수는 PHP와 별다르지 않습니다. 저장된 쿠키 정보를 보면 문자열 소스 차원에서 PHP에서 다룰 때와 동일하지 않습니다. 왜냐하면 PHP에서 인코딩/디코딩하는 방식과 자바스크립트에서 인코딩/디코딩하는 방식이 다르기 때문입니다. 따라서 양쪽의 함수를 혼용하여 사용하는데는 문제가 있으니 주의하기 바랍니다. 여기에 정의된 setCookie() 함수는 "Designing Dynamic Web Pages with JavaScript"의 저자 Nick Heinle의 작품을 변형시킨 것입니다. 본래의 함수는 서적을 참조하시기 바랍니다. 이 원서에 대한 번역서는 "자바스크립트로 다이나믹 웹페이지 디자인하기"라는 제목으로 나와 있습니다.
[code javascript;gutter:false] function setCookie(name, value, expires, path, domain, secure) {
secure = (secure == null) ? false : secure;
var exp = new Date();
exp.setTime(expires);
document.cookie = name + "=" + escape(value)
+ ((expires == null) ? "" : ("; expires=" + exp.toGMTString()))
+ ((path == null) ? "" : ("; path=" + path))
+ ((domain == null) ? "" : ("; doamin=" + domain))
+ ((secure == true) ? "; secure" : "");
} [/code]
예를 들어 아래와 같이 각 매개변수를 지정할 수 있으며, 이 때 유효기간은 1시간이 됩니다.
[code javascript;gutter:false] setCookie(
"mycookie", // 쿠키명
"cookie_value", // 쿠키값
exp.getTime()+1000*3600, // 유효 기간
"/exam", // 유효 디렉토리
".phpclass.com" // 유효 도메인
); [/code]
쿠키 정보 읽어오기
쿠키명과 값은 document.cookie 객체에 통해 참조될 수 있습니다. 자바스크립트가 저장하는 쿠키의 형태는 아래와 같으며 각각의 name=value 쌍은 세리콜론과 공백으로 구분되어지고 제일 마지막 값에는 세미콜론이 없습니다.
[code javascript;gutter:false] name1=value1; name2=value2; name3=value3 [/code]
쿠키의 값을 좀 더 쉽게 얻기 위해 다음과 같이 getCookie() 함수를 정의하여 사용합니다. 이 함수는 Nick Heinle의 작품을 그대로 가져왔습니다.
[code javascript;gutter:false] // Heinle's function for retrieving a cookie.
function getCookie(name) {
var cname = name + "=";
var dc = document.cookie;
if (dc.length > 0) {
begin = dc.indexOf(cname);
if (begin != -1) {
begin += cname.length;
end = dc.indexOf(";", begin);
if (end == -1)
end = dc.length;
return unescape(dc.substring(begin, end));
}
}
return null;
} [/code]
이 함수는 단지 쿠키명만 지정하여 주면 document.cookie 객체를 검사하여 해당 쿠키의 값을 되돌려 줍니다. 저장된 쿠키가 없는 경우에는 null 값을 되돌려 줍니다.
[code javascript;gutter:false] value = getCookie ("mycookie"); [/code]
쿠키 삭제하기
마지막으로 쿠키를 삭제할 수 있는 함수 delCookie()를 살펴보겠습니다. 이 함수는 쿠키 센추럴(www.cookiecentral.com)에 있는 Dorcht의 함수를 그대로 가져왔습니다.
[code javascript;gutter:false] function delCookie (name, path, domain) {
if (getCookie(name)) {
document.cookie = name + "="
+ ((path == null) ? "" : "; path=" + path)
+ ((domain == null) ? "" : "; domain=" + domain)
+ "; expires=Thu, 01-Jan-70 00:00:01 GMT";
}
} [/code]
delCookie() 함수는 쿠키 파일에서 쿠키를 삭제하기 위해 사용되는 함수이다. delCookie() 함수를 사용하기 위해서는 보통 쿠키명만 넘겨주면 된다. 그러나 setCookie() 함수에서 쿠키를 구울 때 path와 domain을 지정하였으면, delCookie() 함수로 지울 때도 동일할 path와 domain을 분명히 지정해 주어야 합니다. 예를 들어, "mycookie" 쿠키에 대한 정보는 다음과 같이 지울 수 있습니다.
[code javascript;gutter:false] delCookie("mycookie", "/exam", ".phpclass.com"); [/code]
구두점 인코딩/디코딩
브라우저가 등호(=)와 세미콜론(;)을 각 쿠키를 분리시키는 구분자로 사용하기 때문에, 이것들은 자신이 저장하는 텍스트안에 넣을 수가 없습니다. 이러한 특수 코드를 쿠키값에 저장하려면 document.cookie 객체에 문자열을 넘기기 전에 escape()를 사용하여 인코딩해야 하고, unescape()를 사용하여 복구하여야 합니다.
escape() 함수
일반문자를 ASCII 형식(URL 형식; 폼에서 보내어진 %가 붙은 문자) 문자로 변환합니다. 예를 들어 아래와 같이 "ASCII &? 문자"라는 문자열을 escape() 함수로 넘겨주면 "ASCII%20%26%3F%20%uBB38%uC790"라는 문자열을 되돌려 받습니다.
[code javascript;gutter:false] var encode = escape("ASCII &? 문자"); [/code]
unescape() 함수
ASCII 형식(URL 형식) 문자를 일반문자로 변환합니다. 예를 들어 아래와 같이 "ASCII%20%26%3F%20%uBB38%uC790"라는 문자열을 unescape() 함수로 넘겨주면 "ASCII &? 문자"라는 문자열을 되돌려 받습니다.
[code javascript;gutter:false] var decode = unescape("ASCII%20%26%3F%20%uBB38%uC790"); [/code]

'phpsource > 캐시&세션&쿠키' 카테고리의 다른 글

넷스케이프의 쿠키에 관한 예비 규격서(복사본)  (0) 2001.02.21
{쿠커}9.쿠커  (0) 2001.02.20
{쿠커}7.setcookie() 함수  (0) 2001.02.20
{쿠커}6.쿠키 다루기  (0) 2001.02.20
{쿠커}5.쿠키 규격  (0) 2001.02.20
Posted by 방글24
PHP에서의 쿠키
PHP가 거의 완벽하게 쿠키를 지원하기 때문에 쿠키를 이용하기 위해 이해하기 어려운 요구헤더나 응답헤더를 이해할 필요가 없습니다. 쿠키를 생성할 때는 setcookie() 함수를 사용합니다. 쿠키를 생성할 때 필요로 하는 옵션들 - 유효기간, 유효경로, 유효도메인, 보안설정 - 은 setcookie() 함수의 매개변수로 전달하면 됩니다. PHP 내에서 쿠키를 읽는 것은 변수를 액세스하는 것처럼 간단합니다. PHP 스크립트를 시작할 때 쿠키들은 자동적으로 전역변수로 사용되도록 만들어집니다. 예를 들어, 쿠키명이 "ID"이고 쿠키값이 "123456789"라면 쿠키명 "ID"에 해당하는 전역변수 $ID에 "123456789"라는 값이 저장되어 있을 것입니다. 때에 따라서는 $ID라는 전역변수대신에 $HTTP_COOKIE_VARS["ID"]라는 전역배열변수를 가지고 다룰 수 있습니다.
쿠키 설정하기
PHP에서는 setcookie() 함수를 이용하여 쿠키를 설정할 수 있습니다. PHP에서 쿠키를 생성하는 함수 setcookie()의 정의는 다음과 같으며, 이 중에 name를 제외한 나머지 매개변수는 모두 생략할 수 있습니다.
int setcookie(string name, string [value],
                                      int [expire],
                                      string [path],
                                      string [domain],
                                      int [secure]);
생략할 수 있는 매개변수에 대한 기본값은 빈문자열(value, path, domain)이거나 0(expire, secure)입니다. 예를 들어, 만약 expire와 path는 기본값을 사용하고 domain만 새로이 지정하고자 한다면 다음과 같이 사용할 수 있습니다.
[code php;gutter:false] setcookie("name", "value", 0, "", ".phpclass.com"); [/code]
구분 매개변수명 기본값 동작
쿠키의 유효기간 expires 0 사용자가 브라우저를 종료할 때 쿠키가 없어짐
쿠키의 유효 디렉토리 path 웹문서 경로 웹문서가 존재하는 디렉토리
쿠키의 유효 도메인 domain 지정안함 쿠키를 설정한 서버의 도메인
쿠키의 보안 secure 지정안함 Disabled
name & value
첫 번째 매개변수 name은 설정할 쿠키명이고 value는 그 쿠키에 저장될 이름입니다. 자세한 것은 앞장 "쿠키 규격"을 참조바랍니다.
유효기간 설정하기
세 번째 매개변수 expire는 쿠키 유효기간을 설정하는 함수이며, 정수형으로서 표준 유닉스 시간을 그 값으로 갖습니다. 유효기간은 반드시 타임스탬프(1970년 1월 1일 이후 시간을 초로 표시)로 지정됩니다. 이 타임스탬프는 PHP에서 time()과 mktime() 함수들을 사용하여 계산할 수 있습니다. time() 함수는 현재 시간을 타임스탬프로 리턴하며, mktime() 함수는 사람들에게 익숙한 형식의 날짜(예를 들어, Tue, 06 Feb 2001 12:57:21 GMT)를 타임스탬프로 변환해 줍니다. time() 함수와 mktime() 함수에 의해 계산된 시간은 웹서버 시간에 따라 계산되는데 반하여 쿠키의 유효기간은 웹서버가 아닌 클라이언트 시스템 상에서의 시간이며, 따라서 웹서버와 서로 다른 시간대에 있을 수 있습니다. 기본값인 0은 오직 현재 방문자의 브라우저 세션을 위해서 설정되며, 방문자가 브라우저를 닫으면 만료됩니다. 브라우저를 종료하더라도 계속 쿠키가 존재하기 위해서는 유효기간을 명시하여야 합니다.
[code php;gutter:false] // 3600초(1시간) 이후에 만료된다.
setcookie("mycookie", $value, time()+3600);

// 2002년 1월 1일에 만료된다.
setcookie("mycookie", $value, mktime(0,0,0,1,1,2002));

// 2020년 5월 12일 오후 6:30분에 만료된다.
setcookie("mycookie", $value, mktime(18,30,0,5,12,2020)); [/code]
이와 같이 유효기간을 지정하게 되면 브라우저를 종료한 뒤 다시 실행하더라도 그대로 보존되며, 지정된 시간이 되면 자동적으로 그 쿠키를 제거할 것입니다.
유효경로 지정하기
이 매개변수를 생략하는 경우에는 setcookie() 함수를 호출한 웹문서가 있는 디렉토리와 이 디렉토리의 하위 디렉토리에서만 쿠키값을 참조할 수 있게 됩니다. 따라서 PHP4 세션함수에서 사용되는 쿠키와 같이 모든 서버상의 모든 디렉토리에서 유효한 쿠키를 사용하려면 path 매개변수의 값으로 루트 디렉토리를 설정하여야 합니다. 즉, 세션함수에서의 쿠키는 "/"가 기본값이지만 setcookie() 함수에서의 기본값은 현재 디렉토리가 됩니다.
[code php;gutter:false] setcookie("mycookie", "cookie_value", 0, "/"); [/code]
"관련서적(?)"을 보다보면 이 부분에서 다소 상이하다는 것을 알 수 있습니다. 관련서적에는 기본 동작이 "/"로 서버상의 모든 디렉토리가 유효하다고 되어 있습니다. 그러나 이는 앞의쿠키 규격에서 보았듯이 HTTP 응답헤더 Set-Cookie에 유효경로를 지정하지 않으면 웹문서가 존재하는 디렉토리 및 그 하위 디렉토리에서만 유효한 쿠키가 만들어지게 됩니다. 관련서적 저자는 세션함수와 혼동하지 않았나 생각합니다. 세션함수에서 사용하는 쿠키의 유효경로는 "/"로 되어 있습니다. 물론 php.ini의 옵션 session.cookie_path에 설정된 값이 기본값이 되는 것이지요.
유효도메인 지정하기
복수 도메인에 쿠키를 사용하기 위해서는 아래와 같이 도메인의 앞쪽 부분을 생략하여 지정하여야 합니다. ".phpclass.com"라고 지정하면 www.phpclass.com, hwooky.phpclass.com, ..... 와 같이 뒤쪽이 일치하는 모든 도메인에서 쿠키를 사용할 수 있습니다. 그러나 www.phpclass.net라는 도메인에서는 쿠키를 사용할 수 없습니다.
[code php;gutter:false] setcookie("mycookie", "cookie_value", $expire, $path, ".phpclass.com"); [/code]
이것은 호스트 이름이 phpclass.com 도메인에 있는 모든 서버들로 쿠키를 전송하도록 브라우저에 알립니다.
쿠키의 보안 지정하기
타인으로부터 보호해야 할 민감한 정보가 쿠키에 포함되어 있을 때에 지정할 수 있는 매개변수입니다. 서버가 SSL(Secure Sockets Layer)을 지원할 때만 쿠키를 전송합니다.
배열값 쿠키 설정하기
도메인당 쿠키는 최대 20개까지 저장할 수 있다는 것은 앞에서도 언급한 바 있습니다. 그런데 관련서적을 보면 배열을 이용하면 여러 개의 값들을 하나의 쿠키에 저장시킬 수 있다고 되어 있습니다. 즉, 쿠키를 하나의 배열로 다루고, 그 배열에 있는 각 구성 요소에 값을 지정하는 것입니다. 그리고 이러한 경우의 예를 아래와 같다고 하였습니다. 아래의 예제들은 거의 모두 PHP 3.0.14에서 실험한 결과입니다.
[code php;gutter:false] if (!isset($mycookie[0])) {
setcookie("mycookie[0]", "hwooky");
}

$mycookie[1]++;
setcookie("mycookie[1]", $mycookie[1]);

echo ("Hello $mycookie[0], you've seen this page " .
$mycookie[1] . ($mycookie[1] == 1 ? " time!" : " times!")); [/code]
그러나 위와 같은 방법으로 배열 각 요소를 쿠키에 저장하게 되면 역시 각 배열 요소가 하나의 쿠키로 저장되기 때문에 20개가 넘는 배열 요소를 저장할 수 없습니다. 아래는 이 때 생성되는 쿠키입니다.
mycookie[1]
7
www.safety.katri/exam2/cookie/
0
2023223680
29397420
3081596640
29397410
*
mycookie[0]
hwooky
www.safety.katri/exam2/cookie/
0
1993223680
29397420
3054096640
29397410
*
그러면 실제로 20개가 넘는 배열 요소를 가지고 위와 같은 방법으로 쿠키를 구워 보도록 하죠. 아래는 이러한 경우의 예입니다.
[code php;gutter:false] <?php

for ($i=0;$i<26;$i++)
setcookie("cookie[$i]", "$i");

if (!isset($cookie)) {
echo "<META http-equiv='Refresh' content='0; URL=$PHP_SELF'>";
exit;
}

?>

<P>document.cookie에서 확인한 쿠키정보</P>
<SCRIPT language=JavaScript>
<!--
cookie_str = document.cookie;
while (-1 != cookie_str.indexOf(';')) {
current = cookie_str.substring(0, cookie_str.indexOf(';')+1);
cookie_str = cookie_str.substring(cookie_str.indexOf(';')+1);
document.write(current + '\n');
}
document.write(cookie_str + '\n');
//-->
</SCRIPT> [/code]
위 소스코드를 실행하면 아래와 같이 20개의 배열요소만 쿠키에 저장되어 있는 것을 확인할 수 있습니다. 여기서 하나 더 주의깊게 살펴볼 것이 있습니다. 쿠키를 구워낸 순서와 반대로 저장된다는 것입니다. 이것은 PHP3에서의 결과이며 뒤에서도 언급하겠지만 PHP4에서는 이 순서가 뒤바뀌게 됩니다.
document.cookie에서 확인한 쿠키정보

cookie[19]=19;
cookie[18]=18;
cookie[17]=17;
cookie[16]=16;
cookie[15]=15;
cookie[14]=14;
cookie[13]=13;
cookie[12]=12;
cookie[11]=11;
cookie[10]=10;
cookie[9]=9;
cookie[8]=8;
cookie[7]=7;
cookie[6]=6;
cookie[5]=5;
cookie[4]=4;
cookie[3]=3;
cookie[2]=2;
cookie[1]=1;
cookie[0]=0
쿠키를 구워낼 때 배열 요소 대신에 배열명을 지정하면 어떻게 될까요? 지금부터 알아보도록 하겠습니다.
[code php;gutter:false] <?php

if (!isset($mycookie)) {
$mycook = array("mycook1"
, "mycook2"
, "mycook3"
, "mycook4"
, "mycook5"
, "mycook6"
, "mycook7"
, "mycook8"
, "mycook9"
, "mycook10"
, "mycook11"
, "mycook12"
, "mycook13"
, "mycook14"
, "mycook15"
, "mycook16"
, "mycook17"
, "mycook18"
, "mycook19"
, "mycook20"
, "mycook21"
, "mycook22"
, "mycook23"
, "mycook24"
, "mycook25"
);

setcookie("mycookie", $mycook, time()+3600);
die("<META http-equiv='Refresh' content='0; URL=$PHP_SELF'>");
} else {
setcookie("mycookie", "", time()-3600*24*365);
if (is_array($mycookie))
while (list($name,$value)=each($mycookie))
echo "$name=$value\n";
else
echo "(no array)$mycookie\n";
}

?> [/code]
실행 결과는 아래와 같습니다.
(no array)Array
서버에서 받은 쿠키를 확인하면 배열값이 넘어오는 것이 아니라 단순 문자열 "Array"가 넘어온다는 것을 알 수 있습니다. 그럼 실제로 로컬 시스템에 저장된 쿠키는 어떻게 되었을까요? 그것을 알아보기 위해 로컬시스템에 저장된 쿠키파일을 살펴보았습니다. 아래는 위의 소스를 익스 5.0에서 실행한 후에 "c:\windows\cookies\hwooky@cookie[1].txt"에 저장된 쿠키 파일 내용입니다.
mycookie
Array
www.safety.katri/exam2/cookie/
0
2298062848
34459487
537668192
29397773
*
첫번째 줄의 mycookie가 쿠키명이고, Array가 쿠키값입니다. 각 배열요소값은 저장되지 않고 setcookie("mycookie", $mycook, time()+3600)를 이용해 쿠키를 만들 때 값으로 지정된 배열변수 $mycook의 변수형만 쿠키파일에 저장되는 것을 볼 수 있습니다. 그러면 쿠키를 서버에서 클라이언트로 보낼 때 배열요소값은 생략하고 변수형 "Array"라는 문자열만 보낸 것이 아닐까요? 서버에서 클라이언트로 쿠키를 보낼 때 쿠키정보를 응답헤더에 첨부해서 보낸다는 것은 앞장에서 살펴보았습니다. 그래서 실제로 어떤 정보를 응답헤더에 첨부해서 클라이언트로 보내는지 확인하기 위해 응답헤더를 직접 확인하였습니다. 아래는 위의 소스를 실행할 때 발생하는 응답헤더를 모니터링한 것입니다.
http/1.1 200 ok:
date: Tue, 06 Feb 2001 12:57:21 GMT
server: Apache/1.3.14 (Unix) PHP/4.0.3pl1 PHP/3.0.14
x-powered-by: PHP/3.0.14
set-cookie: mycookie=Array; expires=Tuesday, 06-Feb-01 13:57:21 GMT
connection: close
content-type: text/html
위의 응답헤더를 보면 알겠지만 클라이언트로 보내는 쿠키정보에는 $mycook 변수형만 첨부되어 있지 배열요소는 클라이언트로 보내지 않는다는 것을 알 수 있습니다. 이를 다시 확인하기 위해 브라우저에서 서버로 보내지는 환경변수 "HTTP_COOKIE"를 확인하여 보겠습니다. 브라우저에 있는 쿠키 정보는 요구헤더를 통해 웹서버로 전달되며 웹서버가 요구헤더를 이용하여 환경변수 "HTTP_COOKIE"를 설정하도록 되어 있습니다. 요구헤더에 포함된 쿠키정보의 구조에 대하여는 앞장에서 살펴보았습니다.
[code php;gutter:false] <?php

if (!isset($mycookie)) {
$mycook = array("mycook1"
, "mycook2"
, "mycook3"
, "mycook4"
, "mycook5"
, "mycook6"
, "mycook7"
, "mycook8"
, "mycook9"
, "mycook10"
, "mycook11"
, "mycook12"
, "mycook13"
, "mycook14"
, "mycook15"
, "mycook16"
, "mycook17"
, "mycook18"
, "mycook19"
, "mycook20"
, "mycook21"
, "mycook22"
, "mycook23"
, "mycook24"
, "mycook25"
);

setcookie("mycookie", $mycook, time()+3600);
die("<META http-equiv='Refresh' content='0; URL=$PHP_SELF'>");
} else {
setcookie("mycookie", "", time()-3600*24*365);
if (is_array($mycookie))
while (list($name,$value)=each($mycookie))
echo "$name=$value\n";
else
echo "ENV=[".getenv("HTTP_COOKIE")."]\n";
}

?> [/code]
위 소스의 실행 결과는 다음과 같습니다. 실행 결과를 보면 알겠지만 환경변수 "HTTP_COOKIE"를 통해 전달되는 쿠키정보는 "mycookie=Array"이 전부입니다. 결국 배열 $mycook의 값을 쿠키로 굽더라도 브라우저에 저장된 쿠키값은 배열요소 전부가 아니라 변수형 "Array"만 쿠키파일에 저장된다는 것을 알 수 있습니다.
ENV=[mycookie=Array]
이러한 현상은 setcookie() 함수 대신에 아래와 같이 직접 header() 함수를 이용할 때도 동일하게 나타납니다.
[code php;gutter:false] $expires = gmdate("D, j-M-Y H:i:s", time() + 3600)." GMT";
header("Set-Cookie: mycookie=$mycook; expires=$expires"); [/code]
쿠키정보를 브라우저로 보내려면 setcookie() 함수를 이용하지만 PHP 스크립터 내부에서는 최종적으로 php3_header() 함수를 통해 응답헤더의 일부로 쿠키정보를 브라우저에 전달합니다. 아래는 PHP3.0.14 소스파일 head.c에 있는 아파치 웹서버에 대한 php3_header() 함수를 요약한 것입니다.
[code c;gutter:false] /*
소스 파일 위치 : ......\php-3.0.14\functions\head.c
*/

PHPAPI int php3_header(void)
{
......(중간생략)......

cookie = php3_PopCookieList();
while (cookie) {
if (cookie->name)
len += strlen(cookie->name);
if (cookie->value) {
cookievalue = _php3_urlencode(cookie->value, strlen (cookie->value));
len += strlen(cookievalue);
}

......(중간생략)......

tempstr = emalloc(len + 100);
if (!cookie->value || (cookie->value && !*cookie->value)) {

......(중간생략)......

} else {
/* FIXME: XXX: this is not binary data safe */
sprintf(tempstr, "%s=%s", cookie->name, cookie->value ? cookievalue : "");
if (cookie->name) efree(cookie->name);
if (cookie->value) efree(cookie->value);
if (cookievalue) efree(cookievalue);
cookie->name=null;
cookie->value=null;
cookievalue=null;
if (cookie->expires > 0) {
strcat(tempstr, "; expires=");
dt = php3_std_date(cookie->expires);
strcat(tempstr, dt);
efree(dt);
}
}
if (cookie->path && strlen(cookie->path)) {
strcat(tempstr, "; path=");
strcat(tempstr, cookie->path);
efree(cookie->path);
cookie->path=null;
}
if (cookie->domain && strlen(cookie->domain)) {
strcat(tempstr, "; domain=");
strcat(tempstr, cookie->domain);
efree(cookie->domain);
cookie->domain=null;
}
if (cookie->secure) {
strcat(tempstr, "; secure");
}
table_add(GLOBAL(php3_rqst)->headers_out, "Set-Cookie", tempstr);
if (cookie->domain) efree(cookie->domain);
if (cookie->path) efree(cookie->path);
if (cookie->name) efree(cookie->name);
if (cookie->value) efree(cookie->value);
if (cookievalue) efree(cookievalue);
efree(cookie);
cookie = php3_PopCookieList();
efree(tempstr);
}
GLOBAL(php3_HeaderPrinted) = 1;
GLOBAL(header_called) = 1;
send_http_header(GLOBAL(php3_rqst));

......(중간생략)......

}

......(중간생략)......

GLOBAL(header_is_being_sent) = 0;
return(1);
} [/code]
위 함수에는 응답헤더에 포함되는 쿠키 정보 문자열 "set-cookie: mycookie=Array; expires=Tuesday, 06-Feb-01 13:57:21 GMT"을 만드는 과정이 나와 있고 최종적으로는 모든 작성된 쿠키 정보 문자열들을 브라우저로 전송(함수 send_http_header)하는 것으로 함수가 종료됩니다. 함수를 분석해 보면 _php3_urlencode(cookie->value, strlen (cookie->value))에 의해 배열에 대한 쿠키값이 "Array"로 변환되는 것을 볼 수 있고 배열요소가 쿠키 정보 문자열에 포함되지 않는다는 것을 알 수 있습니다. 여기에서 배열요소는 모두 사라지게 되는 것입니다.
하나의 쿠키에 배열을 담기 위한 노력
배열요소가 20개 이상 존재한다면 그대로 쿠키로 저장할 수는 없습니다. 이때는 배열을 직렬화(serialize)하여 하나의 문자열로 만든 다음 이 문자열을 쿠키로 만드는 것입니다. 쿠키를 읽어 들일 때는 반대로 문자열을 원래의 배열로 만들기 위해 unserialize 하는 것입니다. 이러한 방법은 세션함수에서 이용하는 방법으로 가장 신뢰성있는 방법입니다.
[code php;gutter:false] <?php

if (!isset($mycookie)) {
$mycook = array("mycook1"
, "mycook2"
, "mycook3"
, "mycook4"
, "mycook5"
, "mycook6"
, "mycook7"
, "mycook8"
, "mycook9"
, "mycook10"
, "mycook11"
, "mycook12"
, "mycook13"
, "mycook14"
, "mycook15"
, "mycook16"
, "mycook17"
, "mycook18"
, "mycook19"
, "mycook20"
, "mycook21"
, "mycook22"
, "mycook23"
, "mycook24"
, "mycook25"
);

$value = serialize($mycook);
setcookie(
"mycookie",
get_magic_quotes_gpc() ? $value : addslashes($value),
time+3600
);
die("<META http-equiv='Refresh' content='0; URL=$PHP_SELF'>");
} else {
setcookie("mycookie", "", time()-3600*24*365);
$mycook = unserialize(stripslashes($mycookie));
if (is_array($mycook))
while (list($name,$value)=each($mycook))
echo "$name=$value\n";
else
echo "ENV=[".getenv("HTTP_COOKIE")."]\n";
}

?> [/code]
위에서 get_magic_quotes_gpc()를 이용하는 부분이 있을 것입니다. php.ini 설정 파일에 있는 옵션 magic_quotes_gpc의 설정상태에 따라 적절히 처리해 주지 않으면 저장된 쿠키를 제대로 읽을 수가 없습니다. 제가 공개한 세셔너 또는 쿠키 관련 자료들이 제대로 동작하지 않는다면 이 부분을 의심해 보아야 합니다. 제가 실험한 웹서버의 환경에서는 magic_quotes_gpc의 값이 ON으로 설정되어 있기 때문에 저장된 값에는 '(single-quote), "(double-quote), \(backslash), 널(NUL) 들의 앞에 백슬래시가 자동으로 붙게 됩니다. 따라서 이러한 경우에는 쿠키를 읽을 때 반드시 stripslashes() 함수를 이용하여 자동으로 붙은 백슬래시를 제거해야 합니다. 그런데 여러분의 웹서버 환경에서 magic_quotes_gpc의 값이 OFF로 되어 있다면 제가 공개한 자료들이 실행에 문제가 생길 수 있습니다. 단순한 숫자나 영문자로 구성된 쿠키값일 때는 관계없으나 serialize() 함수로 직렬화된 문자열의 경우는 꼭 문제가 생기지요. get_magic_quotes_gpc() 부분을 삽입한 것은 웹서버의 설정상태에 관계없이 동작시키기 위해 작성된 것이니 참조바랍니다.
위 소스의 실행 결과는 다음과 같습니다. 이제야 제대로 배열이 저장되는 것 같네요.
0=mycook1
1=mycook2
2=mycook3
3=mycook4
4=mycook5
5=mycook6
6=mycook7
7=mycook8
8=mycook9
9=mycook10
10=mycook11
11=mycook12
12=mycook13
13=mycook14
14=mycook15
15=mycook16
16=mycook17
17=mycook18
18=mycook19
19=mycook20
20=mycook21
21=mycook22
22=mycook23
23=mycook24
24=mycook25
쿠키 사용을 위한 PHP 설치 옵션
쿠키로부터 전달받은 값이 서버 설치 옵션에 따라 전역변수로 받을 수도 있고 전역배열변수 $HTTP_COOKIE_VARS[]로 받을 수도 있습니다.
그런데 $HTTP_COOKIE_VARS[]을 언제나 사용할 수 있는 것은 아니고, PHP를 서버에 설치할 때 지정한 옵션에 따라 달라지지요. $HTTP_COOKIE_VARS[]와 관련된 서버 세팅은 두가지입니다. 하나는 소스 컴파일할 때 "--enable-track-vars"라는 설정옵션을 지정하여야 합니다. 두번째는 "--enable-track-vars"를 지정하여 소스 컴파일을 하더라도 php.ini 파일에 있는 track_vars 지시자에 의해 $HTTP_COOKIE_VARS[]를 Enable 할 수도 있고 Disable 할 수도 있습니다. 아래와 같이 track_vars 지시자를 Enable 하십시요.
php.ini의 내용중
================

track_vars = On ; enable the $HTTP_*_VARS[] arrays, where * is one of
; ENV, POST, GET, COOKIE or SERVER.
만약 여러분의 서버가 "--enable-track-vars"를 지정하여 소스 컴파일되어 있지 않다면 PHP_COOKIE_VARS를 사용하시기 전에 문서 최상단에 아래와 같이 php_track_vars 지시자를 사용하세요.
[code php;gutter:false] <?php_track_vars?>
<?php
.
.
.
?> [/code]
주의할 점은 php_track_vars 지시자가 PHP3에서만 제대로 동작되며, PHP4부터는 php_track_vars 지시자를 사용하지 않습니다. PHP4에서 track_vars 의 설정값이 "1"일 때에 php_track_vars 지시자를 사용하게 되면 아래와 같은 에러가 발생합니다.
Warning: <?php_track_vars?> is no longer supported
- please use the track_vars INI directive instead in ...... on line ???
PHP 4.0.3부터는 track_vars가 자동적으로 (항상) ON 상태입니다. 따라서 PHP 4.0.3부터는 php.ini의 track_vars의 설정 상태에 관계없이 php_track_vars 지시자를 사용하면 무조건 위와 같은 에러가 발생합니다.
PHP의 변수이름은 알파뉴머릭과 밑줄로만 이루어져 있습니다. 만약 쿠키명에 유효하지 않은 문자들이 포함되어 있다면 유효하지 낳은 문자들은 밑줄(_)로 변환됩니다. 예를 들어, 쿠키명 "in%va.lid_"는 "in_va_lid_"로 변환됩니다.
$HTTP_COOKIE_VARS[]를 사용하여야 할 이유는?
$HTTP_COOKIE_VARS["username"] 대신에 전역변수 $username를 사용하여도 동작결과는 동일합니다. 그러면 언제 $HTTP_COOKIE_VARS[]을 사용하여야 할까요? 이전페이지에서 세션값, GET, POST, 쿠키로 넘어 오는 모든 값은 전역변수로 넘어올 수도 있고 $HTTP_SESSION_VARS[], $HTTP_GET_VARS[], $HTTP_POST_VARS[], $HTTP_COOKIE_VARS[]와 같은 전역 배열 변수로도 넘어오지요. 여기서 보았듯이 배열로 넘어오는 값들은 각 요소(세션, GET, POST, 쿠키)마다 서로 다른 배열변수에 담겨오기 때문에 배열변수가 무엇이냐에 따라 넘어온 값이 어떠한 성격을 가지고 있는지 파악할 수 있습니다. 그러나 전역변수로 넘어온 값은 전역변수명만을 가지고는 그 값이 세션값이었는지, HTTP GET 방식으로 넘어왔는지, HTTP POST 방식으로 넘어왔는지, 쿠키값이었는지가 구분이 되지 않습니다. 사용상의 편이성만으로만 보면 전역변수를 사용하는 것이 좋겠지요. 그러나 보안이라는 측면에서 보면 넘어온 값의 성격을 구분하지 못할 때는 문제가 발생할 수 있습니다. 예를 들어 앞장(home.php)에서 아래와 같이 HTTP POST 방식으로 userid와 passwd값을 입력받아 서브밋하였습니다.
[code php;gutter:false] <FORM name=getID method="post" action="login_process.php">
<P>사용자ID : <INPUT type="text" name="login_userid" size="15"></P>
<P>비밀번호 : <INPUT type="password" name="login_passwd" size="15"></P>
</FORM> [/code]
이 값을 다음 장(login_process.php)에서 받았을 때 $HTTP_POST_VARS[] 배열을 사용하지 않고 전역변수 $login_userid, $login_passwd를 직접 사용한다면 이 값이 꼭 앞장 양식에서 입력되어 들어온다는 보장이 없습니다. 누군가가 부당한 목적을 위해 앞장을 통하지 않고 아래와 같이 URL 파라미터로 값을 입력할 수도 있지요.
login_process.php?login_userid=user3&login_passwd=test
위와 같이 URL 파라미터로 login_process.php 페이지로 $login_userid, $login_passwd 값을 전달할 수 있지요.
아래와 같은 세션값도 마찬가지입니다. $access_userid 값과 $access_userid 값은 login_process.php 페이지에서 home.php 페이지로 세션을 통해 비밀스럽게(?) 전달되어 인증처리를 하여야 하는데 역시 누군가가 부당한 목적을 위해 세션을 통하지 않고 URL 파라미터를 통해 $access_userid 값과 $access_userid 값을 home.php 페이지로 전달할 수 있지요.
이것을 방지하기 위해 각 요소(세션, GET, POST, 쿠키)마다 배당된 다른 배열변수를 이용해 전역변수를 덮어쓰기하는 것입니다.
보안상 신경쓰지 않아도 되는 전역변수 값이야 이렇게 할 필요가 없으나 인증에 필요한 값들은 불편하더라도 이같은 코딩 습관에 익숙하시는 것이 바람직합니다.
공개 소스 중에는 이렇게까지 하지 않는 경우도 많이 있으나 여러분이 이러한 면에도 관심을 가져주었으면 해서 때에 따라서는 불필요할 지도 모르지만 코드를 일부로 포함시켰습니다.
쿠키 삭제하기
쿠키는 보통 setcookie() 함수의 첫번째 매개변수만으로 삭제할 수 있습니다.
[code php;gutter:false] setcookie("mycookie"); [/code]
그러나 때에 따라서는 첫번째 매개변수만 지정할 경우 해당 쿠키가 삭제되지 않는 경우를 볼 수 있습니다. 이것은 쿠키를 설정할 때 유효도메인, 유효경로를 지정한 경우가 대부분입니다. 이와 같은 경우에는 쿠키 설정할 때 지정된 유효도메인과 유효경로를 삭제시에도 지정하여야 합니다.
[code php;gutter:false] setcookie("mycookie", "cookie_value", 0, "/exam", ".phpclass.com"); [/code]
예를 들어 쿠키 설정할 때 위와 같이 지정하였다면, 쿠키 삭제할때는 아래와 같이 지정하여야 합니다. 삭제할 때 유효기간 설정값은 예를 들은 것 뿐이며 적절한 과거 시점을 지정하면 됩니다.
[code php;gutter:false] setcookie("mycookie", "", time()-31536001, "/exam", ".phpclass.com"); [/code]
현재 설정된 쿠키 변수들에는 영향을 미치지 않으며, 또한 $HTTP_COOKIE_VARS[]도 변경시키지 않는다.

 

쿠키의 생성, 참조, 삭제되는 시점
setcookie() 함수로 쿠키를 생성하거나 삭제하더라도 새로운 HTTP 요구(require)가 없으면 이 쿠키에 대한 정보가 쿠키용 전역변수 또는 전역배열변수 $HTTP_COOKIE_VARS[]에 적용되지 않습니다. 이러한 setcookie() 함수의 동작원리를 잘 이해하고 있어야 합니다. 따라서 위에서와 같이 setcookie("mycookie")를 통해 쿠키를 삭제하더라도 현재 설정된 쿠키 전역변수와 전역배열변수 $HTTP_COOKIE_VARS[]의 내용은 계속 유지됩니다. setcookie() 함수를 통해 쿠키를 생성하면 이 값은 로컬시스템(사용자 하드드라이브)에 저장되었다가 다음 페이지를 읽을 때 쿠키정보를 서버로 보내게 됩니다. 서버는 이 쿠키정보를 이용하여 전역변수값으로 설정해 주지요.
setcookie() 함수 사용시 발생하는 에러
setcookie() 함수를 사용하는 데 주의 할 점이 있습니다. setcookie() 함수는 일반적인 HTML 태그 또는 PHP로부터 보내지는 실제의 출력 이전에 호출되어야 합니다. setcookie() 함수를 호출하기 전에 include() 또는 auto_prepend를 통하여 코드를 읽어들일 수 있는데 이러한 코드에 브라우저로 출력되는 스페이스 또는 빈줄이 있으면 에러가 발생합니다. 이 에러에 대한 것은 제 홈페이지의 Q&A 게시판에서 언급되어 있으며, 메뉴 "후키라이브러리 >> 캐시리미터 >> 헤더 관련 PHP 함수" 의 header() 함수에서도 언급되어 있으니 참조바랍니다. 아래는 이 때 PHP3 및 PHP4에서 발생하는 에러메시지입니다.
PHP3일 때
=========
Warning: Oops, php3_SetCookie called after header has been sent
in /home/....../test.php3 on line ???

PHP4일 때
=========
Warning: Cannot add header information - headers already sent by
(output started at /home/....../test.php:3)
in /home/....../test.php on line ???
setcookie() 함수 호출 순서
PHP3에서의 실험
PHP는 쿠키들을 PHP 스크립트에 있는 setcookie() 호출들의 순서와 역순으로 서버로 전달합니다. 앞에서 배열요소를 쿠키에 저장할 때도 확인하였습니다. 어떻게 해서 이런 현상이 발생하였을까요? 이를 확인하기 위해 다시 소스코드를 분석해 보겠습니다. 아래는 PHP3.0.14 소스파일 head.c에 있는 아파치 웹서버에 대한 php3_header() 함수 및 _php3_SetCookie() 함수를 요약한 것입니다. head.c 파일은 PHP3.0.14 소스파일의 압축을 풀면 php-3.0.14\functions\head.c에 있습니다.
[code c;gutter:false] void _php3_SetCookie(char * name, char * value, time_t expires
, char * path, char * domain, int secure)
{
......(중간생략)......

if (name) name = estrdup(name);
if (value) value = estrdup(value);
if (path) path = estrdup(path);
if (domain) domain = estrdup(domain);
php3_PushCookieList(name, value, expires, path, domain, secure);
} [/code]
SetCookie() 함수는 내부적으로 결국 _php3_SetCookie() 함수를 실행하게 되어있는데 이 함수가 하는 일이라고는 단지 쿠키 설정 정보들을 CookieList라는 스택 자료 구조에 저장(Push)하는 것 뿐입니다.
[code c;gutter:false] PHPAPI int php3_header(void)
{

......(중간생략)......

cookie = php3_PopCookieList(); //<-- 스택으로부터 데이터를 가져음
while (cookie) {

......(중간생략)......

cookie = php3_PopCookieList(); //<-- 스택으로부터 데이터를 가져옴
efree(tempstr);
}
......(중간생략)......

send_http_header(GLOBAL(php3_rqst)); //<-- 응답헤더 전송

......(중간생략)......

return(1);
} [/code]
응답헤더를 통해 보낼 정보(쿠키정보 포함)가 다 모아지면 php3_header() 함수를 실행하게 됩니다. 이 함수를 살펴보면 위에서와 같이 SetCookie() 함수를 통해 스택 CookieList에 모아진 자료를 하나씩 차례로 불러와 헤더 정보에 추가하는 것을 알 수 있습니다.
자료구조론을 읽어보신 분은 이미 이해하셨겠지만 CookieList가 스택구조다 보니 저장(Push)될 때와 반대의 순서로 읽어(Pop) 들인다는 것(후입선출구조)입니다. 그러니 응답헤더에 포함되는 순서가 SetCookie() 함수 실행순서와 뒤바뀌게 되고 결국 쿠키가 구워지는 순서가 뒤바뀌게 되는 것이지요.
제가 공개하는 쿠커(Cooker)와 같이 때에 따라서는 이 순서가 바뀌면 안돼는 웹애플리케이션도 필요할 것입니다. 이러한 경우는 어떻게 해야 할까요. 해결방법은 두가지, 자바스크립트를 이용하던가 아니면 header() 함수를 이용하시면 됩니다. 쿠커에서는 이 문제때문에 setcookie() 함수 대신에 header() 함수를 이용하였습니다.
setcookier() 호출 순서와 역순으로 브라우저에서 쿠키가 생성되거나 삭제되기 때문에 만약 동일한 이름을 가진 쿠키를 삭제하고 새롭게 다른 값으로 설정하기를 원한다면 setcookie()로 새로운 쿠키를 먼저 설정한 다음, 나중에 다시 setcookie()를 호출하여 예전의 쿠키를 삭제해야 합니다.
[code php;gutter:false] <?php
// 새로운 쿠키를 설정
setcookie("mycookie", "cookie_value");
// 예전의 쿠키를 삭제
setcookie("mycookie");
?> [/code]
PHP4에서의 실험
실험까지는 하지 않았고 PHP4 메뉴얼에 의하면 setcookie() 함수 호출 순서와 서버로 전달되는 순서가 같게 변경되었습니다. 제 개인 생각으로도 PHP4에서의 방법이 옳지 않나 생각합니다. 뒤에서 언급된 쿠키정보클래스 "쿠커(Cooker)에서도 이 호출순서와 서버로 전달되는 순서가 역순이라 setcookie() 함수를 사용할 수가 없었습니다. 그래서 setcookie() 함수 대신에 header() 함수를 직접 이용하게 되었지요. 쿠커를 작성할 때 PHP4에서는 setcookie() 함수를 사용해도 되겠지만 PHP3와의 호환성을 위해 setcookie() 함수를 사용하지 않았습니다.

'phpsource > 캐시&세션&쿠키' 카테고리의 다른 글

{쿠커}9.쿠커  (0) 2001.02.20
{쿠커}8.document.cookie 객체  (0) 2001.02.20
{쿠커}6.쿠키 다루기  (0) 2001.02.20
{쿠커}5.쿠키 규격  (0) 2001.02.20
{쿠커}4.브라우저 설정  (0) 2001.02.20
Posted by 방글24
쿠키 생성 및 접근
쿠키를 생성하기 위해서는 웹 서버가 앞장에서 다룬 쿠키 규격에 맞게 "Set-Cookie" HTTP 헤더 정보를 보내면 됩니다. 즉 HTTP 헤더를 생성하는 CGI를 작성하면 원하는 내용을 쿠키에 입력하는 것이 가능합니다. 클라이언트에 저장된 쿠키를 꺼내기 위해서는 클라이언트가 정보요청을 할 때(즉 CGI을 불렀을 때) 함께 넘어오는 환경변수 HTTP-COOKIE에 저장되어 있는 정보를 추출하여 사용하면 됩니다. PHP 또는 자바스크립트에서는 이러한 작업을 아주 쉽게 할 수 있는 방법을 제시합니다. 물론 C언어와 같은 다른 수단을 사용하더라도 쿠키 규격을 만족하도록 HTTP 헤더 또는 환경변수를 다루면 되지만 PHP 또는 자바스크립트보다는 좀 다루기가 쉽지 않을 것입니다.
여기서는 PHP와 자바스크립트를 이용하여 쿠키를 다루는 방법에 대하여 기술할 것입니다. 자세한 것은 다음 장 "setcookie() 함수" 및 "document.cookie 객체"를 참조바랍니다.
PHP
쿠키를 생성하기 위한 함수로 SetCookie() 함수를 제공하며, 클라이언트에서 전달된 쿠키는 쿠키명에 해당하는 전역변수를 가지고 다루거나 아니면 $HTTP_COOKIE_VARS[]라는 전역배열변수를 가지고 다룰 수 있습니다.
[code php;gutter:false] <?php

if (!isset($mycookie)) {
setcookie("mycookie", "cookie_value", time+3600);
die("<META http-equiv='Refresh' content='0; URL=$PHP_SELF'>");
} else {
echo "$mycookie<BR>\n";
}

?> [/code]
자바스크립트
document.cookie 객체는 쿠키의 모든 이름과 값을 가지고 있고, 자바스크립트에서 이 속성(property)을 이용할 수 있습니다. 사용자들은 아래와 같이 document.cookie를 마치 문자열 변수처럼 취급하여 쉽게 쿠키의 정보를 제어할 수 있습니다.
[code javascript;gutter:false] document.cookie = "ID=" + escape("123456789")
+ "; expires=Thu, 01-Jan-70 00:00:01 GMT"
+ "; path=/exam"
+ "; doamin=.phpclass.com"
+ "; secure"; [/code]

'phpsource > 캐시&세션&쿠키' 카테고리의 다른 글

{쿠커}8.document.cookie 객체  (0) 2001.02.20
{쿠커}7.setcookie() 함수  (0) 2001.02.20
{쿠커}5.쿠키 규격  (0) 2001.02.20
{쿠커}4.브라우저 설정  (0) 2001.02.20
{쿠커}3.보안  (0) 2001.02.20
Posted by 방글24