[우체국의 API는 구주소만 서비스한다. 도로명 주소를 검색하려면 공공데이터포털을 이용해야 한다. 우체국 API를 이용해 구주소를 검색하는 이 예제도 2014-01-10 현재 잘 돌아간다. 공공데이터포털을 이용할 사람은 내가 쓴 공공데이터포털의 우편번호 API 정리 글을 참고하라.]

예전에 우체국이 제공하는 우편번호 API에 대해 쓴 적이 있었다.

당시 나는 세 가지 문제에 봉착했다.

  1. ajax 호출이 되지 않는다.
  2. 테스트를 해 보려고 url로 적으면, IE에서는 보이는데 크롬과 파이어폭스에서는 보이지 않는다.
  3. file_get_contents로 긁어도 안 된다.

그래서 포기했었다. 그냥 DB를 이용했다. 그렇게 하니 최신 우편번호를 적용하기 위해 DB를 매번 갱신해 줘야 했다.

시간이 지나고 많은 것을 알게 됐다. 일단 다른 domain에 있는 놈을 ajax 호출하는 것은 안 된다는 것을 알게 됐다. 그래서 1번 문제가 해결됐다.

2번 문제는, URL로 접근할 때나 문제지 호출할 때 그 자체로는 문제가 되지 않으며 POST로 값을 넘기면 된다는 사실을 알게 됐다. 그래서 해결.

3번 문제는, file_get_contentsGET 방식으로만 값을 넘길 수 있어서 그랬던 것이라는 점을 인지했다. 그래서 file_get_contents가 아닌, POST로 값을 넘겨 응답을 받을 수 있는 PHP 함수를 찾기로 결심!, 그리고 드디어 찾았다.

▶예제 보기   ▶코드 다운로드

우체국 우편번호 API 신청 페이지

(최근에 1day1님의 블로그에서 file_get_contents 함수로 우편번호 API를 사용할 수 있게 하는 글을 찾았다. 옵션을 줘야 한다. 저 글에서 제시하는 예제 코드는 아래와 같다.)

$api_key = "우체국에서 받은 API KEY";
$epost_url = "http://biz.epost.go.kr/KpostPortal/openapi?regkey=$api_key&target=post&query=을지로3가"; 

$opts = array(
  'http'=>array(
    'method'=>"GET",
    'header'=>"Accept-language: ko\r\n"
  )
);

$context = stream_context_create($opts);

$fp = file_get_contents($epost_url , false, $context);

cURL로 가져오기

내가 사용한 방법은 PHP의 cURL 라이브러리를 사용한다. 웬만한 호스팅에는 설치돼 있을 거다. 우분투 사용자들이라면 아래 명령어로 간단하게 설치할 수 있다.

sudo apt-get install php5-curl

(혹시나 해서 덧붙이는데, 설치한 다음 아파치를 재시작해야 적용된다.)

cURL을 이용해 웹페이지의 내용을 읽어 오는 함수

이 함수는 [bluesunh님의 노트] cURL Library를 참고했다. (스프링노트 폭파로 링크 유실)

function fetch_page($url,$param,$cookies=NULL,$referer_url=NULL){
    if(strlen(trim($referer_url)) == 0) $referer_url= $url;
    $curlsession = curl_init ();
    curl_setopt ($curlsession, CURLOPT_URL, $url);
    curl_setopt ($curlsession, CURLOPT_POST, 1);
    curl_setopt ($curlsession, CURLOPT_POSTFIELDS, $param);
    //curl_setopt ($curlsession, CURLOPT_POSTFIELDSIZE, 0);
    curl_setopt ($curlsession, CURLOPT_TIMEOUT, 60);
    if($cookies && $cookies!=""){
        curl_setopt ($curlsession, CURLOPT_COOKIE, $cookies);
    }
    curl_setopt ($curlsession, CURLOPT_HEADER, 1); //헤더값을 가져오기위해 사용합니다. 쿠키를 가져오려고요.
    curl_setopt ($curlsession, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.01; Windows NT 6.0)");
    curl_setopt ($curlsession, CURLOPT_REFERER, "$referer_url"); 

    ob_start();
    $res = curl_exec ($curlsession);
    $buffer = ob_get_contents();
    ob_end_clean();
    $returnVal = array();
    if (!$buffer) {
    	$returnVal['error'] = true;
        $returnVal['content'] = "Curl Fetch Error : ".curl_error($curlsession);
    }else{
    	$returnVal['error'] = false;
        $returnVal['content'] = $buffer;
    }
    curl_close($curlsession);
    return $returnVal;
}

우편번호 오픈 API에서 xml을 받아 오는 함수

자, 그럼 이제 우편번호 오픈 API에서 xml을 받아 오는 함수를 만들어 보자. 이 함수는 위 함수를 사용한다.

function get_post_code_xml_by_api($query){
	$query = iconv('utf-8','euc-kr',$query);

	$post_data = array(
	    'target' => 'post',
	    'regkey' => '1234567890', //자신의 키를 입력
	    'query' => $query
	);

	$url = 'http://biz.epost.go.kr/KpostPortal/openapi';
	$param = http_build_query($post_data);
	$result = fetch_page($url,$param);
	$result['content'] = remove_none_xml_word($result['content']);

	return $result;
}

위에서 regkey 는 우편번호 오픈 API 웹사이트에 가서 등록을 한 후 받으면 된다.

$param을 만드는 데 사용한 http_build_query 함수는 내가 쓴 설명을 참고하면 된다.

$query를 받아서 iconv 함수를 이용해 euc-kr로 변환해 줬는데, 내가 기본으로 utf-8 인코딩을 사용한다고 가정했기 때문이다.

위에서 return 직전에 remove_none_xml_word 라는 함수가 보일 거다.

그 놈은 cURL이 넘겨주는 header 값을 지워 버리고 순수 xml만 남기기 위한 함수다. 그놈을 만들어 보자.

function remove_none_xml_word($content){
	$content_array = explode("\n", $content);
	foreach ($content_array as $key => $value) {
		if(substr(trim($value),0,1)!='<'){
			$content_array[$key]='';
		}
	}
	unset($content_array[0]);
	$content = implode("\n", $content_array);
	return trim($content);
}

위에서 unset 함수를 쓴 이유는, 첫 줄이 빈 줄이기 때문이다. 첫 줄이 빈 줄이면 XML 파싱할 때 에러난다.

우편번호에 대시(-)를 넣어 주는 함수

우편번호 오픈 API는 우편번호를 그냥 123456형식으로 넘겨 준다. 사이에 -를 넣어 보기 좋게 만들어야 사용자들에게 좋을 거다.

또한 그러면서 앞 번호와 뒷 번호를 구분하기 위해 span으로 감싸고 클래스를 매겼다. postcd1, postcd2 하는 식으로 말이다.

function add_dash_and_tag_to_postcd($postcd){
	$postcd1=substr($postcd,0,3);
	$postcd2=substr($postcd,3,3);
	return "<span class="postcd1">$postcd1</span>-<span class="postcd2">$postcd2</span>";
}

HTML을 뿌려 주는 함수

이런 함수들을 바탕으로 이제 HTML을 뿌려 주는 함수를 만들어 보자.

function print_postcode_table($xml){
	?>
	<table class="postcode"><tbody>
	<?php
	    foreach ($xml->itemlist->item as $value) {
	    	$postcd = add_dash_and_tag_to_postcd($value->postcd);
	    	echo '<tr>';
	    	echo "<td><a class='address' href='#{$value->postcd}'>{$value->address}</a></td>";
	    	echo "<td><a class='postcd' href='#{$value->postcd}'>{$postcd}</a></td>";
	    	echo '</tr>';
	    }
	?>
	</tbody></table>
	<?php
}

print_postcode_table 함수는 simpleXML의 node를 받아서 table 형태로 주소와 우편번호를 뿌려 주는 함수다.

가운데 있는 foreach가 왜 저런 모양이 됐는지는 실행부를 보면 알 수 있을 것이다.

실행부

이제 실행부다. 위 함수들을 functions_postcode.php 에 넣었다고 가정하자.

include_once 'include/functions_postcode.php';
header('Content-Type:text/html;charset=utf-8');

if(!empty($_GET['query'])){
	$result = get_post_code_xml_by_api($_GET['query']);	

	if ($result['error'] == false){
		$xml = new SimpleXMLElement($result['content']);
		if(count($xml->itemlist->item) == 0){
			echo '결과가 없습니다';
		}else{
			print_postcode_table($xml);
		}
	}
	else {
		echo '에러 발생: ' . $result['content'];
	}
}else{
	echo '검색어를 입력하세요.';
}

우편번호 오픈 API의 인코딩은 euc-kr이다. 하지만 나는 utf-8로 무조건 페이지를 만든다.

물론 SimpleXMLElement 클래스를 생성하면, 지가 알아서 euc-krxmlutf-8로 변경한다.

그런데 한국 브라우저들은 인코딩 선언이 특별히 없는 경우 기본 인코딩을 euc-kr로 한다. 그래서 header쪽에 인코딩 선언을 넣어 줬다.(둘째 줄) 이 놈은 html로 뿌려줄 용도기 때문에 content-typetext/html이다.

나머지 if문은 다 이해가 될 것이라고 생각한다.

일단 이렇게 하면 search_post.php?query=삼천포 형식으로 URL을 적었을 때 훌륭한 테이블로 결과값이 펼쳐질 것이다.

특히 js로 주소를 넣고 빼고 하는 것을 제어할 수 있도록, 테이블에 클래스를 넣었고, 내용은 a 태그로 감쌌다. a의 클래스는 무엇을 감싸고 있냐에 따라 각각 address, postcd1, postcd2 다. 우편번호를 삽입하는 부분은 이것을 참고하면 된다.

그러면 우편번호 API 활용법 서버단 끝이다.

▶예제 보기 ▶코드 다운로드