프로그램을 개발하던 도중 10진수로 표현된 Unicode, 즉 &#으로 시작하여 10진수 Unicode가 있고 세미콜론(;)으로 끝나는 문자를 출력해야 할 상황이 생겼다. Javascript에서 문자열 변수 안에 있는 문자열은 '並ぶ'와 같았으며, 그냥 단순히 출력할 경우 코드 부분이 변환되지 않고 그대로 출력되는 문제점이 있었다.

10진 Unicode를 코드에 해당하는 실제 문자로 변환하기 위해서는 String.fromCharCode라는 Javascript 함수를 써야 한다. 그러나 이 함수는 문자 코드를 문자로 변환하는 역할만 할 뿐 문자 코드가 섞여 있는 문자열을 변환하는 기능은 없었다.

그래서 다음과 같은 함수를 만들었다.



str에 변환하고자 하는 문자열을 넘기면 정규식을 이용해 십진 유니코드를 파싱한 뒤 이를 실제 문자로 치환하여 리턴한다.


2008년 1월 19일 이후 작성된 모든 글에 대해서 퍼가는 것을 금지합니다.
퍼가고자 하시는 분은 링크를 달아 주시기 바랍니다.
Posted by Harry

IE와 비 IE 브라우저는 이벤트가 발생했을 때 이벤트에 대한 세부정보를 담고 있는 event 객체를 사용하는 방법에 있어서 많은 차이를 보인다. 가장 먼저, 그 전달 방법부터가 다르다. 다음은 브라우저 별 event 객체의 전달 방법을 나타내었다.

obj의 onclick 이벤트에 process() 함수를 할당

IE의 경우function process()
{
        alert(event.srcElement.getAttribute("id"));
}

<div id="obj" onclick="process();"/>

비 IE 브라우저의 경우function process(e)
{
        alert(e.target.getAttribute("id"));
}

<div id="obj" onclick="process(event);"/>

event 객체를 사용하는 방법이 다를 뿐만 아니라 event 객체의 속성 중 이벤트가 발생한 객체를 나타내는 속성의 이름도 각각 srcElementtarget으로 다르다. 이외에도 많은 속성 이름이 호환되지 않기 때문에 주의를 요한다.

따라서 IE와 비 IE 브라우저 모두에서 작동하는 코드를 작성하기 위해서는 다음과 같이 한다.

IE 및 비 IE 브라우저 모두에서 작동하는 소스function process(e)
{
        if(event) alert(event.srcElement.getAttribute("id"));
        else alert(e.target.getAttribute("id"));
}

<div id="obj" onclick="process(event);"/>



2008년 1월 19일 이후 작성된 모든 글에 대해서 퍼가는 것을 금지합니다.
퍼가고자 하시는 분은 링크를 달아 주시기 바랍니다.
Posted by Harry
AJAX를 이용해 서버와 통신하는 방법을 알아보자.
통신할 데이터는 XML의 형태로 주고 받는다.

소스코드 살펴보기

일단 다음 소스를 보고 스스로 분석해보자. 자바스크립트에 대한 어느 정도의 지식만 있다면 쉽게 분석할 수 있을 것이다.

GetServerTime.html (Language : javascript)
  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3.  
  4.     <HEAD>
  5.         <TITLE> AJAX </TITLE>
  6.  
  7.         <script language="javascript">
  8.             var xhr; //XML Http Request Object
  9.             var url="time.php";
  10.  
  11.             function createXHR()
  12.             {
  13.                 if(window.ActiveXObject)
  14.                     xhr=new ActiveXObject("Microsoft.XMLHTTP");
  15.                 else if(window.XMLHttpRequest)
  16.                     xhr=new XMLHttpRequest();
  17.                 else
  18.                     return null;
  19.             }
  20.  
  21.             function startAjax()
  22.             {
  23.                 createXHR();
  24.                 if(xhr==null) return;
  25.  
  26.                 xhr.open("GET", url, true);
  27.                 xhr.onreadystatechange=CallBack;
  28.                 xhr.send(null);
  29.             }
  30.  
  31.             function CallBack()
  32.             {
  33.                 if(xhr.readystate==4)
  34.                 {
  35.                     if(xhr.status==200)
  36.                     {
  37.                         var result=xhr.responseXML;
  38.                         document.title=result.getElementsByTagName("time")[0].firstChild.data;
  39.  
  40.                         setTimeout(Again, 1000);
  41.                     }
  42.                 }
  43.             }
  44.  
  45.             function Again()
  46.             {
  47.                 xhr.open("GET", url, true);
  48.                 xhr.onreadystatechange=CallBack;
  49.                 xhr.send(null);
  50.             }
  51.         </script>
  52.     </HEAD>
  53.  
  54.     <BODY onload="javascript:startAjax();">
  55.     </BODY>
  56.  
  57. </HTML>
time.php (Language : php)
  1. <?php
  2.     header ("Content-Type: text/xml; charset=euc-kr");
  3.     echo '<?xml version="1.0" encoding="euc-kr" ?>';
  4.     echo '<time>';
  5.     echo date ("G:i:s");
  6.     echo '</time>';
  7. ?>

GetServerTime.html에서 XMLHttpRequest 객체를 이용하여 time.php에 비동기적으로 접속하여 계속적으로 서버 시간을 알아오는 소스이다.

가장 중요한 것은 XMLHttpRequest 객체이다. 이 객체는 서버와의 비동기통신을 할 수 있도록 제공되는 객체이다.

XMLHttpRequest 객체 생성하기

객체의 생성은 11~19라인이다.

createXHR (Language : javascript)
  1. function createXHR()
  2. {
  3.     if(window.ActiveXObject)
  4.         xhr=new ActiveXObject("Microsoft.XMLHTTP");
  5.     else if(window.XMLHttpRequest)
  6.         xhr=new XMLHttpRequest();
  7.     else
  8.         return null;
  9. }

IE의 지원이 불완전한 관계로 브라우저의 종류에 따라 생성 방법을 다르게 하야 함에 유의하라. 특별한 이유가 없는 한 위의 소스코드는 변경될 일이 없으므로 아예 외워 버리는 것도 좋을 것이다.

서버와 본격적으로 통신하기

서버와의 통신을 본격적으로 시작하는 StartAjax 함수를 보자.

startAjax (Language : javascript)
  1. function startAjax()
  2. {
  3.     createXHR();
  4.     if(xhr==null) return;
  5.  
  6.     xhr.open("GET", url, true);
  7.     xhr.onreadystatechange=CallBack;
  8.     xhr.send(null);
  9. }


23라인에서 createXHR() 함수를 호출하여 XHR 객체를 생성한다. 생성된 객체는 전역 변수인 xhr에 저장된다. 이 때 xhr이 null이라면 생성에 실패한 것이므로 통신을 종료한다(24라인).

26라인에서는 xhr의 연결을 설정하는 open() 함수를 볼 수 있다. open() 함수에는 세 개의 인자가 전달되는데, 각각은 다음과 같다.

XMLHttpRequest::open(string method, string url, boolean asynch, string username, string password);
method
통신의 방법을 설정한다. "POST"와 "GET", "PUT" 중 하나를 넘겨줄 수 있는데, "POST"의 경우 실제 http 자체에 내용을 넣어 전달하는 것이고, "GET"의 경우 '?' 기호와 '&' 기호를 이용하여 주소에 여러 변수의 값을 담아 넘겨주는 방법이다. "PUT"의 경우 거의 쓰이지는 않는 방법이다.

url
통신할 파일의 주소를 적어준다. 절대 경로와 상대 경로 둘 다 상관 없지만 주의할 점은 같은 서버 내에 있어야 접근이 허가된다는 것이다.

asynch
통신의 동기/비동기 여부를 결정한다. true일 경우 비동기 통신, false일 경우 동기 통신이 된다. 기본값은 true, 즉 비동기 통신이다. AJAX의 큰 장점 중 하나가 비동기 통신이므로 주로 true로 사용한다.

username, password
해당 페이지에서 username과 password를 요구한다면 이 인자를 통해 username과 password를 전달한다.
27라인에서는 콜백 함수를 설정하고 있다. 콜백 함수란, 직접 호출하지 않아도 특정 이벤트에 자동으로 호출되는 함수를 말한다. onreadystatechange라는 이벤트에 CallBack()이라는 함수를 할당함으로써 onreadystatechange 이벤트가 발생할 경우 자동으로 CallBack() 함수가 호출된다.

28라인의 send() 함수는 실질적으로 통신을 하는 함수이다. 인자로는 전달할 데이터를 넣어주는데, "GET" 방식에서는 null을, "POST" 방식에서는 전달할 데이터를 넣어주면 된다.

서버에서 응답하기

이렇게 하여 서버로 요청이 넘어가면 서버에서는 time.php 파일을 열어 응답을 한다. 응답은 일반 웹 페이지를 뿌리는 것과 똑같이 하면 된다. 즉, php로 응답을 할 경우 echo로 뿌려 준 모든 소스코드가 응답이 된다.

time.php에서는 GetServerTime.html에서 요청을 전달받고 바로 응답을 한다. header 함수의 경우 응답 http의 헤더를 설정하는 부분인데, 꼭 응답의 헤더에서 Content-Type, 즉 mime을 text/xml로 설정해야 클라이언트에서 XML 데이터로 받아 처리할 수 있다. 그렇지 않을 경우 XML 데이터임에도 불구하고 XML로 인식을 하지 못하게 된다.

ReadyState

XMLHttpRequest 객체를 사용하는 모든 과정에서 이 객체의 속성 중 하나인 readystate가 계속 변하게 되며, 변할 때마다 onreadystatechange라는 이벤트를 발생시킨다. readystate는 다음과 같이 5가지의 값을 가질 수 있다.

0 객체는 생성되었으나 open 함수는 호출되지 않음
1 open 함수는 호출되었으나 send 함수는 호출되지 않음
2 send 함수는 호출되었으나 아직 서버로부터 응답이 오지 않음
3 서버로부터 응답이 일부만 도착함
4 서버로부터 모든 응답이 도착함
즉 실제로 응답을 처리해야 하는 시점은 readystate가 4인 때이다.

onreadystatechange 이벤트의 콜백 함수로 CallBack() 함수를 설정했으니 readystate가 0~4로 바뀔 때마다 CallBack() 함수가 호출된다. CallBack() 함수에서는 매번 readystate의 값을 검사하여 4일 경우에만 응답을 처리하면 된다.

하지만 readystate가 4인 경우에도 올바르지 않은 응답이 올 수 있다. 가령, 접근 권한이 없어 접근하지 못했을 때에도 readystate는 4가 될 수 있다. 이 때에는 XMLHttpRequest의 status 속성을 검사하면 된다. status는 성공적인 응답이 왔을 때에 200으로 설정되므로 이를 검사한다.

응답 처리하기

이렇게 readystate==4 && status==200의 조건을 만족했을 경우 서버로부터 성공적인 응답이 도착한 것이므로 xhr에는 응답이 저장된다. 이 응답은 두 가지 방법으로 접근할 수 있다.

첫 번째 방법은 xhr.responseText로 접근하는 것이다. 서버에서 XML 데이터가 아닌 Text 데이터를 리턴했을 경우 사용한다. XML을 리턴했더라도 이를 Text의 형태로 받고 싶다면 이를 이용한다.

두 번째 방법은 xhr.responseXML로 접근하는 것이다. 이 방법은 응답의 Content-type이 text/xml인 경우에만 성공적으로 처리된다. 이 방법은 DOM Object의 형태로 XML 문서에 접근할 수 있어 매우 편하다. 또한 AJAX 자체가 본래 XML을 사용하도록 만들어 진 것이므로 주로 이 방법을 사용하게 된다.

DOMDocument

DOMDocument란, XML 데이터를 효과적으로 제어/조작하기 위하여 고안된 객체이다. XML 데이터를 통째로 읽어 메모리에 트리의 형태로 저장해 놓고 다음의 명령어들을 통해 검색/추가/제거/수정 등의 작업을 할 수 있다. element라는 DOM Object가 존재한다고 가정하고 설명한다.

접근
element.childNodes : element의 모든 자식 노드를 배열로 반환한다.
element.firstChild : element의 첫 번째 자식 노드를 반환한다.
element.lastChild : element의 마지막 자식 노드를 반환한다.
element.parentNode : element의 부모 노드를 반환한다.
element.nextSibling : element의 다음 형제 노드를 반환한다.
element.previousSibling : element의 이전 형제 노드를 반환한다.
element.nodeValue(=data) : element의 값을 반환한다.
element.hasChildNodes(); : element가 자식노드를 가지면 true, 가지지 않으면 false를 반환한다.
element.getAttribute(name); : element의 attribute 중 이름이 name인 attribute의 값을 반환한다.

검색
element.getElementsByTagName(tagname); : 이름이 tagname인 모든 노드를 배열의 형태로 반환한다.
element.getElementById(tagID); : ID가 tagID인 노드를 반환한다.

추가
document.createElement(tagname); : tagname의 이름으로 새로운 노드를 생성한다.
document.createTextNode(text); : text의 값으로 새로운 텍스트 노드를 생성한다.
element.appendChild(child); : child를 맨 마지막 자식 노드 뒤에 추가한다.
element.insertBefore(new, target); : new를 target 바로 앞에 추가한다.

제거
element.removeChild(child); : element의 자식 노드 중 child를 삭제한다.

변경
element.replaceChild(new, old); : element의 자식 노드 중 old를 new로 대체한다.
element.setAttribute(name, value); : element의 속성 중 이름이 name인 속성의 값을 value로 설정한다.
element.removeAttribute(name); : element의 속성 중 이름이 name인 속성을 삭제한다.

마무리

기본적으로 서버와 통신하는 방법을 알아보았다. 사실 위의 소스코드를 그대로 실행하면 시간이 바뀌지 않는다는 것을 알 수 있다. 이는 인터넷 임시 파일이 생성되어 분명 페이지가 바뀌었음에도 불구하고 컴퓨터에 저장된 임시 파일을 읽어들여서 바뀌지 않은 내용을 보여주기 때문이다. 이 때에는 요청하는 주소를 계속 변화시키기 위하여 주소에 랜덤값을 같이 넘겨 주는 것이 좋다.
예를 들어 다음과 같다.

url="time.php?key=" + Math.random();

위와 같이 하면 매번 다른 주소로 요청이 넘어가기 때문에 저장된 임시 페이지를 읽어오지 않아서 매번 다른 값을 볼 수 있다.




2008년 1월 19일 이후 작성된 모든 글에 대해서 퍼가는 것을 금지합니다.
퍼가고자 하시는 분은 링크를 달아 주시기 바랍니다.
Posted by Harry
AJAX는 Asynchronous JAvascript & XML의 약자로, 말 그대로 자바스크립트와 XML을 이용하여 서버와 비동기적으로 통신하는 것을 일컫는다. 이를 이용하면 좀 더 다이나믹한 웹 페이지를 꾸밀 수 있게 된다.

일반적으로, 서버와 통신하기 위해서는 한 번의 페이지 이동을 거쳐야 한다. 왜냐 하면 서버측 프로그램은 페이지가 바뀔 때 호출이 되고, 이 때 서버의 정보를 얻어올 수 있기 때문이다. 물론 HTML등의 단순한 문서는 서버측의 프로그램이 필요 없을 수도 있겠지만, DB에 Access하는 페이지의 경우 일반적으로는 한 번의 작업을 할 때마다 페이지를 이동하여 서버측 프로그램을 호출해야 한다.

하지만, AJAX를 이용하면 서버 작업 시 페이지 이동이 불필요하게 되어서 사용자로 하여금 훨씬 편하게 사이트를 이용할 수 있게 한다.

AJAX를 이용한 대표적인 사이트를 꼽으라면 구글 맵스 를 들 수 있을 것이다. 이는 프로그램으로 나와 있던 Google Earth를 웹 상으로 옮겨놓은 것이라고 생각하면 된다.
사용자 삽입 이미지

AJAX가 구현된 대표적인 사이트로 꼽히는 'Google Maps'의 페이지 모습이다.


처음 보는 사람이라면 '이거 뭐 다른데서 서비스하는 지도랑 똑같잖아?'라고 생각할 수도 있다. 하지만 분명히 큰 차이점이 있다. 다른 곳은 이용할 때 ActiveX 플러그인을 설치할 것을 요구한다. 하지만 구글 맵스는 어떠한 설치도 필요없다. 이것이 구글 맵스의 가장 큰 장점인 것이며, AJAX의 장점을 여실히 보여주는 예이다.

ActiveX가 없는 순수한 웹페이지인데도 페이지 전환이 없이 깔끔하게 지도를 표시하고 있다.

AJAX를 이용하면 어떤 것이 가능한 것인지 충분히 볼 수 있었다고 생각된다.

AJAX의 핵심요소는 XMLHttpRequest와 DOM이다.
XMLHttpRequest : 페이지 전환 없이 서버로 Http를 이용하여 정보를 전달하고 받아오는 자바스크립트 객체이다. 본래 IE가 처음 지원하였으나 현재는 대부분의 브라우저가 지원하고 있다.
DOM : XML 데이터를 관리하는 객체이다. XML 자료가 주어지면 몇 가지 함수를 통해 파싱, 추가, 삭제, 수정 등을 자유롭게 할 수 있도록 도와준다.
기본적인 원리를 간단히 설명하자면, XMLHttpRequest라는 객체에 여러 가지 정보를 담고 서버로 이를 전송한다. 그러면 서버가 이를 받아 처리를 한 후 그 결과값을 다시 클라이언트로 전송한다. 클라이언트는 서버에서 받아온 결과값을 이용하여 실시간으로 페이지를 갱신하게 된다.

태터툴즈의 자동 저장기능에 감사드립니다. 한 번 잘못 눌렀는데 다행히 다 저장되어있네요.. 저도 아직 AJAX를 공부하고 있는 입장이지만, 공부해 나가면서 계속 포스팅하겠습니다.



2008년 1월 19일 이후 작성된 모든 글에 대해서 퍼가는 것을 금지합니다.
퍼가고자 하시는 분은 링크를 달아 주시기 바랍니다.
Posted by Harry
PHP로 사이트 개발을 끝낸 후에 배포를 했는데, 가끔 있는 오류 때문에 페이지에 오류 메시지가 뜬다면?
이러한 상황을 방지하기 위해 php.ini 의 세팅을 변경함으로써 오류메시지를 보이지 않게 할 수 있다.

ini_set('display_errors', 'off');

위의 코드가 들어가 있는 페이지에서는 오류 메시지가 표시되지 않는다. 다만, 그 페이지에서만 한정되므로, 모든 페이지에 위 코드를 써야 한다. 한 페이지에 설정하고 이를 include하는 것이 현명할 것이다.

만약 어떤 특정 함수에서만 오류메시지를 출력하고 싶지 않다면 다음과 같이 함수 이름 앞에 @(at)을 붙여주면 된다.

@mysql_connect(...);

문제가 발생할 소지가 있는 함수에는 @을 붙여 깔끔한 페이지 작성을 하도록 하자.


2008년 1월 19일 이후 작성된 모든 글에 대해서 퍼가는 것을 금지합니다.
퍼가고자 하시는 분은 링크를 달아 주시기 바랍니다.
Posted by Harry
우리 반 H모씨 曰,
 "미궁게임 문제 줄테니까 웹페이지좀 만들어줘."

뭐 그냥 일반적인 미궁 게임처럼 페이지 이름을 답으로 해서 넘어가는 형식으로 하면 되지만, PHP 공부도 할 겸 해서 DB에 문제와 답을 저장하고 하나의 페이지에서 다 할 수 있는 일명 '미궁게임 PHP Version'을 만들어보았습니다.

사용자 삽입 이미지

문제 페이지입니다.


사용자 삽입 이미지

사용자 삽입 이미지

만세~


모든 작업은 index.php 하나에서 이루어집니다. 현재 풀고 있는 문제는 세션을 이용하여 처리할 수 있도록하였습니다. 세션을 이용하여 자료를 저장하는 방법을 아키군에게 물어보니, 세션 변수에 스테이지 자체를 저장하라고 하더군요. 하지만 그래도 변수인데 솜씨 좋은 놈이 조작할까 왠지 모를 걱정이 되어 세션과 DB를 연동하여 자료를 저장했습니다. 일단 제가 저장할 것은 stage이기 때문에 데이터베이스에 session용 테이블을 하나 만들고, 여기에 session_id, expire, stage와 같은 3개의 필드를 만들어주었습니다.

session_id는 그야말로 해당 세션의 고유 아이디를 저장하고 있고, expire는 해당 세션의 만료 시간, stage는 실제로 저장될 풀고 있는 문제 번호를 저장하는 필드입니다. id는 30자리의 1부터 9까지로 이루어진 문자열을 임의로 생성하여 할당했으며, 만료 시간은 기본 1시간으로 설정하였습니다.

일단 사용자가 최초로 사이트에 접속하면 세션이 있는지를 검사하고 없다면 새로운 id를 할당한 후 이를 세션 변수에 저장하고, 생성된 id를 DB에 저장합니다. 물론 DB의 stage필드의 값으로는 초기값인 1을 넣어주어야겠지요. 만약 사용자가 문제를 맞혔다면 세션 변수에 저장되어 있는 id를 이용하여 DB에서 id와 일치하는 레코드를 찾고, 해당하는 stage값을 읽어와 1 증가시킨 후에 업데이트합니다.

또한 페이지가 열릴 때마다 세션 테이블에서 만료 시간이 지난 레코드를 모두 찾아 삭제해줍니다. 이렇게 하면 최근 1시간 이내에 생성된 세션만 남아있게 됩니다.

사실 이외에도 몇 가지 부수적인 것들이 많이 있습니다. 아직 함수화를 하는 데 익숙치가 않아서 소스코드가 매우 난잡한 게 최대 단점이랄까요. 뭐 그래도 보안상 신경을 쓴다고 써서 만든 것이니(솔직히 보안 할 문제도 아니지만) 쉽게 뚫리지는 않겠지요.

버전 업좀 하고 문제좀 만들어서 올린 후에 공개하겠습니다.


2008년 1월 19일 이후 작성된 모든 글에 대해서 퍼가는 것을 금지합니다.
퍼가고자 하시는 분은 링크를 달아 주시기 바랍니다.
Posted by Harry