phpsource/파일분석2002. 9. 9. 16:11
TAR 아카이브 포맷
TAR 아카이브의 포맷을 보면 이전의 유닉스 호환 포맷(UNIX-compatible formats)과 POSIX (IEEE P1003.1) 기준으로 새로이 정의된 USTAR 포맷(USTAR format)이 있습니다. 새로이 정의된 USTAR 포맷은 유닉스 호환 포맷보다 더 많은 정보를 저장할 수 있으며 더 긴 파일 패스명을 지원합니다. 그러나 어느 포맷이 되었든지 헤더는 512바이트 크기의 1블록으로 구성되어 있습니다.
우선 이전의 유닉스 호환 포맷에 의한 헤더 구조를 보면 아래와 같습니다.
< 유닉스 호환 포맷에 의한 헤더 구조 >
FIELD NAME OFFSET SIZE MEANING
name 0 100 name of file
mode 100 8 file mode
uid 108 8 owner user ID
gid 116 8 owner group ID
size 124 12 length of file in bytes
mtime 136 12 modify time of file
chksum 148 8 checksum for header
link 156 1 indicator for links
linkname 157 100 name of linked file
link 필드에는 링크 파일(linked file)이면 1, 심볼릭 링크(symbolic link) 이면 2, 기타일 때는 0이 기록됩니다. 디렉토리의 경우에는 링크명에 슬래시(/)가 붙게되지요.
새로운 USTAR 포맷에 의한 헤더 구조는 아래와 같습니다. magic 필드에는 null 문자로 종료되는 문자열 "ustra"이 기록되며 magic 필드 이전의 모든 필드는 typeflag 필드를 제외하고는 모두 이전의 유닉스 호환 포맷과 동일합니다. 유닉스 호환 포맷에서의 link 필드가 USTAR 포맷에서는 typeflag 필드로 변경되었습니다.
< USTAR 포맷에 의한 헤더 구조 >
FIELD NAME OFFSET SIZE MEANING
name 0 100 name of file
mode 100 8 file mode
uid 108 8 owner user ID
gid 116 8 owner group ID
size 124 12 length of file in bytes
mtime 136 12 modify time of file
chksum 148 8 checksum for header
typeflag 156 1 type of file
linkname 157 100 name of linked file
magic 257 6 USTAR indicator
varsion 263 2 USTAR version
uname 265 32 owner user name
gname 297 32 owner group name
devmajor 329 8 device major number
devminor 337 8 device minor number
prefix 345 155 prefix for file name
이와 같이 어느 포맷이 되었든지 파일명, 파일크기 등 파일 정보에 관한 내용이 저장되는 헤더는 1블록(512바이트)로 구성되어 있습니다.
TAR 아카이브를 다룰 때 name 필드부터 typeflag 필드까지만 정확히 다루게 된다면 윈도우를 포함한 어느 시스템에서나 정상적으로 동작하는 것 같습니다. 즉 여러분이 PHP를 이용하여 작성된 TAR 아카이브를 가지고 유닉스 또는 리눅스의 tar 유틸리티를 이용하여 풀 수 있으며, 또한 윈도우에서 알집이나 window commander에서 풀 수도 있습니다.
테이블에 나타난 바와 같이 각 필드마다 그 위치와 크기가 고정되어 있습니다.
magic, uname, gname 필드는 마지막 코드는 반드시 null(아스키문자 0)이 나타나는 null 종료 문자열(null-terminated character strings)입니다. name, linkname, prefix 필드는 마지막 코드가 반드시 null일 필요는 없으나 정해진 필드크기가 다 채워지지 않았다면 채워지지 않은 빈 공간을 반드시 null로 채워야 합니다. name 필드의 예를 들어보면 만약 파일명이 "s1.txt"라면 name 필드에 기록될 때는 "s1.txt" . str_repeat(chr(0), 100 - strlen("s1.txt"))에서 얻은 값으로 기록됩니다.
USTAR 포맷에서 uname, gname 필드는 각각 로그인 사용자명과 그룹 사용자명을 기록합니다.
mode, uid, gid, chksum, devmajor, devminor 필드의 마지막 코드는 반드시 null이 기록되어야 하나 size, mtime, version 필드는 반드시 null로 종료할 필요는 없으나 일반적으로 null이 기록되는 것 같습니다. 따라서 숫자를 나타내는 이들 필드는 모두 null로 종료한다고 생각하시면 될 것입니다. 이와 같이 숫자를 나타내는 필드들은 모두 null로 종료되므로 실제로 숫자가 기록되는 장소의 크기는 테이블에 정하여진 SIZE-1이 됩니다. 예를 들어 uid의 경우를 보면 필드 크기는 8바이트이지만 실제로 OFFSET 108부터 114까지의 7바이트에만 기록되며 마지막 OFFSET 115에는 null이 기록됩니다. 숫자 필드에서 한가지 주의할 것은 기록되는 숫자는 10진수가 아니라 8진수로 기록된다는 것이지요. 그리고 기록되는 숫자의 자리수가 필드 크기보다 작을 때는 앞쪽으로 남는 자리수만큼 "0"으로 채워지게 됩니다. 만약 uid 값이 8이라면 uid 필드에는 "0000010"이 기록됩니다.
어떤 필드가 되었든지 헤더에서 사용되지 않는 공간은 모두 null로 채우도록 되어있습니다. 이제는 각 필드별로 다른 특징을 살펴보지요.
"name" 필드는 파일명 또는 디렉토리명이 기록되는 곳으로 총 100자까지 기록될 수 있습니다. 파일명이 100자가 되지 않아 비워있는 곳은 모두 null 값으로 채워집니다. 여기에 기록되는 파일명에는 패스명이 포함됩니다.
USTAR 포맷의 경우를 보면 prefix 필드의 값이 null이 아니라면 100자가 넘는 파일명이 가능하도록 name 필드 앞에 붙게 됩니다. 그러나 이전의 유닉스 호환 포맷이나 윈도우 시스템에서 TAR 아카이브를 만들 수 있는 윈도우커맨더 등과의 호환성을 생각한다면 prefix 필드를 null로 남겨두는 것이 좋을 듯하며 100자가 넘는 파일명인 경우 뒷쪽을 짤라내어 100자까지만 name 필드에 저장하는 것이 좋을 듯합니다.
USTAR 포맷에서만 사용하고 있는 typeflag 필드는 이전의 유닉스 호환 포맷의 link 필드와 호환성을 유지한 채 확장시킨 것입니다. 아래는 typeflag 필드에 기록될 수 있는 값들이며 이 중에 0, 1, 2까지는 이전의 유닉스 호환 포맷과 호환성을 유지합니다.
< typeflag 필드의 값 >
TYPE FLAG FILE TYPE
0 or null Regular file
1 Link to another file already archived
2 Symbolic link
3 Character special device
4 Block special device
5 Directory
6 FIFO special file
7 Reserved
A-Z Available for custom usage
"typeflag"는 파일 형식을 나타내는 필드로 디렉토리일 때는 "5"가 기록되며 파일일 경우에는 "0"이 기록됩니다.
"mode" 필드는 파일 모드가 기록되는 곳으로 8진수로 기록됩니다. 예를 들면 0755, 0644와 같지요. "mode" 필드에서 사용할 수 있는 크기는 총 7자입니다. 이 경우 보통 "0000755"와 같이 남는 공간은 앞쪽에 "0"으로 채우게 됩니다. 그러나 이러한 기록 방법은 프로그램에 따라 약간씩 차이가 나기도 하네요. 윈도우 유틸리티인 windows commander에서 TAR 아카이브를 만들게 되면 "000755 " 또는 "000644 "와 같이 6자만 8진수로 만들어 주고 7번째 자리에는 " "로 채우게 됩니다. 윈도우에서야 원래 파일 모드라는 개념이 없으니까 관계가 없다고 생각할지 모르겠으나 윈도우에서 압축한 TAR 아카이브를 리눅스에서 풀 때는 생각한다면 이를 적절히 처리하는 것이 좋을 것 같습니다.
"uid"와 "gid"도 "mode"와 같이 8진수로 기록되며 총 7자리를 만들 게 됩니다. 빈 공간은 앞쪽에 "0"을 채우게 되지요.
"size"는 바이트 단위의 파일 크기를 나타내며 8진수로 기록됩니다.
"mtime"는 파일을 수정한 시간을 나타내며 이에 해당하는 php 함수는 filemtime()입니다.
"magic" 필드는 압축 알고리즘의 이름을 나타내며 보통 "ustar" 또는 "GNUtar" 등이 기록됩니다. 6자가 안되는 부분은 " "로 뒤쪽에 채워지게 됩니다.
"linkname", "uname", "gname", "devmajor", "devminor", "prefix", "noname" 필드는 모두 chr(0)으로 채워넣습니다.
위와 같이 "chksum" 필드를 제외한 필드를 모두 기록한 후에 마지막으로 "chksum" 필드를 기록합니다. "chksum" 필드는 묶여진 파일이 정상적인가를 확인하는데 이용하는 체크섬 필드입니다. 8진수로 기록되며 채워지지 않는 부분은 앞쪽으로 "0"으로 채우게 됩니다. 체크섬 값은 아래와 같은 방법으로 구하게 됩니다. 이 때 변수 $HEADER에는 "chksum" 필드를 제외한 필드가 위에서 기술한 방법대로 먼저 기록되어 있다고 가정합니다.
[code php;gutter:false] function get_checksum() {
global $HEADER;

$sum = 0;

for ($i=0;$i<512;$i++) {
if ($i < 148 || 156 < $i) {
$sum += ord($HEADER[$i]);
} else {
$sum += ord(" ");
}
}

return $sum;
} [/code]
만약 기록하고자 하는 것이 파일이 아니라 디렉토리라면 파일과 같은 내용이 없기 때문에 512바이트의 헤더만 존재합니다. 한번 디렉토리 정보가 기록되면 그 뒤의 파일들은 앞에서 나타난 디렉토리에 속하게 됩니다. 따라서 디렉토리가 변경되는 부분에서만 단 한번 디렉토리 정보가 기록됩니다. 앞에서도 설명하였지만 파일 헤더와 다른 점이라면 "typeflag" 필드값이 "5"라는 것과 "name" 필드에는 파일명 대신에 패스명이 기록됩니다. 예를 들면 "sub1/sub2/"와 같지요. 다른 필드는 파일일 때와 같습니다.
디렉토리 정보가 없이 파일을 묶었을 때의 헤더 구조
예를 들어 TAR 아카이브 파일 내용 중에서 s1.txt 파일에 대한 헤더 구조를 덤프(dump)해 보면 아래와 같습니다.
< s1.txt 파일에 대한 헤더 구조 >
디렉토리 정보와 함께 기록된 파일에 대한 헤더 구조
sub/s1.txt
sub/s2.txt
sub/s3.txt
만약 위에서와 같이 s1.txt, s2.txt, s3.txt 파일이 모두 동일한 디렉토리 sub에 존재하며 이를 묶을 때 디렉토리 정보 sub를 기록했을 때 TAR 아카이브의 s1.txt 파일에 대한 헤더 구조를 덤프해 보면 아래와 같습니다.
< 디렉토리 정보가 기록된 s1.txt 파일의 헤더 구조 >
디렉토리 정보를 기록한 헤더 구조
sub/s1.txt
sub/s2.txt
sub/s3.txt
만약 위에서와 같이 s1.txt, s2.txt, s3.txt 파일이 모두 동일한 디렉토리 sub에 존재하며 이를 묶을 때 디렉토리 정보 sub를 기록했을 때 TAR 아카이브의 sub 디렉토리 헤더 구조를 덤프해 보면 아래와 같습니다.
< sub 디렉토리에 대한 헤더 구조 >

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

{TAR 파일}5.후미에 붙여지는 블록  (0) 2002.09.09
{TAR 파일}4.본문 구조  (0) 2002.09.09
{TAR 파일}2.아카이브 구조  (0) 2002.09.09
{TAR 파일}1.개요  (0) 2002.09.09
{HTML 파서}5.다운로드  (0) 2001.07.24
Posted by 방글24
phpsource/파일분석2002. 9. 9. 15:23
TAR 아카이브는 512바이트를 1블록으로하여 다루게 됩니다. 따라서 TAR 아카이브의 크기를 보면 512 * n 바이트임을 알 수 있습니다. TAR 아카이브는 여러 개의 파일이 하나로 묶여있으므로 각 멤버파일마다 본문 내용에 앞서 파일에 대한 정보를 기록하게 되는 1블록의 헤더가 반드시 나타나며 그 뒤를 이어 n블록의 본문 내용이 나타납니다. 때에 따라서는 하나의 디렉토리에 있는 파일뿐만 아니라 다른 디렉토리에 있는 파일들도 하나의 TAR 아카이브에 묶을 때도 있을 것입니다. 이러한 경우에는 디렉토리에 대한 정보도 기록하여야 하는데 이 경우에도 파일 헤더와 같이 1블록의 디렉토리 헤더를 가지게 됩니다. 디렉토리의 경우에는 파일과는 달리 본문 내용이 없으므로 각 디렉토리마다 1블록의 디렉토리 헤더만이 존재합니다. 파일 및 디렉토리에 관한 모든 정보(헤더 및 본문)가 다 기록된 후에는 마지막으로 아스키 0으로 채워진 1블록 이상의 빈블록(empty block)들이 붙여지게 됩니다.
이젠 몇가지 실예를 들어 전체 구조가 어떻게 구성되는지 살펴보겠습니다.
동일한 디렉토리에 있는 파일들(디렉토리 정보를 기록하지 않을 때)
아래와 같이 동일한 디렉토리에 있는 세 개의 파일(s1.txt, s2.txt, s3.txt)을 디렉토리 정보를 기록하지 않고 파일정보만 기록된 TAR 아카이브의 구조를 살펴보겠습니다.
s1.txt
s2.txt
s3.txt
s1.txt, s2.txt, s3.txt 파일이 모두 동일한 디렉토리에 존재하며 이를 묶을 때 디렉토리 정보를 전혀 기록하지 않는다면 TAR 아카이브의 전체 구조는 아래와 같을 것입니다.

s1.txt 파일 헤더

s1.txt 파일 본문

 

 

 

s2.txt 파일 헤더

s2.txt 파일 본문

 

 

 

s3.txt 파일 헤더

s3.txt 파일 본문

 

 

 

빈 블록

 

 

 

1 블록 (512 바이트)

n 블록 (512 * n 바이트)

1 블록 (512 바이트)

n 블록 (512 * n 바이트)

1 블록 (512 바이트)

n 블록 (512 * n 바이트)

n 블록 (512 * n 바이트)

동일한 디렉토리에 있는 파일들(디렉토리 정보를 기록할 때)
아래와 같이 동일한 디렉토리에 있는 세 개의 파일(s1.txt, s2.txt, s3.txt)을 디렉토리 정보와 함께 기록된 TAR 아카이브의 구조를 살펴보겠습니다.
sub/s1.txt
sub/s2.txt
sub/s3.txt
s1.txt, s2.txt, s3.txt 파일이 모두 동일한 디렉토리 sub에 존재하며 이를 묶을 때 디렉토리 정보 sub를 기록한다면 TAR 아카이브의 전체 구조는 아래와 같을 것입니다.

sub 디렉토리 헤더

s1.txt 파일 헤더

s1.txt 파일 본문

 

 

 

s2.txt 파일 헤더

s2.txt 파일 본문

 

 

 

s3.txt 파일 헤더

s3.txt 파일 본문

 

 

 

빈 블록

 

 

 

1 블록 (512 바이트)

1 블록 (512 바이트)

n 블록 (512 * n 바이트)

1 블록 (512 바이트)

n 블록 (512 * n 바이트)

1 블록 (512 바이트)

n 블록 (512 * n 바이트)

n 블록 (512 * n 바이트)

여러 개의 디렉토리에 있는 파일들
s1.txt
s2.txt
sub1/s3.txt
sub1/sub2/s4.txt
sub1/sub2/s5.txt
sub1/sub2/sub3/s6.txt
sub4/s7.txt
s1.txt, s2.txt, s3.txt 파일이 여러 개의 디렉토리에 분산되어 존재하며 이를 묶을 때 이들 디렉토리 정보를 함께 기록한다면 TAR 아카이브의 전체 구조는 아래와 같을 것입니다.

s1.txt 파일 헤더

s1.txt 파일 본문

 

 

 

s2.txt 파일 헤더

s2.txt 파일 본문

 

 

 

sub1 디렉토리 헤더

s3.txt 파일 헤더

s3.txt 파일 본문

 

 

 

sub2 디렉토리 헤더

s4.txt 파일 헤더

s4.txt 파일 본문

 

 

 

s5.txt 파일 헤더

s5.txt 파일 본문

 

 

 

sub3 디렉토리 헤더

s6.txt 파일 헤더

s6.txt 파일 본문

 

 

 

sub4 디렉토리 헤더

s7.txt 파일 헤더

s7.txt 파일 본문

 

 

 

빈 블록

 

 

 

1 블록 (512 바이트)

n 블록 (512 * n 바이트)

1 블록 (512 바이트)

n 블록 (512 * n 바이트)

1 블록 (512 바이트)

1 블록 (512 바이트)

n 블록 (512 * n 바이트)

1 블록 (512 바이트)

1 블록 (512 바이트)

n 블록 (512 * n 바이트)

1 블록 (512 바이트)

n 블록 (512 * n 바이트)

1 블록 (512 바이트)

1 블록 (512 바이트)

n 블록 (512 * n 바이트)

1 블록 (512 바이트)

1 블록 (512 바이트)

n 블록 (512 * n 바이트)

n 블록 (512 * n 바이트)


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

{TAR 파일}4.본문 구조  (0) 2002.09.09
{TAR 파일}3.헤더 구조  (1) 2002.09.09
{TAR 파일}1.개요  (0) 2002.09.09
{HTML 파서}5.다운로드  (0) 2001.07.24
{HTML 파서}4.배열 구조의 구성  (0) 2001.07.24
Posted by 방글24
phpsource/파일분석2002. 9. 9. 14:57
TAR(Tape ARchive) 아카이브 파일은 1970년대 자기테이프에 백업 & 검색하기 위하여 유래되었다고 합니다만 지금은 주로 여러 개의 파일을 묶어 전송하기 위하여 사용됩니다. 기본적으로 TAR 아카이브는 여러 개의 파일을 전혀 압축하지 않은 상태로 단지 하나의 파일로 묶어주는 역할만을 합니다. 우리가 보통 유닉스에서 제공하는 tar 유틸리티를 이용할 때 z 옵션을 지정하여 주면 압축까지 하는 것을 볼 수 있습니다. 그러나 이는 tar 유틸리티에서 압축해 주는 것이 아니라 tar 유틸리티와는 별개로 작성되어 있는 gzip 유틸리티를 불러다가 압축하게 되지요.
PHP 에서의 상황을 보면 zlib 라이브러리(gz로 시작하는 함수들)를 통해 파일을 압축할 수 있습니다. 그러나 zlib 함수는 기본적으로 하나의 파일만 다룰 수 있습니다. 웹상에서 여러 파일을 압축하고 해제하는 것이 다소 위험하여 그런지는 알 수 없으나 웹 스크립트에서는 TAR 아카이브를 잘 다루지 않는 것 같습니다. 생각해 보면 위험하기도 하겠습니다. 무슨 파일이 포함되었는지도 모르는 압축파일을 서버에 올려서 풀어버린다면 그 위험성은 상상하고도 남겠지요. 또한 내가 아닌 누군가가 나의 웹서버의 내용을 통째로 압축하여 가져가 버린다면...... 소름끼치는 상상이 될 수도 있겠지요. 그러나 구더기 무서워 장 못담그겠습니까? 서버상의 여러 개의 파일을 하나로 묶어서 다루어야 할 경우는 너무 많기때문에 TAR 아카이브를 다룰 수 있는 함수는 꼭 있어야 겠지요. 그리고 TAR 아카이브를 다룰 때 발생할 수 있는 여러 가지 위험성을 충분히 고려하여 사용하기만 한다면 별(?) 문제 없을 것입니다.
현재 PHP에서 일반적으로 웹상에서 여러 개의 파일을 압축하기 위해서는 exec() 또는 system()와 같은 함수와 리눅스에서 제공하는 tar 유틸리티를 이용하게 됩니다. 그러나 이러한 방법은 서버 상황에 따라 때로는 제대로 동작되지 않을 경우도 있으며 또한 윈도우 서버의 경우에는 해결방법이 될 수가 없습니다. 결국 가능한한 서버 환경에 관계없이 웹상에서 TAR 아카이브를 다루기 위해서는 TAR 아카이브를 직접 처리하는 것이 좋을 것 같습니다.
본인도 PHP에서 다중 파일 다운로드 클래스를 만들다보니 여러 개의 파일을 다운로드하기 위해서는 결국 여러 개의 파일을 하나의 파일로 묶은 후에 이 파일을 다운로드 받은 것이 가장 좋겠다는 생각까지는 하게 되었으나 현재 공개된 해결책으로는 위에서 언급한 리눅스의 tar 유틸리티를 이용하는 방법 외에는 눈에 띄는 것이 없었습니다. 그래서 인터넷을 검색하기 시작하였고 이를 통해 C로 작성된 tar 유틸리티의 소스 및 TAR 아카이브 구조에 관한 기술자료를 얻을 수 있었습니다. 이러한 자료를 통해 리눅스의 tar 유틸리티와 같은 기능을 수행하는 TAR 아카이브 클래스를 작성하게 되었습니다.
TAR 아카이브 관련 PHP 소스
TAR 관련 PHP 소스는 그리 흔한 것 같지 않습니다. 저도 관련 소스를 검색하여 보았으나 www.phpclasses.org에서 단 하나 발견하였을 뿐입니다. 본인도 이 소스를 참조하여 제 나름대로 TAR 아카이브를 다루는 클래스(hTarFile)를 작성하였습니다. 관심있는 분은 관련 소스들을 참조하시고 혹시 모르니 여러분도 인터넷을 더 검색해 보시기 바랍니다.
  • tar class
    Josh Barger
    joshb@npt.com
    http://www.phpclasses.org
  • hTarFile class
    Wookyung Hwang
    hwooky@phpclass.com
    http://www.phpclass.com
(추가) PEAR(PHP Extension and Application Repository)의 "File Formats" 패키지에 TAR 관련 PHP 소스 "Archive_Tar" 클래스가 있으니 http://pear.php.net 홈페이지를 참조바랍니다.
TAR 아카이브는 아니지만 zip 파일을 만들어 주는 소스가 보이네요. 소스는 TAR 아카이브를 다루는 것보다 훨씬 간단하구요. 실험해 보지는 않았지만 꽤 쓸모있는 소스인 것 같네요. 참조하세요.
  • zipfile class
    Eric Mueller
    eric@themepark.com
    http://www.zend.com/codex.php?id=696&single=1

Posted by 방글24
phpsource/회원인증2002. 2. 25. 14:30
파일 구성
adult.php - 성인 인증을 통과한 접속자에게 성인물을 제공함
로직
< 성인용 페이지 로직 >
성인 인증받지 못한 방문자 걸러내기
PHP 4.0.0 ~ 4.0.3일 때
[code php;gutter:false] session_start(); if (!isset($HTTP_SESSION_VARS["AdultCard"]) || "ok" != $HTTP_SESSION_VARS["AdultCard"]["permission"]) { // // 로그인을 거치지 않는 방문자 // ?> <META http-equiv='refresh' content='0; url=home.php'> <?php exit; } $AdultCard = $HTTP_SESSION_VARS["AdultCard"]; // // 성인 인증 성공 // [/code]
성인 인증에 성공한 다음에 세션변수 $AdultCard를 다룰 때는 반드시 전역변수 $AdultCard를 가지고 다루시기 바랍니다. 그래야 변경된 세션변수값이 정상적으로 다음 페이지에 넘어갑니다.
PHP 4.0.4 ~ 4.0.5일 때
[code php;gutter:false] session_start(); if (!isset($HTTP_SESSION_VARS["AdultCard"]) || "ok" != $HTTP_SESSION_VARS["AdultCard"]["permission"]) { // // 로그인을 거치지 않는 방문자 // ?> <META http-equiv='refresh' content='0; url=home.php'> <?php exit; } $AdultCard = & $HTTP_SESSION_VARS["AdultCard"]; // // 성인 인증 성공 // [/code]
성인 인증에 성공한 다음에 세션변수 $AdultCard를 다룰 때는 전역변수 $AdultCard 또는 $HTTP_SESSION_VARS["AdultCard"] 중 어느 것을 가지고 다루어도 관계없으나 가능하면 $HTTP_SESSION_VARS["AdultCard"]으로 다루도록 하세요. 그것이 향후 문서를 PHP 4.1.0으로 업그레이드할 때 작업하기가 편할 것입니다.
PHP 4.1.0 ~ 일 때
[code php;gutter:false] session_start(); if (!isset($_SESSION["AdultCard"]) || "ok" != $_SESSION["AdultCard"]["permission"]) { // // 로그인을 거치지 않는 방문자 // ?> <META http-equiv='refresh' content='0; url=home.php'> <?php exit; } // // 성인 인증 성공 // [/code]
성인 인증에 성공한 다음에 세션변수 $AdultCard를 다룰 때는 전역변수 $AdultCard 대신에 $_SESSION["AdultCard"]을 가지고 다루어 주시기 바랍니다. 이렇게 하는 것이 보안성 측면에서 유리하다고 PHP 메뉴얼에 적혀있네요. 물론 $_SESSION 대신에 이전 버전부터 사용하던 $HTTP_SESSION_VARS를 이용하셔도 관계없습니다만 향후 업그레이드될 때의 호환성을 고려한다면 $_SESSION이 더 나을 것 같습니다.
성인용 게시물
위에서와 같이 성인 인증을 거친 방문자에게는 적절한(?) 내용을 보여주어야 겠지요. 그 내용은 저도 모릅니다. 알아서 하세요. 단 로그아웃을 위한 메뉴 하나 정도는 꼭 필요하겠지요.
[code html;gutter:false] <HTML> <HEAD> <TITLE>성인용 페이지</TITLE> </HEAD> <BODY> // // 성인용 게시물(내용 생략) // <A href="./logout.php">로그아웃</A> </BODY> </HTML> [/code]

Posted by 방글24
phpsource/회원인증2002. 2. 25. 14:26
파일 구성
logout.php - 로그아웃 처리
로직
< 로그아웃처리 페이지 로직 >
소스 코드
각 버전별로 작성된 코드를 보면 session_unset 함수를 이용하여 모든 세션변수를 해제시키지 않고 세션변수 $AdultCard 에 대하여만 해제시키도록 하였습니다. 세션 함수를 본 성인 인증 소스만 사용한다면 session_unset 함수로 모든 세션변수를 해제시켜도 관계없지만 만약 성인 인증 소스 외에 현 웹사이트의 다른 문서에서도 세션 함수를 사용해야 한다면 성인 인증 소스에서만 사용하고 있는 세션변수 $AdultCard 만 해제시켜야 다른 문제가 발생하지 않습니다.
PHP 4.0.0 ~ 4.0.5일 때
[code php;gutter:false] <?php session_start(); session_unregister("AdultCard"); ?> <META http-equiv='refresh' content='0; url=home.php'> [/code]
PHP 4.1.0 ~ 일 때
[code php;gutter:false] <?php session_start(); unset($_SESSION["AdultCard"]); ?> <META http-equiv='refresh' content='0; url=home.php'> [/code]

Posted by 방글24
phpsource/회원인증2002. 2. 25. 13:29
파일 구성
login.php - 홈페이지에서 입력된 주민등록번호를 가지고 성인 인증을 수행함
로직
< 홈페이지 로직 >
처음 접속자 확인, 주민등록번호 2차 검증 및 성인 판정에 따른 분기
PHP 4.0.0 ~ 4.0.3일 때
[code php;gutter:false] session_start(); if (!isset($HTTP_SESSION_VARS["AdultCard"])) { // // 웹사이트에 처음 접속했거나 로그아웃한 경우 // ?> <META http-equiv='refresh' content='0; url=home.php'> <?php exit; } $AdultCard = $HTTP_SESSION_VARS["AdultCard"]; if ($birth=check_jumin($HTTP_POST_VARS["j1"], $HTTP_POST_VARS["j2"])) { // // 주민등록번호가 정상적으로 입력된 경우 // if (19 <= check_age(substr($birth, 0, -1))) { // // 성인(만19세 이상)인 경우 // $AdultCard["permission"] = "ok"; ?> <META http-equiv='refresh' content='0; url=adult.php'> <?php exit; } } // // 주민등록번호가 틀렸거나 성인이 아닌 경우 // $AdultCard["permission"] = "no"; ?> <META http-equiv='refresh' content='0; url=home.php'> <?php exit; [/code]
PHP 4.0.4 ~ 4.0.5일 때
[code php;gutter:false] session_start(); if (!isset($HTTP_SESSION_VARS["AdultCard"])) { // // 웹사이트에 처음 접속했거나 로그아웃한 경우 // ?> <META http-equiv='refresh' content='0; url=home.php'> <?php exit; } $AdultCard = & $HTTP_SESSION_VARS["AdultCard"]; if ($birth=check_jumin($HTTP_POST_VARS["j1"], $HTTP_POST_VARS["j2"])) { // // 주민등록번호가 정상적으로 입력된 경우 // if (19 <= check_age(substr($birth, 0, -1))) { // // 성인(만19세 이상)인 경우 // $HTTP_SESSION_VARS["AdultCard"]["permission"] = "ok"; ?> <META http-equiv='refresh' content='0; url=adult.php'> <?php exit; } } // // 주민등록번호가 틀렸거나 성인이 아닌 경우 // $HTTP_SESSION_VARS["AdultCard"]["permission"] = "no"; ?> <META http-equiv='refresh' content='0; url=home.php'> <?php exit; [/code]
PHP 4.1.0 ~ 일 때
[code php;gutter:false] session_start(); if (!isset($_SESSION["AdultCard"])) { // // 웹사이트에 처음 접속했거나 로그아웃한 경우 // ?> <META http-equiv='refresh' content='0; url=home.php'> <?php exit; } if ($birth=check_jumin($_POST["j1"], $_POST["j2"])) { // // 주민등록번호가 정상적으로 입력된 경우 // if (19 <= check_age(substr($birth, 0, -1))) { // // 성인(만19세 이상)인 경우 // $_SESSION["AdultCard"]["permission"] = "ok"; ?> <META http-equiv='refresh' content='0; url=adult.php'> <?php exit; } } // // 주민등록번호가 틀렸거나 성인이 아닌 경우 // $_SESSION["AdultCard"]["permission"] = "no"; ?> <META http-equiv='refresh' content='0; url=home.php'> <?php exit; [/code]
주민등록번호 2차 검증
주민등록번호 체계
현재 주민등록번호는 1975년부터 사용된 것으로 모두 13개 숫자로 돼 있습니다. 최초 6개 숫자는 생년월일을 나타내고, 뒤쪽 7개 숫자는 출생연대, 성별, 주민등록번호 발급기관, 신고순위 등으로 이루어진 다소 복잡한 구조로된 조합으로 그 조합체계는 공개되어 있지 않습니다.
조합체계에 대한 정확한 내용은 알 수 없으나 아래에 있는 주민등록법 개정행동연대에서 올린 "주민등록번호 체계"에 대한 글을 보시면 그 체계의 일부나마 알 수 있을 것입니다. 확인된 바는 없지만 이러한 조합체계는 시대에 따라(?) 약간의 유동이 있었던 것 같습니다. 따라서 현재 공개되는 주민등록번호 유효성 검증 소스들에는 거의 모두 약간의 오류를 포함하고 있지 않나 생각합니다.
주민등록번호 체계 -- 주민등록법개정행동연대
(수정:2010.1.11) 오래된 문서라서 현재는 링크가 깨진 상태입니다. 주민등록번호 체계에 대하여는 아래를 참조하세요.
우리나라의 주민등록제도는 1962년 주민등록법의 제정으로 처음 도입되었으며, 1975년 주민등록법시행령과 시행규칙의 개정으로 생년월일, 성별, 지역을 식별할 수 있도록 된 13자리의 숫자체제로 바뀌어 현재까지 사용되고 있습니다.
앞의 여섯자리 숫자는 생년월일을 나타냅니다. 뒤의 7자리 숫자는 출생연대, 성별, 주민등록번호 발급기관, 신고순위 및 오류검증번호를 나타냅니다.
뒤의 7자리 숫자 중 맨 앞자리 숫자는 출생연대와 성별을 나타냅니다. 예를 들면, 1900년대에 태어난 남자는 1번, 여자는 2번, 2000년대에 태어난 남자는 3번, 여자는 4번이 부여됩니다.
두 번째 자리부터 다섯번째 자리까지의 네자리 숫자는 최초 주민등록번호 발급기관의 고유번호, 여섯번째 자리는 신고순위, 마지막 일곱번째 숫자는 주민등록번호가 맞는지 여부를 증명해주는 오류수정 번호입니다.
주민번호체계 : YYMMDD - ABCDEFG

YYMMDD : 생년월일
예) 790309

A는 성별을 표시합니다.
예) 2000년대 남자 - 3, 여자 - 4
1900년대 남자 - 1, 여자 - 2
1800년대 남자 - 9, 여자 - 0

BCDE : 최초 주민등록번호 발급기관의 고유번호

F : 주민등록지에서 그 생년월일로 신고된 순서

G : 앞의 숫자들을 조합, 계산하여 산출되는 오류검증번호
주민등록번호 검증 함수
[code php;gutter:false] check_jumin($jumin1, $jumin2) [/code]
지정된 주민등록번호가 유효하면 생년월일 및 성별을 나타내는 문자열을, 틀리면 false를 반환한다. $jumin1은 주민등록번호 중 앞쪽 6자리의 숫자를 나타내는 문자열이며, $jumin2는 뒷쪽 7자리의 숫자를 나타내는 문자열입니다.
반환되는 값의 예를 보면 1991년 1월 12일에 출생한 남성이라면 "19910112M"을 반환하고 여성이라면 "19910112F"를 반환합니다. 아래는 이 함수에 대한 전체 소스입니다. 참고로 말씀드린다면 이와같은 검증 소스를 응용하여 주민등록번호를 임의로 생성해 주는 소스를 제작, 배포하는 것은 현행법상 엄연한 범법행위로 처벌받게 된다는 것을 명심하시기 바랍니다.
[code php;gutter:false] function check_jumin($jumin1, $jumin2) { if(strlen($jumin1) != 6 || strlen($jumin2) != 7) { return false; } $jumin = $jumin1 . $jumin2; for ($i=$sum=0;$i<12;$i++) { $sum += intval($jumin[$i]) * (($i % 8) + 2); } // // Checksum // if ((11 - ($sum % 11)) % 10 != intval($jumin[12])) { return false; } // // 총13자리의 주민등록번호 중 7번째의 숫자는 1부터 4까지의 값을 갖는다. // 이 값에 따라 성별 및 Y2K가 확인된다. // $a = intval($jumin[6]); if ($a < 1 || 4 < $a) { return false; } $sex = ($a % 2) ? "M" : "F"; $year = ($a < 3) ? 1900 : 2000; // // 출생년 확인 // $year += intval(substr($jumin1, 0, 2)); // // 출생월 확인 // $month = intval(substr($jumin1, 2, 2)); if($month < 1 || 12 < $month) { return false; } // // 출생일 확인(각 달에 따른 날수 차이 및 윤달 고려) // $day = intval(substr($jumin1, 4, 2)); $days = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); // // 2월생이면 윤달 확인 // if (2 == $month && check_leapyear($year)) { $days[1] = 29; } if(($day < 1) || ($days[$month-1] < $day)) { return false; } // // 반환값 // // 남성이면 "yyyymmddM", 여성이면 "yyyymmddF" // return "$year" . substr($jumin1, 2) . $sex; } [/code]
여기에 기술된 소스는 제가 작성한 것이 아니고 아래의 출처에서 밝힌 바와 같이 김순제 님이 작성하신 것에 약간의 수정만 가한 것입니다. 이 소스가 정확히 주민등록번호를 검증할 수 있는 것인지에 대하여는 확신할 수가 없네요. 제가 정확한 주민등록번호 검증 알고리즘을 본 일이 없기 때문에 이미 공개된 것을 그대로 가져왔습니다.
제작 : 김순제 님(soonj@lct.co.kr)
수정 : 후키(hwooky@phpclass.com)
따라서 여기서 공개된 성인 인증 소스는 공부삼아 보시기 바라며 진짜로 성인 사이트를 제작하시려거든 아래 업체에서 제공하는 실명확인 서비스를 받아 성인 인증을 수행하기 바랍니다. 실명확인 서비스란 실명과 주민등록번호가 일치하는지 확인해 주는 서비스를 의미하며 이를 이용하기 위해서는 아래 업체에서 해당 서비스를 신청하여야 합니다.
한국신용평가정보㈜(www.kisinfo.co.kr)
정보통신진흥협회(www.kait.or.kr)
한국신용정보(www.idcheck.co.kr)
윤년 확인 함수
주민등록번호의 유효성을 검증하는 과정에서 윤년 여부를 확인하게 됩니다. 아래와 같은 윤년 확인 로직에 의해 출생년도가 윤년인지 확인한 후 윤년인 경우에는 2월달을 29일까지 계산하면 윤년이 아닌 경우에는 28일까지 계산하여 주민등록번호 유효성을 검증합니다.
< 윤년 확인 로직 >
이러한 기능을 수행하는 것이 check_leapyear 함수이며 이 함수를 실행한 결과 윤년이면 true를, 윤년이 아니면 false를 반환합니다.
[code php;gutter:false] check_leapyear($year) [/code]
성인 확인
정보통신망이용촉진및정보보호 등에 관한 법률 및 청소년보호법 모두를 만족하는 성인 나이가 만 19세 이상인지 연 19세 이상인지는 제가 법률적 지식이 없어 잘 모르겠으나 현재 대부분의 성인 사이트들이 만19세 이상을 성인으로 인증하고 있으며 이에 따라 제가 공개하는 성인 사이트용 인증 소스도 만 19세 이상을 기준으로 인증하고 있습니다. 만약 향후 만 19세 이상이 아니고 연 19세 이상으로 그 기준이 변경되었을 경우에는 성인 확인 부분을 약간 수정하셔야 할 것입니다. 그러나 연나이는 우리나라 나이보다 1살 적기 때문에 "현재년도 - 주민등록년도"라는 수식으로 쉽게 구할 수 있습니다.
참고삼아 말씀드린다면 2001년 5월 24일 개정된 청소년보호법 제2조제1호에 의하면 청소년의 기준이 만나이에서 연나이로 변경되었는데 그 내용을 보면 아래와 같이 정의되어 있습니다.
"청소년"이라 함은 만 19세 미만의 자를 말한다.
다만, 만 19세에 도달하는 해의 1월 1일을 맞이한 자를 제외한다.
<<시행일 2001.8.25>>
`年나이'는 생일로부터 다음해 1월 1일을 지난 횟수만큼을 나이로 인정해 주는 방법으로 예를 들어 2001년 8월23일을 기준으로 1999년 9월 9일생의 경우 `滿나이'로는 한 살, 통상 국내에서 통용하는 나이개념으로는 세 살이 되지만 年나이로는 1월1일을 두 차례 지났기 때문에 두살이 됩니다.
`年나이 19세미만'으로 바뀌면 정상 나이의 대학 1년생의 경우 대학에 입학하는 해 1월1일부터 12월31일까지의 연 나이가 만19세로 돼 청소년보호법의 적용을 받지 않게 됩니다. 이는 생년월일에 따라 만 18세에서 만 19세로 전환되는 시점이 개인마다 달라 생일을 일일이 따져야 하는 불편과 대학 1년생에 대해서는 성인으로 간주하는 사회적 통념과의 괴리를 없애기 위한 것입니다.
滿나이 계산 함수
우리의 전통적인 나이 계산법에 의하면 아래와 같이 나이를 구할 수 있을 것입니다.
우리나라 나이 = 현재년도 - 주민등록년도 + 1
반면 서양식 나이 계산법인 만나이는 현재 생일이 지났을 경우에는 우리나라 나이보다 1살이 적고, 생일이 지나지 않았을 경우에는 2살이 적은 나이입니다. 이러한 만나이를 구하는 함수가 check_age입니다. 이 함수의 입력값으로는 "yyyymmdd" 형태의 문자열을 지정하여 줍니다. 예를 들면 1999년 5월 20일 생이면 "19990520"이 되는 것입니다. 이 함수를 실행하면 정수값으로 만나이를 반환시켜 줍니다.
[code php;gutter:false] check_age($birth) [/code]
이 함수의 전체 소스를 살펴보면 다음과 같습니다. 중간에 있는 $cur_year - $birth_year 의 결과가 바로 연나이에 해당합니다.
[code php;gutter:false] function check_age($birth) { $cur_year = intval(date("Y")); $birth_year = intval(substr($birth, 0, 4)); // // $age + 1 이 우리나라 나이임 // $age = $cur_year - $birth_year; // // month = 01 ~ 12 // day = 01 ~ 31 // $cur_day = intval(date("md")); $birth_day = intval(substr($birth, 4)); if ($cur_day <= $birth_day) { // // 생일이 지나지 않았으면 // $age--; } return $age; } [/code]

Posted by 방글24
phpsource/회원인증2002. 2. 25. 13:26
파일 구성
home.php - 1. 주민등록번호 입력양식을 제공
                 2. 입력된 주민등록번호의 유효성 검증
                 3. 검증 결과에 따른 분기
로직
< 홈페이지 로직 >
세션을 이용한 접속자 상태 확인 및 그에 따른 처리
PHP 4.0.0 ~ 4.0.3일 때
[code php;gutter:false] session_start(); if (!isset($HTTP_SESSION_VARS["AdultCard"])) { // // 웹사이트에 처음 접속했거나 로그아웃한 경우 // session_register("AdultCard"); $HTTP_SESSION_VARS["AdultCard"] = array("permission"=>"no"); } $AdultCard = $HTTP_SESSION_VARS["AdultCard"]; if ("ok" != $AdultCard["permission"]) { // // 처음 접속하거나 로그인에 실패한 경우 주민등록번호 입력양식을 출력 // login_form(); } else { // // 로그인에 성공한 경우는 성인용 페이지로 직행 // ?> <META http-equiv='refresh' content='0; url=adult.php'> <?php } [/code]
PHP 4.0.4 ~ 4.0.5일 때
[code php;gutter:false] session_start(); if (!isset($HTTP_SESSION_VARS["AdultCard"])) { // // 웹사이트에 처음 접속했거나 로그아웃한 경우 // session_register("AdultCard"); $HTTP_SESSION_VARS["AdultCard"] = array("permission"=>"no"); } $AdultCard = & $HTTP_SESSION_VARS["AdultCard"]; if ("ok" != $HTTP_SESSION_VARS["AdultCard"]["permission"]) { // // 처음 접속하거나 로그인에 실패한 경우 주민등록번호 입력양식을 출력 // login_form(); } else { // // 로그인에 성공한 경우는 성인용 페이지로 직행 // ?> <META http-equiv='refresh' content='0; url=adult.php'> <?php } [/code]
PHP 4.1.0 ~ 일 때
[code php;gutter:false] session_start(); if (!isset($_SESSION["AdultCard"])) { // // 웹사이트에 처음 접속했거나 로그아웃한 경우 // $_SESSION["AdultCard"] = array("permission"=>"no"); } if ("ok" != $_SESSION["AdultCard"]["permission"]) { // // 처음 접속하거나 로그인에 실패한 경우 주민등록번호 입력양식을 출력 // login_form(); } else { // // 로그인에 성공한 경우는 성인용 페이지로 직행 // ?> <META http-equiv='refresh' content='0; url=adult.php'> <?php } [/code]
세션 변수 $AdultCard는 연관배열로 "permission" 배열요소의 상태에 따라 성인 인증을 받았는지 안받았는지를 구분합니다. 이 값이 "no"이면 처음 접속하였거나 로그인에 실패한 접속자가 되며, "ok"이면 이미 성인 인증을 받은 접속자임을 나타냅니다.
따라서 "no"일 때는 접속자의 주민등록번호를 입력받는 화면을 나타냄으로 접속자로 하여금 성인 인증이 필요하다는 것을 알려주게되며, "ok"일 때는 즉시 성인용 페이지로 직행하게 됩니다.
PHP 버전에 따라 코딩 방법을 약간씩 다르게 해 보았습니다. 오십보 백보이기는 하지만 그래도 버전별로 보안상 가장 나은 방법을 택하여 작성해 보았습니다. 제가 보안 전문가가 아니라 잘못 이해하고 작성된 것이 있을 지 모르겠네요. 그렇다면 Q & A 게시판을 이용하여 지적하여 주시기 바랍니다. 하위버전용으로 작성된 것은 상위버전에서도 사용될 수 있으나 그 반대로는 불가능합니다.
주민등록번호 입력 화면
< 주민등록번호 입력 >
처음 접속하였거나 앞에서 행한 로그인에서 인증에 실패한 경우에는 이와 같은 입력화면을 출력하여 성인 인증을 위한 주민등록번호를 입력받도록 합니다.
청소년유해매체물의 경우에는 청소년보호법 및 정보통신망이용촉진및정보보호 등에 관한 법률에 의하여 그 표시방법 및 청소년 접근을 제한할 수 있는 방법 등에 관하여 규정하고 있습니다. 성인 인증 소스를 공개하는 본인은 법률의 문외한으로 이 소스가 위의 청소년유해매체물에 대한 표기 및 접근차단 방법이 동법에 적합한지는 알지 못합니다. 따라서 여기서 공개하는 모든 인증 소스는 누구나 자유롭게 이용(복사,수정,배포,재배포)할 수 있으나, 사용중 발생할 수 있는 모든 문제(법규 위반에 따른 책임 소재 및 그 외 발생가능한 모든 피해)에 대하여 어떠한 책임도 질 수 없음을 알려드립니다.
[code html;gutter:false] <CENTER> <TABLE width="400" border="0" cellpadding="0" cellspacing="6"> <TR> <TD align="center" height="134" width=90%> <P> 이 정보내용은 청소년유해매체물로서 정보통신망이용촉진및정보보호 등에 관한 법률 및 청소년보호법의<BR>규정에 의하여 <IMG src="img/19-.gif" align="middle" width="100" height="28" border="0" alt="만19세 미만">의 청소년이 이용할 수 없습니다. </P> <P> 주민등록번호로 성인여부를 판단합니다. </P> </TD> </TR> <TR> <TD align="center" height="102"> <!-- 로그인 폼양식 출력 시작 --> <FORM name=form1 action="login.php" method=post> <TABLE width="350" border="0" cellpadding="0" cellspacing="6" bgcolor="#dbf09f"> <TR> <TD align="right"> 주민등록번호 </TD> <TD> <INPUT size=6 maxlength=6 name=j1 type=text onKeyUp="checkKey(this.form)"> -<INPUT size=7 maxlength=7 name=j2 type=password onKeyDown="checkKey(this.form)"> </TD> </TR> <TR> <TD align="center" height="30" colspan="2"> <INPUT type=button value="성인공간 입장" onClick="checkKey(this.form)"> </TD> </TR> </TABLE> </FORM> <!-- 로그인 폼양식 출력 종료 --> </TD> </TR> </TABLE> </CENTER> [/code]
주민등록번호 1차 검증
주민등록번호를 입력하게 되면 자바스크립트로 작성된 checkKey 함수에 의해 입력된 주민등록번호가 올바른 것인지 1차 검증하게 됩니다. 이 소스 역시 인터넷 상에 이미 공개된 소스로 정확한 검증은 아니며 개략적으로만 그 유효성을 검증할 수 있습니다. 자바스크립트로 더 정확하게 검증해주는 소스를 원한다면 PHPSCHOOL.COM에서 검색해 보세요. 찾을 수 있을 것입니다.
[code html;gutter:false] <SCRIPT language=javascript> <!-- function checkJumin(jumin1, jumin2) { var i, sum = 0; var str = jumin1 + jumin2; if (parseInt(jumin2) < 1000000 && parseInt(jumin2) > 4999999) return false; for (i=0,sum=0; i<12; i++) sum += (((i%8) + 2) * (str.charAt(i) - "0")); if (((11 - (sum % 11)) % 10) == str.charAt(12)) return true; return false; } function checkKey(form) { if (form.j1.value.length==6) form.j2.focus(); key = event.keyCode; if (key==13 || key==0) { if (form.j1.value.length != 6 || form.j2.value.length != 7) { alert("주민등록번호를 입력하세요."); form.j1.focus(); return; } if (checkJumin(form.j1.value,form.j2.value)==false) { alert("주민등록번호가 맞지 않습니다."); form.j1.focus(); return; } form.submit(); } } //--> </SCRIPT> [/code]
현재 페이지에서 입력된 주민등록번호를 1차 검증하여 통과된 경우에만 로그인 처리 페이지로 넘어가 2차 검증을 받게 됩니다. 일단 이곳에서 간략하게나마 입력된 주민등록번호의 유효성을 검증하여 잘못된 것은 다시 주민등록번호를 입력하도록 함으로써 서버의 부하를 다소나마 줄여줄 수 있을 것입니다.

Posted by 방글24
phpsource/회원인증2002. 2. 25. 11:34
세션함수를 이용한 성인용 사이트 인증소스입니다. 주민등록번호를 입력받아 성인용 페이지에 접근할 수 있도록 작성된 "성인 인증 소스"입니다. 작성되었습니다.
파일 구성
home.php  - 성인인증을 위한 주민등록번호 입력(홈페이지)
login.php   - 주민등록번호를 가지고 성인 인증을 수행함
logout.php - 로그아웃 처리
adult.php   - 성인 인증을 통과한 접속자에게 성인물을 제공함
성인 인증 로직
< 성인 인증 로직 >
주민등록번호가 유효한가를 검증하는 부분이 home.php에도 있고, login.php에도 있습니다. home.php에서는 자바스크립트를 이용하여 개략적으로 주민등록번호를 검증하여 줌으로써 주민등록번호를 엉터리로 입력할 경우에는 다음페이지로 넘어가지 않더라도 현재페이지에서 다시 주민등록번호를 입력하도록 유도하여 서버의 부담을 줄여줄 수 있습니다.
login.php에서는 PHP 코드를 사용하여 주민등록번호를 좀 더 정밀하게 검증하여 주게 됩니다.

Posted by 방글24
phpsource/템플릿2002. 1. 28. 12:47
written: Jan 28 2002
last modified: Sep 20 2006
간단한 구조의 웹문서에서는 템플릿을 사용할 필요가 거의 없을 것입니다. 이러한 경우는 보통 우리가 많이 사용하는 방법인 HTML 문서 내에 PHP 코드를 삽입하여 작성하게 되면 훨씬 빠르고 손쉽게 문서를 작성할 수 있을 것입니다.
문제는 웹사이트의 내용이 점점 다양해지고 규모가 커지게 되면 PHP 코드 삽입 방식으로는 개발 속도와 문서 관리에 있어 금방 한계에 부딪치게 된다는 것입니다. 결국 현재 PHP의 기술 수준으로 볼 때 템플릿툴을 이용하지 않고 복잡한 웹사이트를 개발한다는 것은 거의 시간 낭비가 될 것입니다. (물론 PHP 언어를 위해 작성된 그래픽 웹에디터도 있는 것 같으니 관심있으면 한번 찾아보시길 바랍니다.)
PHP 코드와 HTML의 분리
템플릿툴을 이용하면 PHP 코드에서 HTML을 완전히(?) 분리할 수 있습니다. 이와 같이 HTML을 PHP 코드와 분리하게 되면 웹사이트 개발 속도를 획기적으로 개선시킬 수 있게 됩니다. 양쪽 요소를 별개로 관리 개발할 수 있으며 최소한의 인터페이스만 서로 조정해 주면 되지요. 즉, 템플릿은 웹디자이너들이 담당하여 멋들어지게 만들 것이며, PHP 코드는 웹프로그래머들이 모든 능력을 총동원하여 강력하게 작성할 것이기 때문이지요.
웹디자이너와 PHP 프로그래머 사이에 유일한 통로수단이 바로 템플릿 변수이지요. 다른 것은 서로 전혀 관계없습니다. 앞장에서 설명한 달력을 가지고 이 관계를 설명해 보지요. 아래는 최종적으로 얻어야 할 웹페이지인 달력입니다. 현재는 2001년 12월 달력이 나타나 있지만 이것을 해가 바뀌고 달이 바뀌면 그 내용 역시 바뀌게 될 것입니다.
2001년 12월
             1 
 2   3    4    5    6    7    8 
 9  10   11   12   13   14   15 
16  17   18   19   20   21   22 
23  24   25   26   27   28   29 
30  31            
위와 같은 문서에서 웹디자이너가 담당해야 할 요소는 아래와 같이 달력 디자인 및 정적 데이터들일 것입니다.
{YEAR}년 {MONTH}월
{A1} {A2} {A3} {A4} {A5} {A6} {A7}
{B1} {B2} {B3} {B4} {B5} {B6} {B7}
{C1} {C2} {C3} {C4} {C5} {C6} {C7}
{D1} {D2} {D3} {D4} {D5} {D6} {D7}
{E1} {E2} {E3} {E4} {E5} {E6} {E7}
{F1} {F2} {F3} {F4} {F5} {F6} {F7}
디자인된 화면을 보니 동적으로 바뀌어야 할 데이터들이 모두 템플릿 변수 {A1}, {A2}, ...... , {F7}로 표시되어 있는 것을 알 수 있습니다. 이렇게 하는 것으로 디자이너가 할 일은 다 한 것입니다. 달력을 더 멋있게 만들고 안만들고는 웹디자이너 맘이지요. 아님 사장 맘인가?
이제 남은 것은 PHP 프로그래머가 년도와 월에 맞게 적절한 알고리즘을 이용하여 각 템플릿 변수에 값을 할당하는 것이겠지요. 알고리즘의 성능을 개선하는 것은 프로그래머가 알아서 할 일이며 디자이너와는 전혀 관계가 없지요.
{YEAR} <- "2001"
{MONTH} <- "12"
{A1} <- ""
{A2} <- ""
{A3} <- ""
{A4} <- ""
{A5} <- ""
{A6} <- ""
{A7} <- "1"
{B1} <- "2"

.
.
.

{F1} <- "30"
{F2} <- "31"
{F3} <- ""
{F4} <- ""
{F5} <- ""
{F6} <- ""
{F7} <- ""
결국 HTML과 PHP 코드를 분리하게 됨으로 얻은 이점은 디자이너와 프로그래머가 서로의 영역에서 그 능력을 최대로 발휘하면서 웹사이트의 디자인과 성능을 향상시킬 수 있다는 것이지요. 간단한 웹사이트에서야 한 사람이 이 모든 일을 해야 하니까 별의미가 없다고 생각할 지 모르지만 한 사람이 하더라도 일의 성격을 구분하여 작업할 수 있다는 것만으로도 많은 이득을 얻을 수 있습니다.
일정한 틀을 가지고 반복 사용되는 부분
보통 하나의 웹사이트에서 반복 사용되는 부분을 처리하는데 프레임 태그를 많이 사용합니다. 그러나 요즈음 대부분의 웹사이트에서는 반복되는 부분이 있음에도 불구하여 프레임을 거의 사용하지 않지요.
아래와 같은 예의 홈페이지를 살펴보면 하나의 페이지가 크게 4 구역으로 나누어져 있는 것을 알 수 있습니다. 상단에 위치한 구역에는 베너 및 주 메뉴가 있고, 좌측 구역에는 서브 메뉴가 있고, 중앙 구역은 메인 화면이 있고, 하단 구역에는 관리자 이름을 표시하는 글들이 있습니다.
< 홈페이지의 구성 >
이 중에 상단과 하단 구역은 모든 페이지에서 공유하는 구역이고 좌측 구역은 몇몇 관련 페이지들이 공유하는 구역입니다. 중앙 구역만이 유일하게 모든 페이지마다 다른 내용을 보여주고 있지요. 결국 이와 같은 경우에 공유되는 각 구역을 별도의 템플릿으로 작성해 놓는다면 다른 페이지에서 그 부분을 다시 작성하지 않더라도 템플릿으로 작성해 놓은 것을 읽어 들이는 것만으로도 하나의 페이지를 만들 수 있습니다. 중앙 구역만 각 페이지 마다 새로 작성하면 되는 것이지요.
[code php;gutter:false] <? include_once("class.hTemplate.php"); $tpl = new hTemplate("./templates"); $tpl->define( array( 'top' => 'top.htm', // 상단 구역에 대한 템플릿 'left' => 'left.htm', // 좌측 구역에 대한 템플릿 'center' => 'center.htm', // 중앙 구역에 대한 템플릿 'bottom' => 'bottom.htm' // 하단 구역에 대한 템플릿 ) ); . . . ?> [/code]
< 템플릿을 이용한 홈페이지 구성 >
이와같이 공유하는 구역에 대한 것은 템플릿을 이용하여 공유하게 되면 웹사이트 전체의 코드양을 상당수 줄일 수 있을 것입니다.

'phpsource > 템플릿' 카테고리의 다른 글

{후키템플릿}3.7.output()  (0) 2006.08.01
{후키템플릿}4.1.템플릿 파일 경로  (0) 2003.04.30
{후키템플릿}0.4.라이선스(License)  (0) 2002.01.28
{후키템플릿}7.4.URL 리디렉션  (0) 2002.01.28
FastTemplate 1.1.0  (0) 2000.08.06
Posted by 방글24
phpsource/템플릿2002. 1. 28. 11:50
written: Sep 20 2006
hwooky's Template(hTemplate;hT) is licensed using LGPL. Copyright (c) 2005-2006 Wookyung Hwang(hwooky@phpclass.com). All rights reserved.
This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

-GNU LESSER GENERAL PUBLIC LICENSE (LGPL)

Address Bug Reports or Comments on THIS LIBRARY ONLY to Wookyung Hwang, hwooky@phpclass.com.
The latest version of this class should be available from the following locations: http://www.phpclass.com(korean only)

For more info about hwooky's Template(hTemplate;hT), visit http://www.phpclass.com(korean only)
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999

Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

[This is the first released version of the Lesser GPL. It also counts
 as the successor of the GNU Library Public License, version 2, hence
 the version number 2.1.]


Preamble
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users.

This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below.

When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things.

To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it.

For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights.

We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library.

To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others.

Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license.

Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs.

When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library.

We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances.

For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License.

In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system.

Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library.

The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run.


TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you".

A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables.

The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".)

"Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library.

Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does.

1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library.

You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.

2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:


a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful.
(For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.)

These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library.

In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.

3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices.

Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy.

This option is useful when you wish to copy part of the code of the Library into a program that is not a library.

4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange.

If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code.

5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License.

However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables.

When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law.

If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.)

Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself.

6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications.

You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things:


a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place.
e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.

It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute.

7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things:


a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above.
b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.

9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it.

10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License.

11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library.

If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.

This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.

12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.

13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.

Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation.

14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.

NO WARRANTY

15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.


END OF TERMS AND CONDITIONS

Posted by 방글24