phpsource/템플릿2003. 4. 30. 09:37
written: Jan 28 2002
last modified: Apr 04 2003
템플릿 파일 기본 디렉토리(template roots)
$tpl = new hTemplate(path-to-templates)
객체 생성할 때 생성자에는 템플릿이 저장되어 있는 디렉토리를 지정하여 줍니다. 생략하면 현 PHP 문서의 디렉토리에 템플릿이 있는 것으로 간주됩니다.
템플릿 파일이 저장된 기본 디렉토리는 아래의 예와 같이 생성자의 첫 번재 인수를 통해 지정할 수 있습니다.
[code php;gutter:false] $tpl = new hTemplate('./templates'); [/code]
템플릿 파일 기본 디렉토리의 다중화(multi template roots)
위와 같이 단 하나의 기본 디렉토리를 지정할 수도 있습니다만 1.0.0 버전부터는 배열을 이용하여 하나 이상의 기본 기렉토리를 동시에 설정할 수도 있습니다.
[code php;gutter:false] $tpl = new hTemplate ( array( 'templates', 'templates/sub', '../up/templates' ) ); [/code]
기본 디렉토리가 여러 개 지정되었을 때는 먼저 지정된 디렉토리부터 템플릿 파일을 찾게 됩니다. 즉, 위의 예에서는 먼저 "templates"에서 템플릿 파일을 찾게 되며 만약 이 디렉토리에 원하는 템플릿 파일이 없으면 "templates/sub" 디렉토리에서 찾게 되며 이 디렉토리에도 원하는 템플릿 파일이 없으면 마지막으로 "../up/templates" 디렉토리에서 템플릿 파일을 찾게 됩니다. 이곳에서 조차 원하는 템플릿 파일을 찾지 못한다면 에러가 발생하지요.

Posted by 방글24
파일시스템용, 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
phpsource/파일분석2002. 9. 16. 16:51
2002.9.16 - 0.0.1 패치1
  • get_head() 함수 수정
2002.9.9 - 0.0.1
  • 첫 배포판

'phpsource > 파일분석' 카테고리의 다른 글

{INI 파일}2.INI 핸들러  (0) 2003.06.25
{INI 파일}1.개요  (0) 2003.06.25
{TAR 파일}7.클래스  (0) 2002.09.09
{TAR 파일}6.zlib를 이용한 압축  (0) 2002.09.09
{TAR 파일}5.후미에 붙여지는 블록  (0) 2002.09.09
Posted by 방글24
phpsource/파일분석2002. 9. 9. 16:48
여기서 공개하는 hTarFile 클래스는 바로 TAR 아카이브를 생성하거나 또는 풀 수 있도록 작성된 소스이며 PHP에 내장되어 제공되고 있는 zlib 라이브러리(gz로 시작하는 함수들)를 이용하여 압축할 수 있도록 하였습니다.
hTarFile 클래스 0.0.1 버전 설계의 기본 컨셉은 기존의 유닉스 tar 유틸리티의 사용법만 알면 별문제없이 사용하도록 하겠다는 것입니다. 따라서 이미 tar 유틸리티를 사용할 줄 아는 유닉스 사용자라면 별 어려움없이 hTarFile 클래스를 이용할 수 있으리라 생각합니다.
객체 생성 및 생성자
[code php;gutter:false] require_once("class.hTarFile.php");
$my = & new hTarFile; [/code]
public 메소드
void root(string path-to-files);
root 메소드로 지정하는 path-to-files 인자는 묶고자 하는 파일들의 기본 디렉토리를 의미합니다. 클래스 내의 모든 메소드는 이 기본 디렉토리를 베이스로 처리하기 때문에 매우 중요합니다. 지정하지 않으면 null로 처리되므로 TAR 아카이브를 다루어주는 tar 메소드에서 디렉토리를 완벽하게 지정하여야 합니다.
또 한가지 중요한 것은 여기서 지정되는 path-to-files는 hTarFile 클래스를 이용하기 전에 먼저 해당 서버의 쉘 명령을 이용하여 생성시켜야 하며 TAR 아카이브 또는 tar.gz 파일이 기록되는 디렉토리는 반드시 디렉토리 내에 파일을 기록할 수 있도록 퍼미션을 조정하셔야 합니다. 가장 쉬운 방법은 퍼미션을 777로 설정하는 것이지요. 물론 윈도우 서버에서는 퍼미션 대신에 "읽기전용"으로만 해놓지 않으면 됩니다.
이와 같이 생성 또는 추출하고자 하는 TAR 아카이브 및 TAR 아카이브에 속할/속한 멤버파일들의 기본 디렉토리를 root 메소드로 지정합니다. 일단 root 메소드로 디렉토리가 지정된 후에는 tar 메소드에서는 이 기본 디렉토리를 기준으로하여 상대디렉토리가 지정됩니다.
[code php;gutter:false] $my->root("/tmp/hFiles");
$my->tar("cfz sample.tar.gz s1.txt"); [/code]
묶고자 하는 파일 s1.txt는 /tmp/hFiles 에 있으며, 또한 생성하고자 하는 sample.tar.gz 파일도 /tmp/hFiles 에 생성됩니다. 만약 root 메소드에 지정된 디렉토리가 절대디렉토리가 아니라 상대디렉토리로 지정하였다면 기준이 되는 디렉토리는 현재 실행중인 문서가 있는 디렉토리가 됩니다.
int tar (string options, string tar_filename, string files or dirs)
[code php;gutter:false] $my->tar("cfz sample.tar.gz s1.txt s2.txt s3.txt subdir1 subdir2"); [/code]
사용법은 리눅스에서 제공되는 tar 유틸리티와 거의 유사합니다. tar 유틸리티와 다른 점은 옵션 앞에 붙게 되는 -(minus) 부호가 생략되었다는 것입니다. 다른 것은 동일합니다. 물론 기능적인 것으로 보면 tar 유틸리티가 제공하는 모든 기능을 제공하지는 않으며 그 중에 꼭 필요한 옵션만 제공합니다. 또한 tar 유틸리티에서는 x 옵션을 주었을 때 TAR 아카이브 파일명 뒤에 파일명이나 디렉토리명을 지정하면 해당 파일 또는 디렉토리의 내용만 추출하게 됩니다. 그러나 hTarFile 클래스에서는 파일이나 디렉토리명을 지정하더라도 이를 무시하고 전체를 추출하도록 되어 있습니다. 이 부분은 향후 업그레이드하면서 업하도록 노력하겠습니다.
TAR 아카이브 생성이나 추출에 성공하면 멤버파일 리스트를 되돌려 주며 실패하면 false 값이 되돌려 줍니다.
[code php;gutter:false] require_once("class.hTarFile.php");
$my = & new hTarFile;

$my->root("/tmp/ext");

if (!$files=$my->tar("xfz sample.tar.gz")) {
die("unable to extract TAR archive");
} else {
printf("<P>TAR archive was successfully extracted!</P>\n");

foreach ($files as $file) {
printf("%s<BR>\n", $file);
}
} [/code]
1) TAR 아카이브로 묶기
리눅스의 tar 유틸리티에서 여러 개의 파일을 TAR 아카이브로 묶기 위해서는 아래와 같이 하게 되지요.
tar -cf  tar-file file | dir ......
예를 들면
tar -cf sample.tar s1.txt s2.txt sub1 sub2
이 명령을 수행하면 s1.txt, s2.txt 파일과 sub1, sub2 디렉토리에 있는 모든 파일을 하나의 파일 sample.tar에 묶어 버리지요. 이를 hTarFile 클래스의 메소드 tar를 이용한다면 아래와 같습니다.
[code php;gutter:false] $my->root("/hwooky");
$my->tar("cf sample.tar s1.txt s2.txt sub1 sub2"); [/code]
이 문장들을 수행하게 되면 "/hwooky" 디렉토리에 있는 s1.txt, s2.txt와 /hwooky/sub1, /hwooky/sub2 디렉토리에 있는 모든 파일을 sample.tar 아카이브 파일로 묶게 됩니다.
2) TAR 아카이브을 풀기
리눅스의 tar 유틸리티에서 TAR 아카이브를 여러 개의 파일로 풀기 위해서는 아래와 같이 하게 되지요.
tar -xf  tar-file
예를 들면
tar -xf sample.tar
이를 hTarFile 클래스의 메소드 tar를 이용한다면 아래와 같습니다.
[code php;gutter:false] $my->root("/tmp/hFiles/extract");
$my->tar("xf sample.tar"); [/code]
앞에서 설명하였듯이 이 메소드를 수행하기 전에 root 메소드에서 지정한 "/tmp/hFiles/extract" 디렉토리를 먼저 만들어주고 퍼미션을 쓰기가능하도록 (예를 들면 chmod 777) 설정하여야 제대로 파일을 풀어줄 수 있습니다.
3) tar.gz 파일로 압축하기
리눅스의 tar 유틸리티에서 여러개의 파일을 TAR 아카이브로 묶음과 동시에 자동적으로 gzip 명령으로 압축하기 위해서는 z 옵션을 추기하여야 합니다.
tar -cfz  tar-file file | dir ......
예를 들면
tar -cfz sample.tar.gz s1.txt s2.txt sub1 sub2
이 명령을 수행하면 s1.txt, s2.txt 파일과 sub1, sub2 디렉토리에 있는 모든 파일을 하나의 파일로 묶음과 동시에 gzip 형식으로 압축하여 sample.tar.gz 파일로 저장합니다. 이를 hTarFile 클래스의 메소드 tar를 이용한다면 아래와 같습니다.
[code php;gutter:false] $my->tar("cfz sample.tar.gz s1.txt s2.txt sub1 sub2"); [/code]
4) tar.gz 파일을 압축해제하기
리눅스의 tar 유틸리티에서 여러개의 파일을 TAR 아카이브로 묶음과 동시에 자동적으로 gzip 명령으로 압축하기 위해서는 z 옵션을 추기하여야 합니다.
tar -xfz  tar-file
예를 들면
tar -xfz sample.tar
이를 hTarFile 클래스의 메소드 tar를 이용한다면 아래와 같습니다.
[code php;gutter:false] $my->tar("xfz sample.tar"); [/code]
메소드 tar에서 지원하는 옵션
hTarFile 클래스의 메소드 tar에서 지원하는 옵션을 정리하면 아래와 같습니다.
< 지원하는 옵션 >
지원하는 옵션 기  능

c

TAR 아카이브 생성

f

TAR 아카이브 파일명 지정

x

TAR 아카이브 추출

z

TAR 아카이브를 압축 및 해제

이 옵션 중에서 f 옵션은 반드시 지정하여야 하고 z 옵션은 압축할 필요가 있을 때만 지정하면 됩니다. 나머지 c와 x 옵션은 둘 중에 하나만 선택하십시요. 묶으려면 c 옵션을 선택하고 풀려면 x 옵션을 선택하십시요.

'phpsource > 파일분석' 카테고리의 다른 글

{INI 파일}1.개요  (0) 2003.06.25
{TAR 파일}8.클래스 다운로드  (0) 2002.09.16
{TAR 파일}6.zlib를 이용한 압축  (0) 2002.09.09
{TAR 파일}5.후미에 붙여지는 블록  (0) 2002.09.09
{TAR 파일}4.본문 구조  (0) 2002.09.09
Posted by 방글24
phpsource/파일분석2002. 9. 9. 16:47
PHP에서 제공하는 함수에는 파일을 압축할 수 있는 zlib 라이브러리를 기본적으로 제공하고 있습니다.
압축하기
리눅스의 gzip 프로그램의 출력과 호환성을 유지하기 위해서는 zlib 라이브러리에서 제공하는 함수 중에서 gzencode 함수를 이용하여야 합니다. 이 함수에 의해 얻은 값은 gzip 프로그램의 출력값과 호환성을 가지므로 리눅스의 gzip 프로그램 또는 윈도우의 윈도우커맨더를 가지고 압축을 풀 수가 있습니다. 예를 들어 gzencode 함수를 이용하여 gz 파일을 생성해 주는 사용자 정의 함수를 작성하면 아래와 같습니다.
[code php;gutter:false] function gzcreate($gzfile, $contents) {
if (!$contents=gzencode($contents)) { // PHP4 >= 4.0.4
return false;
}

if (!$fp=fopen($gzfile, "wb")) {
return false;
}

fwrite($fp, $contents);
fclose($fp);

return true;
} [/code]
위 소스 중에 fopen 함수에서 mode 인수를 "wb"로 설정하였습니다. 유닉스에서는 이진(binary)을 의미하는 "b"를 사용하지 않더라도 정상적으로 파일을 처리해 줍니다. 그러나 윈도우에서는 이진 파일과 텍스트파일을 구분하여 저장하거나 읽지 않으면 저장된 파일을 정상적으로 다룰 수 없습니다. 가끔가다 자료실에 있는 이미지 파일이나 압축파일을 다운로드할 때 파일의 헤더부분만 읽어오므로 아무런 내용도 담기지 않은 파일이 다운로드될 때가 있습니다. 이럴 때는 해당 파일이 정확히 이진 모드로 다루어졌는지 확인하여야 합니다. 따라서 리눅스나 유닉스 계통에서는 별 문제가 없는데, 윈도우 서버에서 그런 문제가 발생할 수 있습니다. 따라서 윈도우에서 이미지 파일 또는 압축파일과 같이 바이너리 형태의 파일을 읽거나 쓸 때는 fopen 모드 인자에 반드시 "b" 옵션을 추가해야 정상적으로 다룰 수 있습니다. 유닉스에서는 "b" 옵션을 사용하지 않으며, 설사 "b" 옵션을 지정하더라도 그냥 무시해 버립니다.
압축해제하기
예를 들어 gzib 함수를 이용하여 압축된 파일을 풀기위해서는 대략 아래와 같이 사용자 정의 함수 gzextract 함수를 작성하면 될 것입니다.
[code php;gutter:false] function tarextract($gzfile) {
if (!$fp=fopen($gzfile, "rb")) {
return false;
}

$contents = fread($fp, filesize($gzfile));
fclose($fp);

if (!$contents=gzdecode($contents)) { // PHP4 >= 4.0.4
return false;
}

return $contents;
} [/code]
위의 코드가 제대로 실행될 것 같습니까? 아닙니다. 2002년 8월 31일 현재 PHP에서는 gzencode 함수만 제공할 뿐 gzdecode 함수를 제공하고 있지 않습니다. 그러나 http://www.php.net/manual/en/function.gzencode.php를 보시면 gzdecode 함수를 구현해 주는 팁이 공개되어 있습니다. 그 내용은 아래와 같습니다.
henryk@ploetzli.ch
14-Feb-2002 07:28

Well, I was looking for a gzdecode too and didn't consider the temporary file example above
to be very elegant.
However, as is noted in the very first comment: gzencode() only adds a 10 byte header.

I don't quite know what this header is supposed to be used for, but gzinflate() certainly
doesn't like it, so I stripped it off:

function my_gzdecode($string) {
$string = substr($string, 10);
return gzinflate($string);
}

That's useful to read HTTP-Connections that were compressed by mod_gzip.
--
Henryk Plotz
Gruße aus Berlin


tychay@alumni.caltech.edu
03-Apr-2002 03:53

The 10 byte string in gzencode is the standard gzip header. The first two bytes (1f 8b)
define the return as a gzip file, the third byte (08) means that the body is compressed using
the "deflate" algorithm. The rest is padding (00)'s.

Technically, I believe one should check if the third byte is hex 08 and if so strip off the
first ten bytes and last four bytes and run inflate on it. The last four bytes are file size
and checksum bits.

In practice, you can get away with just stripping the first 10 bytes and running inflate on
it.

Hope this helps,

terry
이 팁에 의해 gzdecode 함수를 작성하면 대략 아래와 같이 될 것입니다.
[code php;gutter:false] function gzdecode($data) {
if("\x1f\x8b\x08" == substr($data, 0, 3)) {
return gzinflate(substr($data, 10, -4)); // PHP4 >= 4.0.4
}
return false;
} [/code]
그런데 이렇게 작성된 gzdecode 함수도 그리 완벽하지는 않습니다. 위에서 설명한 gzencode 함수로 생성된 압축파일을 푸는데는 전혀 문제없이 동작합니다만 리눅스의 gzip 또는 윈도우의 윈도우커맨더, 알집 등으로 압축한 파일은 정상적으로 풀지를 못하네요. 즉, 팁에 의해 작성된 사용자 정의 함수 gzdecode는 리눅스의 gzip 프로그램의 출력과 완전한 호환성을 유지하지는 못하고 있습니다. 이러한 부분은 PHP에서 향후 공식적으로 gzdecode 함수를 제공하여야 가능할 것으로 보입니다. 아니면 좀더 개선된 팁이 공개되든가......

'phpsource > 파일분석' 카테고리의 다른 글

{TAR 파일}8.클래스 다운로드  (0) 2002.09.16
{TAR 파일}7.클래스  (0) 2002.09.09
{TAR 파일}5.후미에 붙여지는 블록  (0) 2002.09.09
{TAR 파일}4.본문 구조  (0) 2002.09.09
{TAR 파일}3.헤더 구조  (1) 2002.09.09
Posted by 방글24
phpsource/파일분석2002. 9. 9. 16:39
TAR 아카이브를 구성하는 멤버 파일 및 디렉토리에 관한 모든 정보(헤더 및 본문)가 다 기록된 후에는 마지막으로 파일 내용과 관계없이 null로 채워진 1블록 이상의 빈블록(empty block)들이 붙여지게 됩니다.
예를 들어 TAR 아카이브 파일의 마지막에 임의로 추가되는 빈블록을 덤프해 보면 아래와 같이 null 문자만으로 채워져 있음을 알 수 있습니다.
< TAR 아카이브 파일의 마지막에 임의로 추가되는 빈블록 구조 >

'phpsource > 파일분석' 카테고리의 다른 글

{TAR 파일}7.클래스  (0) 2002.09.09
{TAR 파일}6.zlib를 이용한 압축  (0) 2002.09.09
{TAR 파일}4.본문 구조  (0) 2002.09.09
{TAR 파일}3.헤더 구조  (1) 2002.09.09
{TAR 파일}2.아카이브 구조  (0) 2002.09.09
Posted by 방글24
phpsource/파일분석2002. 9. 9. 16:30
파일 헤더가 완성되었으면 뒤이어 파일 내용이 들어가게 됩니다. 파일 내용은 512 바이트의 배수로 기록됩니다. 만약 파일크기가 1바이트부터 512 바이트사이라면 1블록(512바이트)을 사용하고 513바이트부터 1024바이트까지는 2블록(1024바이트)을 사용하는 식입니다.
결국 TAR 아카이브에서의 파일 내용 부분이 차지하는 크기는 아래와 같은 식으로 구할 수 있습니다.
[code php;gutter:false] function calc_blocksize($realsize) {
return ceil($realsize / 512) * 512;
} [/code]
본문에서도 헤더 구조에서와 마찬가지로 채워지지 않은 빈 공간에 모두 null로 채워야 합니다.
파일크기가 0바이트인 파일인 경우에는 디렉토리인 경우와 마찬가지로 파일 헤더만 존재하며 본문은 기록되지 않습니다.
예를 들어 s1.txt 파일에 대한 본문 구조를 덤프해 보면 아래와 같습니다.
< s1.txt 파일에 대한 본문 구조 >

'phpsource > 파일분석' 카테고리의 다른 글

{TAR 파일}6.zlib를 이용한 압축  (0) 2002.09.09
{TAR 파일}5.후미에 붙여지는 블록  (0) 2002.09.09
{TAR 파일}3.헤더 구조  (1) 2002.09.09
{TAR 파일}2.아카이브 구조  (0) 2002.09.09
{TAR 파일}1.개요  (0) 2002.09.09
Posted by 방글24