Perl에서, new CGI; 하기 전에 QUERY_STRING 바꿔치기..해도 괜찮을지?

raymundo의 이미지

안녕하세요 ^^ 이번에는 CGI와 GET 요청 처리에 대해 좀 문의드릴게 있어서 ^^;

$q = new CGI;                                    # 이렇게 CGI 오브젝트를 생성하고
$name = $q->param("name");            # GET, POST 등의 파라메터를 받아온다거나
print $q->h2("어쩌고");                        # 태그를 출력한다거나

위에서 $q->param("name") 이렇게 파라메터를 가져올 수 있는 건, CGI 오브젝트가 생성될 때 각종 파라메터의 값이 들어가기 때문이고, 그 값은 어디서 오냐 하면

- GET 요청의 경우는 $ENV{'QUERY_STRING'}의 값으로부터
- POST 요청의 경우는 stdin으로부터 CONTENT_LENGTH 환경변수의 값만큼의 길이를 읽어서
라고 이해하고 있습니다. (혹시 제가 빠뜨린 게 있으면 보충해주시면 감사하겠습니다. 아래 질문에 앞서 제가 이걸 제대로 이해하고 있어야 해서...)

그런데 제가 CGI프로그램(UseModWiki 라는 외국의 위키엔진을 가지고 이것저것 기능을 땜질해가며 씁니다)을 수정하고 테스트해보니까, 저 GET 요청에서 아스키 이외의 값이 오면 (한글이라던가) 인코딩에 따라 문제가 되더라고요.

그래서 지금 현재는, 그렇게 한글이 들어올 수 있는 항목에 대해서 Encode::Guess 모듈과 Encode 모듈을 사용해서 변환해주고 있습니다.

    $id = $q->param('id');                # URL에 "스크립트?id=이름"이 있다면 
    $id = guess_and_convert($id);   # "이름"이라는 문자열의 인코딩을 검사,변환
 
sub guess_and_convert {
# 넘어온 인자의 인코딩을 추측해 낸 후에, UTF-8이 아니면 UTF-8로 변환하여 리턴
}

뭐 그래서 그럭저럭 저 코드는 잘 돌아가는데요, 문제는 첨에 URL 에 뭐가 인자로 붙었냐에 따라서 CGI 프로그램의 동작이 달라지고 각각의 동작에서 추가로 읽어오는 파라메터가 다르다보니 (검색이라면 "search"파라메터를 읽어올 것이고 등등) 이런 곳을 모두 찾아서 저렇게 guess_and_convert를 넣어주는 것도 쉽지 않고, 차후에 다시 고칠 때도 힘들겠더라는 거죠.

그래서 든 생각이...

아예 CGI 오브젝트를 생성하기 전에 QUERY_STRING 값을 바꿔치기 하면 어떨까??

라는 겁니다.

# QUERY_STRING 의 인코딩을 검사해서 UTF-8로 변환한 후에
    $ENV{'QUERY_STRING'} = guess_and_convert($ENV{'QUERY_STRING'});
 
# 그 다음 CGI 오브젝트를 생성
    $q = new CGI;

이러면 이제부터는 언제 어디서 $q->param()을 불러도 이미 UTF-8로 변환된 값을 읽게 될 테니 다른 곳에서는 저런 컨버트에 신경쓸 필요가 없겠다는 생각이죠.

사실 이미 저렇게 고쳐서 테스트도 해봤는데 잘 되는 것 같긴 한데요... 혹시 저렇게 미리 바꿔치기함으로써 생길 수 있는 문제가 있다던가, "이왕 바꿔치기 하려면 이것도 같이 해야 한다"라던가 (앞에서 제가 제대로 이해하는지 봐달라고 적은게 그 때문) 그런게 있나 싶어서 문의드립니다. 조언을 부탁드립니다.

좋은 하루 되세요~

cjh의 이미지

CGI 매뉴얼 보시면

You can also initialize the query object from an associative array ref- erence:

$query = new CGI( {'dinosaur'=>'barney',
'song'=>'I love you',
'friends'=>[qw/Jessica George Nancy/]}
);

or from a properly formatted, URL-escaped query string:

$query = new CGI('dinosaur=barney&color=purple');

이렇게도 쓸 수 있네요.

--
익스펙토 페트로눔

--
익스펙토 페트로눔

raymundo의 이미지

아 네, 인자로 스트링이나 해쉬 레퍼런스를 주는 것까지는 저도 매뉴얼에서 봤는데요 ^^ 기존에 있던 코드가 인자 없이 new CGI; 로 생성하고 있는데, 이 때 저 CGI 오브젝트를 초기화하는데 관여하는 게 오직 QUERY_STRING 뿐일까, 아니면 그 외에도 더 있을까 싶어서요.

매뉴얼 왈:
  $query = new CGI;
 
       This will parse the input (from both POST and GET methods) and store it into a perl5 object called $query.

POST와 GET 메쏘드 양쪽에서 들어온 입력을 가지고 한다는데 (POST야 뭐 charset이 명시되니 됐고) GET으로 들어온 입력이란 게 결국 QUERY_STRING 넘겨받은 것 뿐인 건지... 그렇다면 EUC-KR로 인코딩된 QUERY_STRING 값을 UTF-8로 변환한다고 해도 별 문제 없을 것 같습니다만. (사실 처음 걱정한건, 외부에서 넘겨받은 환경변수의 값을 바꿔치기 해도 괜찮은 건가..였는데, 그것도 뭐 괜찮을 성 싶고..)

그러고보면 이건 Perl이나 CGI모듈에 관한 질문이 아니라 http와 웹서버, 브라우저에 관한 질문인 건지도 모르겠네요. ^^;;

좋은 하루 되세요~

p.s. kldp에 하도 간만에 오다보니.. 예전에 자주 도움 받았는데 또 받네요 :-)

좋은 하루 되세요!

raymundo의 이미지

"You should avoid changing the environment like that." 라면서, CGI::Vars 를 사용하라고 하는군요.

    my $param = $q->Vars; 
    $_ = check_and_convert( $_) for values %$param; 

근데 왜 avoid하라는 건지는 안 적혀 있는데, 아무래도 환경변수를 직접 조작하는 건 안 좋다는 거겠죠? 전 여전히 미련이 남는데.. ^^;

해당 글타래는 여기.. (comp.lang.perl.misc)

좋은 하루 되세요!

keedi의 이미지


흐흐 안될건 없지 않을까요? :evil:
어짜피 인자를 표준에 맞게 가공 변형하실텐데... :-)

---------------------------
Smashing Watermelons~!!
Whatever Nevermind~!!

Kim Do-Hyoung Keedi

----
use perl;

Keedi Kim

raymundo의 이미지

좀 전까지 끙끙대다가 경과 보고(?)하려고 왔더니 keedi님의 반가운 답글이 ^^;

CGI 모듈에서 제공하는 Vars 는 GET과 POST를 가리지 않고 다 가져와서 그런지, POST로 요청이 날아오는 경우 중에 파일 업로드, 트랙백 받기 등이 제대로 안 되는 문제가 있더라고요.

이걸 다시 상황 설명하고 관련 코드 언급하면서 또 영작해서 뉴스그룹에 글을 쓸 생각을 하니 엄두가 안 나고.. (게다가 왜 안 되는 건지 중간에 die를 넣어가며 확인해도 짐작이 안 됩니다. Vars가 반환하는 해쉬의 키와 밸류 모두 달라지는게 없는데도...)

- 이 문제를 막기 위해서 request_method()를 불러서 리턴값이 "GET"일 때만 저 Vars를 사용한 치환을 하자니 점점 더 일이 커지고 (게다가 제가 확신할 수 없는 상태로 코드가 늘어나는 게 정말 기분이... -_-;;)

- 아무리 봐도 저 QUERY_STRING 환경변수의 값은 결국 저 스크립트에서만 한번 쓰이고 말 것인데다가 달라지는 건 단지 멀티바이트 캐릭터들의 인코딩 뿐이니까, CGI 모듈이 가져가서 다른 일에 쓰기 전에 바꿔버리는게 오히려 안전하지 않을까 싶기도 하고,

- 원래 시작부터 제가 만든 스크립트가 아니다보니... CGI 오브젝트 생성하기 전에 "$ENV{QUERY_STRING}"을 읽어서 일을 하는 루틴들이 따로 또 있습니다.. 이 루틴에서도 역시 인코딩 변환을 해줘야 해야 하고...

등등의 이유로, 딱 감고 환경변수 바꿔치기를 밀고 나갈까 하고 있습니다. OTL

아아... 인코딩이란 건 참으로 힘든 문제로군요 =.=; 확 생각같아서는 "URL을 항상 UTF-8로 보내기 옵션을 켜시오(또는 끄시오)"라고 띄우고 방문자가 알아서 하라고 놔두고싶을 정도입니다 흐...

좋은 하루 되세요!

keedi의 이미지

어디선가 주워듣기로는 우리나라 사이트들에서 문제를 해결하기 위해 브라우져의 옵션 중 “URL을 항상 UTF-8로 보내기 옵션을 끄십시오”라고 제시하는 것이 정석(표준? 근본적 해결)이 아니다... 라고 들었던 것 같습니다. 괜히 그런 것들 때문에 고생하시네요. :-)

말씀하신 브라우져 옵션들과 상관없이 미리 바꿔도 그런일이 일어나나요? 그러니까 제가 상황을 정확하게 잘 몰라서 이런 말씀을 드리는 것일 수도 있지만, $ENV{QUERY_STRING}에서 문제가 되시는 이유가 한글과 같은 멀티바이트 문자가 있기 때문인가요? 예를들어 a태그에서 사용하는 링크에 한글이 있는 경우처럼요. 이런 경우에는 보기는 안좋지만 대부분의 한글 위키에서 하듯이 강제로 링크 자체의 인코딩 변환을 미리해서 자체 표현으로 바꾸면 이러한 문제가 생기지 않지 않을까요? 추측 추측 일 뿐이라서...

제가 알기로는... http://www.w3.org/TR/REC-html40/interact/forms.html#form-content-type
알파뉴머릭(?) 문자가 아닌경우는 %HH로 표현해야 한다고 본 것 같거든요. 그렇게 되면 환경 변수의 인코딩 영향을 받지 않을 것 갈긴한데...

흠흠... ^^;;

---------------------------
Smashing Watermelons~!!
Whatever Nevermind~!!

Kim Do-Hyoung Keedi

----
use perl;

Keedi Kim

raymundo의 이미지

사실 말씀하신 그대로입니다. ('' );;;

애초에 URL에 멀티바이트 문자를 %-인코딩해서 요청이 들어왔으면 아무런 문제가 없고, 따라서 제가 고치고 있는 위키 내부에서도 링크를 생성해서 출력할때 href= 값을 %-인코딩해서 출력해주면 상관없겠습니다만...

여전히 문제가 되는 경우라면,
1) 방문자가 자신의 브라우저 주소창에 직접 URL을 타이핑하는 경우 - 뭐 보통은 긴 URL을 다 타이핑하기보다는 해당 도메인명만 타이핑해서 들어온 후 그 안에서 링크를 따라가던가 사이트에서 제공하는 검색 기능을 쓰던가 하겠습니다만.

2) 다른 웹사이트(B라고 하죠)에서 링크를 거는 경우 - 이것도, 일단 제 쪽에서 링크들을 %-인코딩해서 제공한다면 B의 주인장이 그걸 복사해서 자신의 웹사이트에 링크를 넣을 테니, 링크 자체가 문제가 되는 건 아닌데요.

주소창에 쓰든 링크를 걸든 간에

.../wiki.pl/Linux        <= 이건 URL만 보면 Linux에 관한 얘기란 걸 쉽게 알 수 있지만
.../wiki.pl/%EB%A6%AC%EB%88%85%EC%8A%A4   <= UTF-8로 운영한다면 이걸테고
.../wiki.pl/%B8%AE%B4%AA%BD%BA            <= EUC-KR로 운영한다면 이걸텐데
아래 두개는 주소를 봐서 저게 "리눅스"에 관한 페이지란 걸 알 수 있겠습니까 =.=;
 
a href=".../wiki.pl/%EB%A6%AC%EB%88%85%EC%8A%A4>리눅스</a <= 이렇게 꼬박꼬박 a 태그를 붙여주고 이름을 적어준다면 그나마 낫겠지만 이건 상대방이 해줘야 하는 거고... 요새 위키나 블로그 툴, 워드프로세서들마저 URL만 적어주면 자동으로 링크로 변환해주는데 저렇게 수작업으로 하기도 참...

URL에 "해당 페이지의 제목"이 들어간다는 게 제가 위키를 (물론 블로그도 포스트마다 일련번호를 붙이는 게 아니라 각 포스트의 제목을 사용해서 URL을 구성하는 블로그툴도 있지요) 좋아하는 이유 중 하나인데, 한글 제목에 대해서 저런 암호문처럼 URL을 구성해야 한다는 게 너무 싫습니다. 저도 표준 지키고 이런 걸 선호합니다만 이 URL만큼은

.../wiki.pl/리눅스

라고 타이핑을 하든 링크를 걸든 제 위키가 받아들였으면 싶은 겁니다. 근데 저 때 브라우저 옵션에 따라서 "리눅스"가 "%EB%A6%AC%EB%88%85%EC%8A%A4"로도 올 수 있고 "%B8%AE%B4%AA%BD%BA"로도 올 수 있기 때문에 wiki.pl 스크립트가 그걸 둘 다 제대로 "리눅스"로 인식하게 하려는 거죠.

여담:
그럼 이름을 가지고 페이지를 찾는 시점에 변환하면 될 텐데 왜 굳이 QUERY_STRING을 통채로...냐 하면, 저런 경우 말고도

.../wiki.pl?reverse=리눅스        <= 역링크를 찾는 경우
.../wiki.pl?search=주저리         <= 문자열을 검색하는 경우

등등의 경우도 다양하게 있어서 그렇습니다.

좋은 하루 되세요!

keedi의 이미지

하아 정말 골치아픈 문제이군요~ T_T

멀티바이트 문자권의 비애라고 말 할 수 밖에요... 흠... 요지는 위키에서 표준이 아니더라도 사용자의 편의를 위해 지원하시려는 기능이군요...

잠깐 정말 무식한 방법을 생각해보았습니다... -_-;;; 예를들어 "오늘의Linux팁" 이라는 페이지가 있을때 원칙은 내용을 utf-8로 저장하고 제목도 utf-8 형식의 %HH인 "%HH%HH%HH%HH%HH%HH%HH%HH%HHLinux%HH%HH%HH"로 파일을 생성하되, 동일한 파일이지만 이름만 euc-kr의 %HH식으로 가진 파일을 하나 더 복사하는 것입니다. -_-;;;; 아니면 동일한 제목의 파일을 가지고 있되 내용은 없이 utf-8 페이지로 가도록 한다던가요... 그러면 웹브라우져의 버전에 상관없이 웹서버가 지가 알아서 연결시켜주겠지요. 흠 정말 무식한 방법이긴하군요... 흠흠... 인코딩이 많아지면 각 인코딩별로 디렉토리와 연결 파일을!!?? 그래도 프로그램 로직이 간결해진다는... -_-;;;

그런데 wiki.pl?search=주저리 이런 경우까지 감안하시려면 말씀하신 CGI 객체 생성 이전에 환경 변수를 미리 적당하게 조작하는 것이 오히려 제일 편한 방법일지도 모르겠습니다. 대신 혹시 모르니 원래의 값을 보존하고 있는 것이 좋겠지요.

혹시 있을지 모를 웹클라이언트(브라우져)의 버전업으로 인한 내부 정책 변화에 민감하셔야겠군요... ^^;

---------------------------
Smashing Watermelons~!!
Whatever Nevermind~!!

Kim Do-Hyoung Keedi

----
use perl;

Keedi Kim

raymundo의 이미지

일단 QUERY_STRING을 바꿔치기 하는 걸로 고쳐 놓고, 써 보다가 문제가 생기면 그때 다시 고치든지 해야겠습니다. (글 제목에 완료 말머리는 이번에도 못 달겠군요 ^^) 어차피 제가 고쳐서 저 혼자 쓰다시피 하는 건데 뭐... =.=;;; 제가 고친 걸 쓰시는 분들이 몇 분 계시긴 합니다만;;

애초에 제 질문 자체가 "이래도 괜찮습니까?"다보니... 대답하는 사람 입장에서 "문제 없다. 괜찮다"라는 말을 쉽게 할 수도 없겠고 ^^;

반대로 "이러이러한 문제가 있을지 생길 수 있다"는 구체적인 예를 드는 답글도 없네요. 유즈넷 comp.lang.perl.misc에서도 두 명이 "그러지 말고 CGI모듈에서 제공하는 ->Vars를 쓰던가 해라"라는 식으로는 말을 했는데 딱히 구체적인 이유는 역시 없네요.

김도형님 펄매니아쪽에서 답글 달아주시랴 여기서 달아주시랴 바쁘셨죠 ^^; 감사합니다. 최준호님도 감사합니다.

좋은 하루 되세요!

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.