8 번째 수정본 소스 보기 : UTF-8이전작업/브라우저GET요청인코딩판별
마지막으로 [b]
-- Loading page list... --
내용출력
로그인[l]
Diary
[f]
최근변경내역
[r]
페이지목록[i]
횡설수설[2]
게시판[3]
링크
수정할 수 없습니다: UTF-8이전작업/브라우저GET요청인코딩판별 는 읽기 전용 페이지입니다.
== # 브라우저의 GET 요청의 인코딩 판별 == IE의 "URL을..." 옵션에 따라서 EUC-KR로 들어오는 페이지 이름을 UTF-8로 바꿔야 한다. === # wiki.pl 수정 === 다음 함수는 인자로 받은 스트링을 보고, 인코딩을 '''추측'''하여 UTF-8로 변환해준다. * Unicode::CheckUTF8 모듈이 있으면 "legal UTF-8"인지 정확히 알 수 있다. 이건 없어도 큰 지장 없을 듯 * Encode와 Encode::Guess 모듈이 있어야 추측하고 변환하는 것이 가능하다. ** Encode는 웬만한 서버에는 있을 법 하고, Encode::Guess는 모르겠다. ** 무수한 캐릭터셋을 다 대조해볼 수 없기 때문에, 후보군을 넣어야 한다. 아래의 경우는 euc-kr과 utf8 중에서 비교. (utf-8이라고 대쉬를 쓰면 안 된다. 그러면 결과가 "utf-8-strict or utf8" 두 가지로 나온다.) ** 후보군을 한중일 세 언어를 동시에 넣을 수 있으면 좋겠는데, euc-kr과 euc-jp,shift뭐시기 등의 일본어 셋과는 코드가 겹치는 게 많아서, 한글을 넣었는데 일본어로 판단하는 경우가 생겨서 힘들 듯 {{{#!vim perl sub guess_and_convert { my ($string) = @_; # legal UTF-8인지 체크 if ($HttpCharset =~ /utf-8|utf8/i) { if (eval "require Unicode::CheckUTF8;") { if (Unicode::CheckUTF8::is_utf8($string)) { # ok return $string; } } } # 추측 if (eval "require Encode; require Encode::Guess;") { my @suspects = qw(euc-kr utf8); my $decoder = Encode::Guess::guess_encoding($string, @suspects); if (ref($decoder)) { # 추측 성공 return convert_encode($string, $decoder->name, $HttpCharset); } } # 모듈이 없거나, 있지만 추측 실패. 변환 포기 return $string; } }}} EUC-KR 시퀀스로, %-인코딩된 문자열이, 하필 ?뒤에 쿼리로 들어올 경우(예: wiki.pl?%C0%A7%C5%B0
)가 있다. 슬래쉬 링크를 쓰는 이상 현재는 이런 경우가 생기지 않는데, 예전에 ext1.*을 쓰던 당시에 구글에 등록된 주소라거나, 다른 사이트에서 링크를 해둔 경우 등이 있을 수 있다. 이 경우는 쿼리스트링 바꿔치기를 하는 시점에는 아스키 문자열이라서 변환이 안 되므로, 결국 나중에 CGI모듈이 디코딩해 준 것을 가지고 변환을 해야 한다. wiki.pl?페이지이름 의 경우와, id= 파라메터로 들어온 것만이라도 처리해 준다. {{{#!vim perl sub DoBrowseRequest { ... if ($id) { # Just script?PageName ### QUERY_STRING 이 utf-8이 아닌 인코딩인 경우 - 여기 한 줄 $id = guess_and_convert($id); if ($FreeLinks && (!-f &GetPageFile($id))) { $id = &FreeToNormal($id); } if (($NotFoundPg ne '') && (!-f &GetPageFile($id))) { $id = $NotFoundPg; } $DocID = $id; &BrowsePage($id) if &ValidIdOrDie($id); return 1; } $action = lc(&GetParam('action', '')); $id = &GetParam('id', ''); ### QUERY_STRING 이 utf-8이 아닌 인코딩인 경우 - 여기 두 줄 $id = guess_and_convert($id); $q->param('id', $id); $DocID = $id; ... } }}} CGI 오브젝트를 생성하기 전에 QUERY_STRING 환경변수의 값을 인코딩 검사를 해서 바꿔치기 해버린다. slashlink 관련 처리도 이 시점에 해 버린다. {{{#!vim perl sub DoWikiRequest { ... ### QUERY_STRING이 %-인코딩된 형태로 오는 경우 ### guess를 해도 ascii로 판정되기 때문에 변환이 안 된다. ### 이 시점에서 디코딩하여 복원함 # $ENV{'QUERY_STRING'} =~ s/%([0-9a-fA-F]{2})/chr(hex($1))/ge; ### slashlinks 처리 if ($SlashLinks && (length($ENV{'PATH_INFO'}) > 1)) { $ENV{'QUERY_STRING'} .= '&' if ($ENV{'QUERY_STRING'}); $ENV{'QUERY_STRING'} .= substr($ENV{'PATH_INFO'}, 1); } ### QUERY_STRING 또는 PATH_INFO가 utf-8이 아닌 인코딩인 경우 $ENV{'QUERY_STRING'} = guess_and_convert($ENV{'QUERY_STRING'}); &InitLinkPatterns(); if (!&DoCacheBrowse()) { eval $BrowseCode; &InitRequest() or return; if (!&DoBrowseRequest()) { eval $OtherCode; &DoOtherRequest(); } } } }}} 이 지점에서 변경할 때의 장점은, * UseCache 옵션을 켰을 때도 잘 동작한다. * 쿼리에 페이지이름이나 id= 이외에 어떤 파라메터에 들어간 한글도 다 인코딩 변환이 된다. * 나머지 코드 어느 지점이 수정되어도 인코딩 걱정을 할 필요가 없다. 단점...은, * 이래도 괜찮은 건지 모르겠음 -_-; [http://groups.google.co.kr/group/comp.lang.perl.misc/browse_thread/thread/8666e4c26327fff1/3b42dcc76c55fa6c?hl=ko#3b42dcc76c55fa6c comp.lang.perl.misc 그룹]에서는 CGI 모듈을 쓰기로 했으면 CGI모듈에서 제공하는 기능을 사용하라고 말리는 분위기였다. 근데 주인장은 아무리 생각해도 어차피 멀티바이트 캐릭터에만 영향을 미치기 때문에 상관없을 거라 생각하고 있다. * 요청이 EUC-KR이나 UTF-8일 때만 테스트해보고 있는데, 라틴 언어권에서 요청을 보내면 제대로 되는지 확인할 수 없음. 설마 ext2 버전을 그 동네에서 쓰는 사람이 있을라구 -_-; === # 추가 업데이트 내역 === ext2.4a - \\ 2007-03-21, 이제 보니 QUERY_STRING과 PATH_INFO가 넘어오는 방식이 좀 다르다. -_-; 쿼리스트링이 %-인코딩된 상태로 요청이 오면 위키 스크립트에도 그 상태 그대로 넘어오고, 따라서 guess_and_convert를 해도 변환이 안 되고 (아스키니까 -_-;) 만일 EUC-KR 시퀀스로 %-인코딩된 문자열을 쿼리로 받는 경우는 처리가 안 된다. (일반적인 상황에서는 위키의 인코딩과 다른 형태의 인코딩으로, 그걸 다시 %인코딩해서 쿼리로 넘겨주는 링크가 생길 일이 없는데... 검색엔진에 옛날에 수집되었던 주소나, 남이 옛날에 링크를 했던 것들이 이런 문제가 있다. 예를 들어 [[게시판]]에 nyxity님이 적은 경우: {{{ 구글로 '모카포트' '에스프레소'를 검색하면 각각 nyxity.com/wiki/wiki.pl?%B8%F0%C4%AB%C6%F7%C6%AE <-- 이런 거 nyxity.com/wiki/wiki.pl?%BF%A1%BD%BA%C7%C1%B7%B9%BC%D2 이렇게 페이지가 검색되는데, 클릭하면 페이지가 연결이 안되네요. }}} 할 수 없이, QUERY_STRING에서 %+16진수2개 꼴로 이뤄진 형태를 일단 디코딩한 후에 guess_and_convert에 넘겨주기로 함. 이거 고치면 고칠수록 서버의 플랫폼과 웹서버의 환경에 의존하게 되는 듯. === # 참고 자료 === === # 의견 === 생각해보니... 위키를 불러올때 꼭 "wiki.pl/페이지이름" 아니면 "wiki.pl/action=액션이름&id=아이디" 형태만 있는게 아니라서... * /reverse=페이지이름 - 이건 아예 역링크를 부르는 액션을 action=reverse&id=페이지이름 의 형태로 바꿔버렸고 -_-; * /search=문자열 - 이렇게 GET으로 특정 문자열 찾기 요청을 할 수도 있고 * /action=links&reverse=페이지이름 - Local:action=links&reverse=UseModWiki소스수정""처럼 reverse 파라메터가 또 등장하는 곳도 있고... 등등 따지고 보면 guess_and_convert를 해야 하는 것들이 한 두 군데가 아니다. 게다가 이런 action들은 앞으로도 얼마든지 늘어날 수 있는데 이때마다 파라메터들의 컨버트를 다 챙길수도 없고... 아예, CGI 오브젝트를 만들기 전에 스크립트로 넘어오는 환경변수를 통채로 바꿔치기 하면 어떨까 {{{#!vim perl sub DoWikiRequest { # 제일 처음 불리는 함수에서 ... ### 본격적으로 뭘 해보기 전에 이 시점에서 인코딩을 판단하여 바꿔버리자 $ENV{'QUERY_STRING'} = guess_and_convert($ENV{'QUERY_STRING'}); # wiki.pl? 뒤에 오는 쿼리 스트링 $ENV{'PATH_INFO'} = guess_and_convert($ENV{'PATH_INFO'}); # wiki.pl/ 뒤에 오는 여분의 패쓰 ### 그러면 이제부터 뭘 하든 이미 다 컨버트 되어 있으니 따로 신경쓸 필요가 없을 것이다 &InitLinkPatterns(); if (!&DoCacheBrowse()) { eval $BrowseCode; &InitRequest() or return; if (!&DoBrowseRequest()) { eval $OtherCode; &DoOtherRequest(); } } } }}} 위와 같이 생각하여 테스트용 사이트에서 해보니 별 문제 없어 보이긴 하는데, 이렇게 무지막지한 짓을 해도 정말 괜찮은 건지 확신이 안 서고 있습니다. =.=;;
생각해보면 이미 [[UseModWiki소스수정/SlashLinks처리]]를 위해서 PATH_INFO 환경변수를 QUERY_STRING으로 옮기는 코드도 있었으니 이것도 비슷하게 봐 줄 수 있을 법 한데... 그럼 말이 난김에 그 코드도 InitRequest가 아니라 이 곳으로 옮기면 캐쉬를 쓰는 경우까지 되지 않을까 싶음. {{{#!vim perl ### slashlinks 처리 - 여기서부터 추가 if ($SlashLinks && (length($ENV{'PATH_INFO'}) > 1)) { $ENV{'QUERY_STRING'} .= '&' if ($ENV{'QUERY_STRING'}); $ENV{'QUERY_STRING'} .= substr($ENV{'PATH_INFO'}, 1); # wiki.pl/ 뒤에 있는 내용을 QUERY_STRING에 옮긴 후 } $ENV{'QUERY_STRING'} = guess_and_convert($ENV{'QUERY_STRING'}); # QUERY_STRING 값을 컨버트 해 주고 # 이제 진행을 하면 &InitLinkPatterns(); if (!&DoCacheBrowse()) { # 캐쉬도 ok가 되지 않을까 eval $BrowseCode; ... }}}
: 음, "이래도 괜찮은 거냐"라는 질문 자체가 "그렇다"라고 대답하기 쉽지 않은 질문이긴 하지만.... [http://kldp.org/node/79279 KLDP 질문글]과 [http://perlmania.org/bbs/bbs.html?mode=read&table=CGI&article=1560&page=1 펄매니아 질문글]에 주말이 지나도록 그렇다 아니다 답글이 없어서, [http://groups.google.co.kr/group/comp.lang.perl.misc/browse_thread/thread/8666e4c26327fff1/3b42dcc76c55fa6c?hl=ko#3b42dcc76c55fa6c comp.lang.perl.misc 그룹]에도 올림...
---- [[위키위키분류]]
UTF-8이전작업/브라우저GET요청인코딩판별
페이지로 돌아가기 |
다른 수정본 보기